diff --git a/speech/.idea/inspectionProfiles/profiles_settings.xml b/speech/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 00000000000..c23ecacb3a2
--- /dev/null
+++ b/speech/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/speech/.idea/misc.xml b/speech/.idea/misc.xml
new file mode 100644
index 00000000000..b317e4e3aa6
--- /dev/null
+++ b/speech/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/speech/.idea/modules.xml b/speech/.idea/modules.xml
new file mode 100644
index 00000000000..3ec43b5d653
--- /dev/null
+++ b/speech/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/speech/.idea/speech.iml b/speech/.idea/speech.iml
new file mode 100644
index 00000000000..9bcf65eeed4
--- /dev/null
+++ b/speech/.idea/speech.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/speech/.idea/workspace.xml b/speech/.idea/workspace.xml
new file mode 100644
index 00000000000..47ebb16fb03
--- /dev/null
+++ b/speech/.idea/workspace.xml
@@ -0,0 +1,760 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ en-E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ DEFINITION_ORDER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1489772607623
+
+
+ 1489772607623
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/speech/grpc/chatdemo.py b/speech/grpc/chatdemo.py
new file mode 100755
index 00000000000..f0e5246fcf7
--- /dev/null
+++ b/speech/grpc/chatdemo.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+#
+# Copyright 2009 Facebook
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+"""Simplified chat demo for websockets.
+
+Authentication, error handling, etc are left as an exercise for the reader :)
+"""
+
+import logging
+import tornado.escape
+import tornado.ioloop
+import tornado.options
+import tornado.web
+import tornado.websocket
+import os.path
+import uuid
+
+from tornado.options import define, options
+
+define("port", default=8888, help="run on the given port", type=int)
+
+
+class Application(tornado.web.Application):
+ def __init__(self):
+ handlers = [
+ (r"/", MainHandler),
+ (r"/test", TestHandler),
+ (r"/chatsocket", ChatSocketHandler),
+ ]
+ settings = dict(
+ cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
+ template_path=os.path.join(os.path.dirname(__file__), "templates"),
+ static_path=os.path.join(os.path.dirname(__file__), "static"),
+ xsrf_cookies=False,
+ )
+ super(Application, self).__init__(handlers, **settings)
+
+
+class MainHandler(tornado.web.RequestHandler):
+ def get(self):
+ self.render("index.html", messages=ChatSocketHandler.cache)\
+
+class TestHandler(tornado.web.RequestHandler):
+ def post(self):
+ self.set_header("Content-Type", "text/plain")
+ self.write("You wrote " + self.get_body_argument("message"))
+
+ # def post(self, message):
+ # # self.render("index.html", messages=ChatSocketHandler.cache)
+ # logging.info(message)
+ chat = {'body': u'{}'.format(self.get_body_argument("message")),
+ 'html': '
dasdasda
\n',
+ 'id': 'cf6aef33-cb77-4df5-91a4-852d560ef097'}
+ ChatSocketHandler.send_updates(chat)
+
+class ChatSocketHandler(tornado.websocket.WebSocketHandler):
+ waiters = set()
+ cache = []
+ cache_size = 200
+
+ def get_compression_options(self):
+ # Non-None enables compression with default options.
+ return {}
+
+ def open(self):
+ ChatSocketHandler.waiters.add(self)
+
+ def on_close(self):
+ ChatSocketHandler.waiters.remove(self)
+
+ @classmethod
+ def update_cache(cls, chat):
+ cls.cache.append(chat)
+ if len(cls.cache) > cls.cache_size:
+ cls.cache = cls.cache[-cls.cache_size:]
+
+ @classmethod
+ def send_updates(cls, chat):
+ logging.info("sending message to %d waiters", len(cls.waiters))
+ print(chat)
+ for waiter in cls.waiters:
+ try:
+ waiter.write_message(chat)
+ except:
+ logging.error("Error sending message", exc_info=True)
+
+ def on_message(self, message):
+ logging.info("got message %r", message)
+ parsed = tornado.escape.json_decode(message)
+ chat = {
+ "id": str(uuid.uuid4()),
+ "body": parsed["body"],
+ }
+ chat["html"] = tornado.escape.to_basestring(
+ self.render_string("message.html", message=chat))
+
+ ChatSocketHandler.update_cache(chat)
+ ChatSocketHandler.send_updates(chat)
+
+
+def main():
+ tornado.options.parse_command_line()
+ app = Application()
+ app.listen(options.port)
+ tornado.ioloop.IOLoop.current().start()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/speech/grpc/requirements.txt b/speech/grpc/requirements.txt
index 13377b67c29..cd8f97b5fdd 100644
--- a/speech/grpc/requirements.txt
+++ b/speech/grpc/requirements.txt
@@ -1,6 +1,56 @@
+appdirs==1.4.3
+awscli==1.11.61
+awsebcli==3.10.0
+backports-abc==0.5
+backports.ssl-match-hostname==3.5.0.1
+beautifulsoup4==4.5.3
+biopython==1.68
+blessed==1.14.1
+boto3==1.4.3
+botocore==1.5.26
+bs4==0.0.1
+cement==2.8.2
+certifi==2017.1.23
+colorama==0.3.7
+docker-py==1.7.2
+dockerpty==0.4.1
+docopt==0.6.2
+docutils==0.13.1
+enum34==1.1.6
+futures==3.0.5
+google-auth==0.8.0
+googleapis-common-protos==1.5.2
grpcio==1.1.0
-PyAudio==0.2.10
+html5lib==0.999999999
+httplib2==0.10.3
+jmespath==0.9.2
+lxml==3.7.3
+mechanize==0.2.5
+numpy==1.12.0
+oauth2client==3.0.0
+packaging==16.8
+pandas==0.19.2
+pathspec==0.5.0
proto-google-cloud-speech-v1beta1==0.15.1
+protobuf==3.2.0
+pyasn1==0.2.3
+pyasn1-modules==0.0.8
+PyAudio==0.2.10
+PyExecJS==1.4.0
+pyparsing==2.2.0
+python-dateutil==2.6.0
+pytz==2016.10
+PyYAML==3.12
+requests==2.9.1
+rsa==3.4.2
+s3transfer==0.1.10
+selenium==3.3.1
+semantic-version==2.5.0
+singledispatch==3.4.0.3
six==1.10.0
-requests==2.13.0
-google-auth==0.8.0
+tabulate==0.7.5
+termcolor==1.1.0
+tornado==4.4.2
+wcwidth==0.1.7
+webencodings==0.5
+websocket-client==0.40.0
diff --git a/speech/grpc/static/chat.css b/speech/grpc/static/chat.css
new file mode 100644
index 00000000000..a400c326057
--- /dev/null
+++ b/speech/grpc/static/chat.css
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2009 FriendFeed
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+body {
+ background: white;
+ margin: 10px;
+}
+
+body,
+input {
+ font-family: sans-serif;
+ font-size: 10pt;
+ color: black;
+}
+
+table {
+ border-collapse: collapse;
+ border: 0;
+}
+
+td {
+ border: 0;
+ padding: 0;
+}
+
+#body {
+ position: absolute;
+ bottom: 10px;
+ left: 10px;
+}
+
+#input {
+ margin-top: 0.5em;
+}
+
+#inbox .message {
+ padding-top: 0.25em;
+}
+
+#nav {
+ float: right;
+ z-index: 99;
+}
diff --git a/speech/grpc/static/chat.js b/speech/grpc/static/chat.js
new file mode 100644
index 00000000000..5c32761a453
--- /dev/null
+++ b/speech/grpc/static/chat.js
@@ -0,0 +1,71 @@
+// Copyright 2009 FriendFeed
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+$(document).ready(function() {
+ if (!window.console) window.console = {};
+ if (!window.console.log) window.console.log = function() {};
+
+ $("#messageform").on("submit", function() {
+ newMessage($(this));
+ return false;
+ });
+ $("#messageform").on("keypress", function(e) {
+ if (e.keyCode == 13) {
+ newMessage($(this));
+ return false;
+ }
+ });
+ $("#message").select();
+ updater.start();
+});
+
+function newMessage(form) {
+ var message = form.formToDict();
+ updater.socket.send(JSON.stringify(message));
+ form.find("input[type=text]").val("").select();
+}
+
+jQuery.fn.formToDict = function() {
+ var fields = this.serializeArray();
+ var json = {}
+ for (var i = 0; i < fields.length; i++) {
+ json[fields[i].name] = fields[i].value;
+ }
+ if (json.next) delete json.next;
+ return json;
+};
+
+var updater = {
+ socket: null,
+
+ start: function() {
+ var url = "ws://192.168.85.196/chatsocket";
+ console.log("received message");
+ updater.socket = new WebSocket(url);
+ updater.socket.onmessage = function(event) {
+ updater.showMessage(JSON.parse(event.data));
+ console.log("received message "+JSON.parse(event.data).body);
+ responsiveVoice.speak(JSON.parse(event.data).body, 'Thai Female');
+ }
+ },
+
+ showMessage: function(message) {
+ var existing = $("#m" + message.id);
+ if (existing.length > 0) return;
+ var node = $(message.html);
+ node.hide();
+ $("#inbox").append(node);
+ node.slideDown();
+ }
+};
diff --git a/speech/grpc/templates/chat.css b/speech/grpc/templates/chat.css
new file mode 100644
index 00000000000..a400c326057
--- /dev/null
+++ b/speech/grpc/templates/chat.css
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2009 FriendFeed
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+body {
+ background: white;
+ margin: 10px;
+}
+
+body,
+input {
+ font-family: sans-serif;
+ font-size: 10pt;
+ color: black;
+}
+
+table {
+ border-collapse: collapse;
+ border: 0;
+}
+
+td {
+ border: 0;
+ padding: 0;
+}
+
+#body {
+ position: absolute;
+ bottom: 10px;
+ left: 10px;
+}
+
+#input {
+ margin-top: 0.5em;
+}
+
+#inbox .message {
+ padding-top: 0.25em;
+}
+
+#nav {
+ float: right;
+ z-index: 99;
+}
diff --git a/speech/grpc/templates/chat.js b/speech/grpc/templates/chat.js
new file mode 100644
index 00000000000..8cc89021c9b
--- /dev/null
+++ b/speech/grpc/templates/chat.js
@@ -0,0 +1,73 @@
+// Copyright 2009 FriendFeed
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+$(document).ready(function() {
+ if (!window.console) window.console = {};
+ if (!window.console.log) window.console.log = function() {};
+
+ $("#messageform").on("submit", function() {
+ newMessage($(this));
+ return false;
+ });
+ $("#messageform").on("keypress", function(e) {
+ if (e.keyCode == 13) {
+ newMessage($(this));
+ return false;
+ }
+ });
+ $("#message").select();
+ updater.start();
+});
+
+function newMessage(form) {
+ var message = form.formToDict();
+ updater.socket.send(JSON.stringify(message));
+ form.find("input[type=text]").val("").select();
+}
+
+jQuery.fn.formToDict = function() {
+ var fields = this.serializeArray();
+ var json = {}
+ for (var i = 0; i < fields.length; i++) {
+ json[fields[i].name] = fields[i].value;
+ }
+ if (json.next) delete json.next;
+ return json;
+};
+
+var updater = {
+ socket: null,
+
+ start: function() {
+ // var url = "ws://" + location.host + "/chatsocket";
+ var url = "ws://192.168.85.196:8080/chatsocket";
+ // var url = "ws://localhost/chatsocket";
+ console.log("received message");
+ updater.socket = new WebSocket(url);
+ updater.socket.onmessage = function(event) {
+ updater.showMessage(JSON.parse(event.data));
+ console.log("received message "+JSON.parse(event.data).body);
+ responsiveVoice.speak(JSON.parse(event.data).body, 'Thai Female');
+ }
+ },
+
+ showMessage: function(message) {
+ var existing = $("#m" + message.id);
+ if (existing.length > 0) return;
+ var node = $(message.html);
+ node.hide();
+ $("#inbox").append(node);
+ node.slideDown();
+ }
+};
diff --git a/speech/grpc/templates/chatdemo.py b/speech/grpc/templates/chatdemo.py
new file mode 100755
index 00000000000..f0e5246fcf7
--- /dev/null
+++ b/speech/grpc/templates/chatdemo.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+#
+# Copyright 2009 Facebook
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+"""Simplified chat demo for websockets.
+
+Authentication, error handling, etc are left as an exercise for the reader :)
+"""
+
+import logging
+import tornado.escape
+import tornado.ioloop
+import tornado.options
+import tornado.web
+import tornado.websocket
+import os.path
+import uuid
+
+from tornado.options import define, options
+
+define("port", default=8888, help="run on the given port", type=int)
+
+
+class Application(tornado.web.Application):
+ def __init__(self):
+ handlers = [
+ (r"/", MainHandler),
+ (r"/test", TestHandler),
+ (r"/chatsocket", ChatSocketHandler),
+ ]
+ settings = dict(
+ cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
+ template_path=os.path.join(os.path.dirname(__file__), "templates"),
+ static_path=os.path.join(os.path.dirname(__file__), "static"),
+ xsrf_cookies=False,
+ )
+ super(Application, self).__init__(handlers, **settings)
+
+
+class MainHandler(tornado.web.RequestHandler):
+ def get(self):
+ self.render("index.html", messages=ChatSocketHandler.cache)\
+
+class TestHandler(tornado.web.RequestHandler):
+ def post(self):
+ self.set_header("Content-Type", "text/plain")
+ self.write("You wrote " + self.get_body_argument("message"))
+
+ # def post(self, message):
+ # # self.render("index.html", messages=ChatSocketHandler.cache)
+ # logging.info(message)
+ chat = {'body': u'{}'.format(self.get_body_argument("message")),
+ 'html': 'dasdasda
\n',
+ 'id': 'cf6aef33-cb77-4df5-91a4-852d560ef097'}
+ ChatSocketHandler.send_updates(chat)
+
+class ChatSocketHandler(tornado.websocket.WebSocketHandler):
+ waiters = set()
+ cache = []
+ cache_size = 200
+
+ def get_compression_options(self):
+ # Non-None enables compression with default options.
+ return {}
+
+ def open(self):
+ ChatSocketHandler.waiters.add(self)
+
+ def on_close(self):
+ ChatSocketHandler.waiters.remove(self)
+
+ @classmethod
+ def update_cache(cls, chat):
+ cls.cache.append(chat)
+ if len(cls.cache) > cls.cache_size:
+ cls.cache = cls.cache[-cls.cache_size:]
+
+ @classmethod
+ def send_updates(cls, chat):
+ logging.info("sending message to %d waiters", len(cls.waiters))
+ print(chat)
+ for waiter in cls.waiters:
+ try:
+ waiter.write_message(chat)
+ except:
+ logging.error("Error sending message", exc_info=True)
+
+ def on_message(self, message):
+ logging.info("got message %r", message)
+ parsed = tornado.escape.json_decode(message)
+ chat = {
+ "id": str(uuid.uuid4()),
+ "body": parsed["body"],
+ }
+ chat["html"] = tornado.escape.to_basestring(
+ self.render_string("message.html", message=chat))
+
+ ChatSocketHandler.update_cache(chat)
+ ChatSocketHandler.send_updates(chat)
+
+
+def main():
+ tornado.options.parse_command_line()
+ app = Application()
+ app.listen(options.port)
+ tornado.ioloop.IOLoop.current().start()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/speech/grpc/templates/index.html b/speech/grpc/templates/index.html
new file mode 100644
index 00000000000..277bde0742a
--- /dev/null
+++ b/speech/grpc/templates/index.html
@@ -0,0 +1,34 @@
+
+
+
+
+ Tornado Chat Demo
+
+
+
+
+
+
+ {% for message in messages %}
+ {% include "message.html" %}
+ {% end %}
+
+
+
+
+
+
+
diff --git a/speech/grpc/templates/index2.html b/speech/grpc/templates/index2.html
new file mode 100644
index 00000000000..277bde0742a
--- /dev/null
+++ b/speech/grpc/templates/index2.html
@@ -0,0 +1,34 @@
+
+
+
+
+ Tornado Chat Demo
+
+
+
+
+
+
+ {% for message in messages %}
+ {% include "message.html" %}
+ {% end %}
+
+
+
+
+
+
+
diff --git a/speech/grpc/templates/message.html b/speech/grpc/templates/message.html
new file mode 100644
index 00000000000..d68cc1d8d8b
--- /dev/null
+++ b/speech/grpc/templates/message.html
@@ -0,0 +1 @@
+{% module linkify(message["body"]) %}
diff --git a/speech/grpc/transcribe_streaming.py b/speech/grpc/transcribe_streaming.py
index 33f3991638d..85815fdfe71 100644
--- a/speech/grpc/transcribe_streaming.py
+++ b/speech/grpc/transcribe_streaming.py
@@ -1,4 +1,6 @@
#!/usr/bin/python
+# -- coding: utf-8 --
+
# Copyright (C) 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,6 +34,85 @@
import pyaudio
from six.moves import queue
+import requests
+import json
+import time
+
+import logging
+import tornado.escape
+import tornado.ioloop
+import tornado.options
+import tornado.web
+import tornado.websocket
+import os.path
+import uuid
+
+from tornado.options import define, options
+
+define("port", default=8888, help="run on the given port", type=int)
+
+class Application(tornado.web.Application):
+ def __init__(self):
+ handlers = [
+ (r"/", MainHandler),
+ (r"/chatsocket", ChatSocketHandler),
+ ]
+ settings = dict(
+ cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
+ template_path=os.path.join(os.path.dirname(__file__), "templates"),
+ static_path=os.path.join(os.path.dirname(__file__), "static"),
+ xsrf_cookies=True,
+ )
+ super(Application, self).__init__(handlers, **settings)
+
+class MainHandler(tornado.web.RequestHandler):
+ def get(self):
+ self.render("index.html", messages=ChatSocketHandler.cache)
+
+class ChatSocketHandler(tornado.websocket.WebSocketHandler):
+ waiters = set()
+ cache = []
+ cache_size = 200
+
+ def get_compression_options(self):
+ # Non-None enables compression with default options.
+ return {}
+
+ def open(self):
+ ChatSocketHandler.waiters.add(self)
+
+ def on_close(self):
+ ChatSocketHandler.waiters.remove(self)
+
+ @classmethod
+ def update_cache(cls, chat):
+ cls.cache.append(chat)
+ if len(cls.cache) > cls.cache_size:
+ cls.cache = cls.cache[-cls.cache_size:]
+
+ @classmethod
+ def send_updates(cls, chat):
+ print("sending updates")
+ logging.info("sending message to %d waiters", len(cls.waiters))
+ for waiter in cls.waiters:
+ try:
+ waiter.write_message(chat)
+ except:
+ logging.error("Error sending message", exc_info=True)
+
+ def on_message(self, message):
+ logging.info("got message %r", message)
+ parsed = tornado.escape.json_decode(message)
+ chat = {
+ "id": str(uuid.uuid4()),
+ "body": parsed["body"],
+ }
+ chat["html"] = tornado.escape.to_basestring(
+ self.render_string("message.html", message=chat))
+
+ ChatSocketHandler.update_cache(chat)
+ ChatSocketHandler.send_updates(chat)
+
# Audio recording parameters
RATE = 16000
CHUNK = int(RATE / 10) # 100ms
@@ -43,7 +124,6 @@
DEADLINE_SECS = 60 * 3 + 5
SPEECH_SCOPE = 'https://www.googleapis.com/auth/cloud-platform'
-
def make_channel(host, port):
"""Creates a secure channel with auth credentials from the environment."""
# Grab application default credentials from the environment
@@ -56,7 +136,6 @@ def make_channel(host, port):
return google.auth.transport.grpc.secure_authorized_channel(
credentials, http_request, target)
-
def _audio_data_generator(buff):
"""A generator that yields all available data in the given buffer.
@@ -86,13 +165,11 @@ def _audio_data_generator(buff):
yield b''.join(data)
-
def _fill_buffer(buff, in_data, frame_count, time_info, status_flags):
"""Continuously collect data from the audio stream, into the buffer."""
buff.put(in_data)
return None, pyaudio.paContinue
-
# [START audio_stream]
@contextlib.contextmanager
def record_audio(rate, chunk):
@@ -122,7 +199,6 @@ def record_audio(rate, chunk):
audio_interface.terminate()
# [END audio_stream]
-
def request_stream(data_stream, rate, interim_results=True):
"""Yields `StreamingRecognizeRequest`s constructed from a recording audio
stream.
@@ -142,7 +218,8 @@ def request_stream(data_stream, rate, interim_results=True):
sample_rate=rate, # the rate in hertz
# See http://g.co/cloud/speech/docs/languages
# for a list of supported languages.
- language_code='en-US', # a BCP-47 language tag
+ language_code='th-TH', # a BCP-47 language tag
+ # language_code='en-EN', # a BCP-47 language tag
)
streaming_config = cloud_speech_pb2.StreamingRecognitionConfig(
interim_results=interim_results,
@@ -156,7 +233,6 @@ def request_stream(data_stream, rate, interim_results=True):
# Subsequent requests can all just have the content
yield cloud_speech_pb2.StreamingRecognizeRequest(audio_content=data)
-
def listen_print_loop(recognize_stream):
"""Iterates through server responses and prints them.
@@ -169,41 +245,279 @@ def listen_print_loop(recognize_stream):
final one, print a newline to preserve the finalized transcription.
"""
num_chars_printed = 0
- for resp in recognize_stream:
- if resp.error.code != code_pb2.OK:
- raise RuntimeError('Server error: ' + resp.error.message)
-
- if not resp.results:
- continue
-
- # Display the top transcription
- result = resp.results[0]
- transcript = result.alternatives[0].transcript
-
- # Display interim results, but with a carriage return at the end of the
- # line, so subsequent lines will overwrite them.
- #
- # If the previous result was longer than this one, we need to print
- # some extra spaces to overwrite the previous result
- overwrite_chars = ' ' * max(0, num_chars_printed - len(transcript))
-
- if not result.is_final:
- sys.stdout.write(transcript + overwrite_chars + '\r')
- sys.stdout.flush()
-
- num_chars_printed = len(transcript)
-
- else:
- print(transcript + overwrite_chars)
-
- # Exit recognition if any of the transcribed phrases could be
- # one of our keywords.
- if re.search(r'\b(exit|quit)\b', transcript, re.I):
- print('Exiting..')
- break
+ try:
+ for resp in recognize_stream:
+ if resp.error.code != code_pb2.OK:
+ raise RuntimeError('Server error: ' + resp.error.message)
+
+ if not resp.results:
+ continue
+
+ # Display the top transcription
+ result = resp.results[0]
+ transcript = result.alternatives[0].transcript
+
+ # Display interim results, but with a carriage return at the end of the
+ # line, so subsequent lines will overwrite them.
+ #
+ # If the previous result was longer than this one, we need to print
+ # some extra spaces to overwrite the previous result
+ overwrite_chars = ' ' * max(0, num_chars_printed - len(transcript))
+ if not result.is_final:
+ sys.stdout.write(transcript + overwrite_chars + '\r')
+ sys.stdout.flush()
+
+ num_chars_printed = len(transcript)
+ print(transcript)
+ else:
+ print(transcript + overwrite_chars)
+
+ # Exit recognition if any of the transcribed phrases could be
+ # one of our keywords.
+ if re.search(r'\b(exit|quit)\b', transcript, re.I):
+ print('Exiting..')
+ break
+ elif re.search(r'\b(ออก)\b', transcript, re.I):
+ print('Exiting..')
+ break
+ # elif transcript == u'ออโต้ เปิดไฟ ' or transcript == u'เอาโต เปิดไฟ ' or transcript == u'oppo เปิดไฟ ' \
+ # or transcript == u'auto เปิดไฟ ' or transcript == u' auto เปิดไฟ ' or transcript == u' oppo เปิดไฟ ':
+ # print('turning on light')
+ # elif transcript == u'ออโต้ ช่วยด้วย ' or transcript == u'เอาโต ช่วยด้วย ' or transcript == u'oppo ช่วยด้วย ' \
+ # or transcript == u'auto ช่วยด้วย ' or transcript == u' auto ช่วยด้วย ' or transcript == u'เอาตัวช่วยด้วย ' \
+ # or transcript == u'auto ชื่อด้วย ' or transcript == u'auto ชื่อด้วย ' or transcript == u' oppo ช่วยด้วย ':
+ # print(u'พร้อมมาช่วยแล้วครับ')
+ # elif transcript == u'ออโต้ เรียกตำรวจ ' or transcript == u'เอาโต เรียกตำรวจ ' or transcript == u'oppo เรียกตำรวจ ' \
+ # or transcript == u'auto เรียกตำรวจ ' or transcript == u' auto เรียกตำรวจ ' or transcript == u'เอาตัวเรียกตำรวจ ' \
+ # or transcript == u'auto เรียนตำรวจ ' or transcript == u'auto ตำรวจ ' or transcript == u'ขอโทษตำรวจ ' \
+ # or transcript == u'เอาตูดตำรวจ ' or transcript == u' auto ตำรวจ ' or transcript == u'auto ตำรวจ ':
+ # print(u'ตำรวจอยู่ระหว่างทางกำลังมา')
+ # elif transcript == u'ออโต้ โรงพยาบาล ' or transcript == u'อัลโตโรงพยาบาล ' or transcript == u'oppo โรงพยาบาล ' \
+ # or transcript == u'auto โรงพยาบาล ' or transcript == u' auto โรงพยาบาล ' or transcript == u'เอาตัวโรงพยาบาล ' \
+ # or transcript == u'เอาตูดโรงพยาบาล ' or transcript == u'also โรงพยาบาล ':
+ # print(u'โรงพยาบาลกำลังมาช่วยเหลือครับ ')
+ # elif transcript == u'ออโต้ เปิดแอร์ ' or transcript == u'เอาโต เปิดแอร์ ' or transcript == u'oppo เปิดแอร์ ' \
+ # or transcript == u'auto เปิดแอร์ ' or transcript == u' auto เปิดแอร์ ' or transcript == u'อัลโต้เปิดแอร์ ':
+ # print('turning on AC')
+ # elif transcript == u'ออโต้ ไฟใหม้ ' or transcript == u'เอาโต ไฟไหม้ ' or transcript == u'oppo ไฟไหม้' \
+ # or transcript == u'auto ไฟไหม้ ' or transcript == u' auto ไฟไหม้ ' or transcript == u'รถตู้ไฟไหม้ '\
+ # or transcript == u'oppo find ไม่ ' or transcript == u'เอาตู้ไฟไหม้ ':
+ # print('ตำรวจดับเพลิงกำลังมาครับ')
+ # elif transcript == u'ออโต้ เปิดทีวี ' or transcript == u'เอาโต เปิดทีวี ' or transcript == u'oppo เปิดทีวี ' \
+ # or transcript == u'auto เปิดทีวี ' or transcript == u' auto เปิดทีวี ':
+ # print('turning on TV')
+
+ elif u'เปิดไฟ' in transcript:
+ turn_on_light()
+ print('turning on light')
+ time.sleep(2)
+ text_to_speech(u'อัลโต้ได้ทำการเปิดไฟให้แล้วค่ะ ')
+ elif u'ปิดไฟ' in transcript:
+ turn_off_light()
+ print('turning off light')
+ time.sleep(2)
+ text_to_speech(u'อัลโต้ได้ทำการปิดไฟให้แล้วค่ะ ')
+ elif u'ช่วยด้วย' in transcript:
+ print(u'พร้อมมาช่วยแล้วครับ')
+ text_to_speech(u'อัลโต้ได้ส่งข้อความและโทรเรียกคนในบ้านให้แล้วค่ะ ')
+ elif u'เรียกตำรวจ' in transcript or u'ตำรวจ' in transcript:
+ print(u'ตำรวจอยู่ระหว่างทางกำลังมา')
+ time.sleep(2)
+ text_to_speech(u'อัลโต้ได้เรียกตำรวจให้แล้วนะค่ะ อยู่ระหว่างทางค่ะ ')
+ elif u'โรงพยาบาล' in transcript:
+ print(u'โรงพยาบาลกำลังมาช่วยเหลือครับ')
+ time.sleep(2)
+ text_to_speech(u'อัลโต้ได้เรียกรถพยาบาลให้แล้วนะค่ะ อยู่ระหว่างทางค่ะ ')
+ elif u'เปิดแอร์' in transcript:
+ turn_on_ac()
+ time.sleep(2)
+ text_to_speech(u'อัลโต้ได้ทำการเปิดแอร์ให้แล้วค่ะ รอสักพักนะค่ะ ')
+ print('turning on AC')
+ elif u'ปิดแอร์' in transcript:
+ turn_off_ac()
+ print('turning off AC')
+ time.sleep(2)
+ text_to_speech(u'อัลโต้ได้ทำการปิดแอร์ให้แล้วค่ะ สบายใจได้หายห่วง ')
+ elif u'ไฟไหม้' in transcript:
+ print('ตำรวจดับเพลิงกำลังมาครับ')
+ time.sleep(2)
+ text_to_speech(u'อัลโต้ได้เรียกรถดับเพลิงให้อย่างเร่งด่วนแล้วค่ะ รอสักแป๊ปนะค่ะ ')
+ elif u'เปิดทีวี' in transcript:
+ turn_on_tv()
+ print('turning on TV')
+ time.sleep(2)
+ text_to_speech(u'อัลโต้ได้ทำการเปิดทีวีให้แล้วค่ะ คอยติดตามชมนะค่ะ ')
+ elif u'ปิดทีวี' in transcript:
+ turn_off_tv()
+ print('turning off TV')
+ time.sleep(2)
+ text_to_speech(u'อัลโต้ได้ทำการปิดทีวีให้แล้วค่ะ คอยติดตามชมนะค่ะ ')
+ elif u'ออก' in transcript:
+ print('Exiting..')
+ break
+ else:
+ print("text not matched transcript")
+ print(transcript)
num_chars_printed = 0
-
+ except:
+ print("error in listen_print_loop")
+
+def turn_on_ac():
+ # My API
+ # PUT https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/9b86fd56-4de8-4b1d-b2de-98c3f5243e27
+ print("sending turning on AC command")
+ try:
+ response = requests.put(
+ url="https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/9b86fd56-4de8-4b1d-b2de-98c3f5243e27",
+ headers={
+ "Authorization": "Bearer 9e450b2e-3acf-4494-8183-c01806684bd2",
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ data=json.dumps({
+ "command": "on"
+ })
+ )
+ print('Response HTTP Status Code: {status_code}'.format(
+ status_code=response.status_code))
+ print('Response HTTP Response Body: {content}'.format(
+ content=response.content))
+ except requests.exceptions.RequestException:
+ print('HTTP Request failed')
+
+def turn_off_ac():
+ # My API
+ # PUT https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/9b86fd56-4de8-4b1d-b2de-98c3f5243e27
+ print("sending turning off AC command")
+ try:
+ response = requests.put(
+ url="https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/9b86fd56-4de8-4b1d-b2de-98c3f5243e27",
+ headers={
+ "Authorization": "Bearer 9e450b2e-3acf-4494-8183-c01806684bd2",
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ data=json.dumps({
+ "command": "off"
+ })
+ )
+ print('Response HTTP Status Code: {status_code}'.format(
+ status_code=response.status_code))
+ print('Response HTTP Response Body: {content}'.format(
+ content=response.content))
+ except requests.exceptions.RequestException:
+ print('HTTP Request failed')
+
+def turn_on_light():
+ # front lifx
+ # PUT https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/08e75403-af24-4dcf-b1d6-ce253008858a
+ print("sending turning on Light command")
+ try:
+ response = requests.put(
+ url="https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/08e75403-af24-4dcf-b1d6-ce253008858a",
+ headers={
+ "Authorization": "Bearer 9e450b2e-3acf-4494-8183-c01806684bd2",
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ data=json.dumps({
+ "command": "on"
+ })
+ )
+ print('Response HTTP Status Code: {status_code}'.format(
+ status_code=response.status_code))
+ print('Response HTTP Response Body: {content}'.format(
+ content=response.content))
+ except requests.exceptions.RequestException:
+ print('HTTP Request failed')
+
+def turn_off_light():
+ # front lifx
+ # PUT https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/08e75403-af24-4dcf-b1d6-ce253008858a
+ print("sending turning off Light command")
+ try:
+ response = requests.put(
+ url="https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/08e75403-af24-4dcf-b1d6-ce253008858a",
+ headers={
+ "Authorization": "Bearer 9e450b2e-3acf-4494-8183-c01806684bd2",
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ data=json.dumps({
+ "command": "off"
+ })
+ )
+ print('Response HTTP Status Code: {status_code}'.format(
+ status_code=response.status_code))
+ print('Response HTTP Response Body: {content}'.format(
+ content=response.content))
+ except requests.exceptions.RequestException:
+ print('HTTP Request failed')
+
+def turn_on_tv():
+ # TV
+ # PUT https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/b64f5e3a-d447-48f8-8d86-050de41cec7a
+ print("sending turning on TV command")
+ try:
+ response = requests.put(
+ url="https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/b64f5e3a-d447-48f8-8d86-050de41cec7a",
+ headers={
+ "Cookie": "JSESSIONID=FCCFD41E2393191D2AA158F251B09CDF-n2",
+ "Authorization": "Bearer 9e450b2e-3acf-4494-8183-c01806684bd2",
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ data=json.dumps({
+ "command": "on"
+ })
+ )
+ print('Response HTTP Status Code: {status_code}'.format(
+ status_code=response.status_code))
+ print('Response HTTP Response Body: {content}'.format(
+ content=response.content))
+ except requests.exceptions.RequestException:
+ print('HTTP Request failed')
+
+def turn_off_tv():
+ # TV
+ # PUT https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/b64f5e3a-d447-48f8-8d86-050de41cec7a
+ print("sending turning off TV command")
+ try:
+ response = requests.put(
+ url="https://graph.api.smartthings.com/api/smartapps/installations/a0304624-dc42-4d93-b84f-421ff52167ca/switches/b64f5e3a-d447-48f8-8d86-050de41cec7a",
+ headers={
+ "Cookie": "JSESSIONID=FCCFD41E2393191D2AA158F251B09CDF-n2",
+ "Authorization": "Bearer 9e450b2e-3acf-4494-8183-c01806684bd2",
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ data=json.dumps({
+ "command": "off"
+ })
+ )
+ print('Response HTTP Status Code: {status_code}'.format(
+ status_code=response.status_code))
+ print('Response HTTP Response Body: {content}'.format(
+ content=response.content))
+ except requests.exceptions.RequestException:
+ print('HTTP Request failed')
+
+def text_to_speech(msg):
+ # Request (4)
+ # POST http://localhost:8888/test
+
+ try:
+ response = requests.get(
+ url="http://localhost:8080/websocket",
+ # headers={
+ # "Cookie": "_xsrf=2|944ae2e2|73e716843e1dd25abd7365e04aec06e7|1490541278",
+ # "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
+ # },
+ # data={
+ # "message": msg,
+ # },
+ )
+ print('Response HTTP Status Code: {status_code}'.format(
+ status_code=response.status_code))
+ print('Response HTTP Response Body: {content}'.format(
+ content=response.content))
+ except requests.exceptions.RequestException:
+ print('HTTP Request failed')
def main():
service = cloud_speech_pb2.SpeechStub(
@@ -224,7 +538,6 @@ def main():
# Now, put the transcription responses to use.
try:
listen_print_loop(recognize_stream)
-
recognize_stream.cancel()
except grpc.RpcError as e:
code = e.code()
@@ -232,6 +545,10 @@ def main():
if code is not code.CANCELLED:
raise
+ # tornado.options.parse_command_line()
+ # app = Application()
+ # app.listen(options.port)
+ # tornado.ioloop.IOLoop.current().start()
if __name__ == '__main__':
main()
diff --git a/speech/responsivevoic.html b/speech/responsivevoic.html
new file mode 100644
index 00000000000..da7ea387d5b
--- /dev/null
+++ b/speech/responsivevoic.html
@@ -0,0 +1,15 @@
+
+
+
+
+ Title
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/speech/tornado b/speech/tornado
new file mode 160000
index 00000000000..8ea13db107f
--- /dev/null
+++ b/speech/tornado
@@ -0,0 +1 @@
+Subproject commit 8ea13db107f4d44fadd24578e693f2838012caa7
diff --git a/speech/tornadowebserver.py b/speech/tornadowebserver.py
new file mode 100644
index 00000000000..3186aedb1cc
--- /dev/null
+++ b/speech/tornadowebserver.py
@@ -0,0 +1,16 @@
+import tornado.ioloop
+import tornado.web
+
+class MainHandler(tornado.web.RequestHandler):
+ def get(self):
+ self.write("Hello, world")
+
+def make_app():
+ return tornado.web.Application([
+ (r"/", MainHandler),
+ ])
+
+if __name__ == "__main__":
+ app = make_app()
+ app.listen(8888)
+ tornado.ioloop.IOLoop.current().start()
\ No newline at end of file