<jupyter_start><jupyter_text>Chat App Using Flask, SocketIO and Google ColabIn this short tutorial, you'll learn how to create a simple but elegant chat app and host it on Google Cloud (for free) under 5 minutes .Here's how the App would look like:On Mobile:![Working Flask Chat app.](../img/flask-chat-1.png?raw=1)On Browser:![Working Flask Chat app.](../img/flask-chat-2.png?raw=1)  What you'll build* A fully working real-time multi user chat app.* Mobile and web friendly Progressive Web App (PWA).* Public URL to share with family/friends.* Hosted on Google Cloud for free. What you'll learn* Dveloping a useful [Flask](http://flask.pocoo.org/) web app.* Using [WebSocket](https://en.wikipedia.org/wiki/WebSocket) with [Flask-SocketIO](https://flask-socketio.readthedocs.io/en/latest/) for bi-directional real-time communication.* How to create a public URL with [ngrok](https://ngrok.com/) to share your web app.* How to run a web server on Colab. What you'll need* Gmail account to access [Google Colaboratory](https://colab.research.google.com/) for free.* A browser such as Chrome.* The sample notebook. Click on the Open in Colab button below to get started.  Python PackagesPackages required to run the app. You'll use [`pip`](https://pypi.org/project/pip/) to install these packages.<jupyter_code>%%writefile requirements.txt
Flask==0.12.2
flask-socketio
eventlet==0.17.4
gunicorn==18.0.0<jupyter_output>Overwriting requirements.txt<jupyter_text>Flask AppHere you are defining event handlers to receive WebSocket (`ws`) messages using the `socketio.on` decorator and it sends reply messages to the connected client using the `send()` and `emit()` functions.Also you are defining a simple `http` endpoint `/hello` for testing purpose.<jupyter_code>%%writefile main.py
import os
import logging

from flask import Flask, render_template
from flask_socketio import SocketIO

secret = os.urandom(24).hex()

app = Flask(__name__)
app.logger.info("Starting...")
app.config['SECRET_KEY'] = secret
app.logger.critical("secret: %s" % secret)
socketio = SocketIO(app)

# render home page
@app.route('/')
def index():
    return render_template('index.html')

# Simple http endpoint
@app.route('/hello')
def hello():
    return "Hello World!"

# ws callback
def message_received(methods=['GET', 'POST']):
    app.logger.info('message was received!')

# ws event handler
@socketio.on('flask-chat-event')
def handle_flask_chat_event(json, methods=['GET', 'POST']):
    app.logger.info('received flask-chat-event: ' + str(json))
    socketio.emit('flask-chat-response', json, callback=message_received)

if __name__ == '__main__':
    socketio.run(app, debug=True)<jupyter_output>Overwriting main.py<jupyter_text>HTML TemplateHere you are defineing:1.   Web UI for the app.2.   JavaScript functions to establish `ws` connection, send and receive messages with `socket.io`.<jupyter_code>%mkdir templates -p
%%writefile templates/index.html
<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="description" content="Learn how to create a chat app using Flask">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Flask Chat</title>

  <!-- Disable tap highlight on IE -->
  <meta name="msapplication-tap-highlight" content="no">

  <!-- Web Application Manifest -->
  <link rel="manifest" href='data:application/manifest+json,{ "name": "Flask Chat", "short_name": "Flask Chat", "display": "standalone" }' />
  
  <!-- Add to homescreen for Chrome on Android -->
  <meta name="mobile-web-app-capable" content="yes">
  <meta name="application-name" content="Flask Chat">
  <meta name="theme-color" content="#303F9F">

  <!-- Add to homescreen for Safari on iOS -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
  <meta name="apple-mobile-web-app-title" content="Flask Chat">
  <meta name="apple-mobile-web-app-status-bar-style" content="#303F9F">

  <!-- Tile icon for Win8 -->
  <meta name="msapplication-TileColor" content="#3372DF">
  <meta name="msapplication-navbutton-color" content="#303F9F">
  <script async src="https://www.googletagmanager.com/gtag/js?id=UA-135532366-1"></script>
  <script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","UA-135532366-1");</script>

  <!-- Material Design Lite -->
  <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
  <link rel="stylesheet" href="https://code.getmdl.io/1.1.3/material.orange-indigo.min.css">
  <script defer src="https://code.getmdl.io/1.1.3/material.min.js"></script>

  <!-- App Styling -->
  <link rel="stylesheet"
    href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&amp;lang=en">
  <style>
    .message-container .spacing {
      display: table-cell;
      vertical-align: top;
    }

    .message-container .message {
      display: table-cell;
      width: calc(100% - 40px);
      padding: 5px 0 5px 10px;
    }

    .message-container .name {
      display: inline-block;
      width: 100%;
      padding-left: 40px;
      color: #bbb;
      font-style: italic;
      font-size: 12px;
      box-sizing: border-box;
    }
  </style>
</head>

<body>
  <div class="demo-layout mdl-layout mdl-js-layout mdl-layout--fixed-header">

    <!-- Header section containing logo -->
    <header class="mdl-layout__header mdl-color-text--white mdl-color--light-blue-700">
      <div class="mdl-cell mdl-cell--12-col mdl-cell--12-col-tablet mdl-grid">
        <div class="mdl-layout__header-row mdl-cell mdl-cell--12-col mdl-cell--12-col-tablet mdl-cell--12-col-desktop">
          <h3><i class="material-icons">chat_bubble_outline</i> Flask Chat</h3>
        </div>
      </div>
    </header>

    <main class="mdl-layout__content mdl-color--grey-100">
      <div id="messages-card-container" class="mdl-cell mdl-cell--12-col mdl-grid">

        <!-- Messages container -->
        <div id="messages-card"
          class="mdl-card mdl-shadow--2dp mdl-cell mdl-cell--12-col mdl-cell--6-col-tablet mdl-cell--6-col-desktop">
          <div class="mdl-card__supporting-text mdl-color-text--grey-600">
            <div id="messages">
              <span id="message-filler"></span>
              <div class="message-container visible">
                <div class="spacing">
                </div>
                <div class="message">Welcome!</div>
                <div class="name"><NAME></div>
              </div>
            </div>
            <form id="message-form" action="POST">
              <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
                <input class="mdl-textfield__input" type="text" id="username">
                <label class="mdl-textfield__label" for="username">User...</label>
              </div>
              <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
                <input class="mdl-textfield__input" type="text" id="message">
                <label class="mdl-textfield__label" for="message">Message...</label>
              </div>
              <button id="submit" type="submit"
                class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect">
                Send
              </button>
            </form>
          </div>
        </div>
      </div>
    </main>
  </div>
  <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.min.js"></script>
  <script type="text/javascript">
    var socket = io.connect('https://' + document.domain + ':' + location.port);

    socket.on('connect', function () {
      socket.emit('flask-chat-event', {
        data: 'User Connected'
      })
      var form = $('form').on('submit', function (e) {
        e.preventDefault()
        let user_name = $('#username').val()
        let user_input = $('#message').val()
        socket.emit('flask-chat-event', {
          user_name: user_name,
          message: user_input
        })
        $('#message').val('').focus()
      })
    })
    socket.on('flask-chat-response', function (msg) {
      console.log(msg)
      if (typeof msg.user_name !== 'undefined') {
        $('#messages').append('<div class="message-container visible"><div class="spacing"></div><div class="message">' + msg.message + '</div><div class="name">' + msg.user_name + '</div></div>')
      }
    })
  </script>
</body>

</html><jupyter_output>Overwriting templates/index.html<jupyter_text>Installing Packages and Running Web Server<jupyter_code>get_ipython().system_raw(
    'pip3 install -r requirements.txt && python3 main.py > logs.txt 2>&1 &'
)<jupyter_output><empty_output><jupyter_text>Checking the Log FileYou can check the log file with this command.<jupyter_code>!tail logs.txt<jupyter_output>[2019-06-29 18:04:09,804] CRITICAL in main: secret: 9aba1627141610d3ea12a10e7a54a08d4c595a7cb9496089
 * Restarting with stat
[2019-06-29 18:04:10,159] CRITICAL in main: secret: 74c1b6b00c53dce5d804e82e823e623c61224d955158072f
 * Debugger is active!
 * Debugger PIN: 127-941-347<jupyter_text>Verifying the Web Server is RunningYou can do a quick check if the server is up and running with `curl`.<jupyter_code># Make sure it's running on local port
PORT = 5000

!curl http://localhost:{PORT}/hello<jupyter_output>Hello World!<jupyter_text>Getting a Shareable Public URL from ngrokHere you are installing `ngrok` and obtaining a shareable URL.<jupyter_code>!wget --quiet https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -O ngrok-stable-linux-amd64.zip
!unzip -q -f ngrok-stable-linux-amd64.zip<jupyter_output><empty_output><jupyter_text>Running `ngrok`.<jupyter_code>get_ipython().system_raw(
    './ngrok http {} &'
    .format(PORT)
)<jupyter_output><empty_output><jupyter_text>Public URL<jupyter_code>public_url = !curl -s http://localhost:4040/api/tunnels | python3 -c \
    "import sys, json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])"

print(public_url[0])<jupyter_output>http://8ab37579.ngrok.io<jupyter_text>Verifying the Public URL is Accessible<jupyter_code>!curl {public_url[0]}/hello<jupyter_output>Hello World!
{'fraction_non_alphanumeric': 0.156644963615473, 'fraction_numerical': 0.024798927613941018, 'mean_word_length': 3.6629464285714284, 'pattern_counts': {'":': 3, '<': 140, '<?xml version=': 0, '>': 142, 'https://': 14, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '92919', 'license': 'MIT', 'n_tokens_mistral': 3657, 'n_tokens_neox': 3435, 'n_words': 759, 'path': 'docs/Python/Flask/Flask_Chat_Colab.ipynb', 'repo_name': 'shanaka-desoysa/short-notes', 'size': '10453'}