Skip to main content

Build Online Web Chat using Flask and Python

In our previous Python project tutorial, we have developed School Management System with Python, Flask and MySQL. In this tutorial, we will develop Online Web Chat using Flask and Python.

A web chat system is an online interface that allows to communicate directly with peoples in real time. Here, we will develop a web chat system using Flask web framework and Flask-SocketIO module that enables bi-directional communication between the server and the client using WebSockets. The WebSockets are a protocol that enables fast and efficient data transfer between the browser and the server, without polling or refreshing.

So let’s proceed with developing Online Web Chat project:

1. Project Setup and Module Installation

First we will create our project web-chat-app-python-flask using below command.

$ mkdir web-chat-app-python-flask

and moved to the project.

$ cd web-chat-app-python-flask

Then we will install required modules for our application. As we will develop a web based application, so we will install Flask micro framework module to create web application.

$ pip install Flask

As we will use Flask-SocketIO module in this project, so we will install this module:

$ pip install flask-socketio

2. Initialize Application

We will create project python file main.py and import required modules. We will create flask instance and also create SocketIO instance.

from flask import Flask, request, render_template, redirect, url_for, session
from flask_socketio import SocketIO, join_room, leave_room, send

from utils import getRoomCode

app = Flask(__name__)
app.config['SECRET_KEY'] = 'ABCDFRHGRPTY'
socketio = SocketIO(app)

We run our app using the SocketIO instance with socketio.run(app, debug=True) instead of using the Flask instance.

if __name__ == '__main__':
    socketio.run(app, debug=True)

3. Create Web Chat Home

We will create route to load home page home.html for our chatroom app. We will handle for submit create chatroom or join chatroom.

rooms = {}

@app.route('/', methods=["GET", "POST"])
def home():
    session.clear()
    if request.method == "POST":
        name = request.form.get('name')
        create = request.form.get('create', False)
        code = request.form.get('code')
        join = request.form.get('join', False)

        if not name:
            return render_template('home.html', error="Name is required", code=code)

        if create != False:
            room_code = getRoomCode(6, list(rooms.keys()))
            new_room = {
                'members': 0,
                'messages': []
            }
            rooms[room_code] = new_room

        if join != False:            
            if not code:
                return render_template('home.html', error="Please enter a room code to enter a chat room", name=name)            
            if code not in rooms:
                return render_template('home.html', error="Room code invalid", name=name)

            room_code = code

        session['room'] = room_code
        session['name'] = name
        return redirect(url_for('room'))
    else:
        return render_template('home.html')

We will create home.html and design home page html.

{% extends 'base.html' %} {% block content %}
<div id="home-container">
  <h1 id="home-header">Online Web Chat</h1>

  {% if error %}
  <p id="error">{{error}}</p>
  {% endif %}

  <form method="post" id="chat-widget-home">
    <div id="name-input">
      <label for="name"></label>
      <input
        type="text"
        id="name"
        name="name"
        placeholder="Enter name"
        value="{{name}}"
      />
    </div>
    <div>
      <label for="code" id="code-label"></label>
      <input
        type="text"
        id="code"
        name="code"
        placeholder="Enter code"
        value="{{code}}"
      />
      <button type="submit" id="join" name="join">Join</button>
    </div>
    <hr />
    <button type="submit" id="create" name="create">Create Room</button>
  </form>
</div>
{% endblock %}

4. Create Chat Room

We will route for room and load room.html template to load chat room page. We will display chat and also handle message send functionality.

@app.route('/room')
def room():
    room = session.get('room')
    name = session.get('name')

    if name is None or room is None or room not in rooms:
        return redirect(url_for('home'))

    messages = rooms[room]['messages']
    return render_template('room.html', room=room, user=name, messages=messages)

We will create room.html template and create html for room page. We will also includes the SocketIO connection JavaScript code on the client side to send message.

{% extends 'base.html' %} {% block content %}
<div id="room-container">
  <h1 id="home-header">Online Web Chat</h1>
  <div id="room-subsection">
    <span id="room-code-display">Room Code: <span>{{room}}</span></span>
    <span><a href="/" id="leave-chat-btn">Leave</a></span>
  </div>

  <div id="chat-room-widget">
    <div id="msgs-container">
      <ul id="messages"></ul>
    </div>

    <div id="message-box">
      <input
        type="text"
        placeholder="Enter your message"
        id="message-input"
        name="message"
      />
      <button type="submit" id="send-btn" onclick="sendMessage()">Send</button>
    </div>
  </div>

  <script type="text/javascript">
    var socketio = io();

    socketio.on("message", function (message) {
      createMessage(message.message, message.sender);
    });

    function createMessage(message, sender) {
      var messages = document.getElementById("messages");

      if (sender === "") {
        content = `
          <p class="member-activity">${message}</p>
        `;
      } else {
        var senderIsUser = "{{user}}" === sender;
        var content = `
          <li class="message-item ${
            senderIsUser ? "self-message-item" : "peer-message-item"
          }">
              <p>${message}</p>
              <small class="${
                senderIsUser ? "muted-text" : "muted-text-white"
              }">${new Date().toLocaleString()}</small>
          </li>
      `;
      }

      messages.innerHTML += content;
    }

    function sendMessage() {
      var msgInput = document.getElementById("message-input");
      if (msgInput.value === "") return;

      var msg = msgInput.value;
      socketio.emit("message", { message: msg });
      msgInput.value = "";
    }
  </script>

  {% for message in messages %}
  <script type="text/javascript">
    createMessage("{{message.message}}", "{{message.sender}}");
  </script>
  {% endfor %}
</div>
{% endblock %}

5. Handle Web Websocket Events

We will also handle websockets events at server side. Here we will handle connect, message and disconnect events.

So first we will handle connect that fired when a client connects to the server. It uses the room id and user name passed by the client to let the user join the chat room, then redirects the user to the chat room page with the message.

@socketio.on('connect')
def handle_connect():
    name = session.get('name')
    room = session.get('room')

    if name is None or room is None:
        return
    if room not in rooms:
        leave_room(room)

    join_room(room)
    send({
        "sender": "",
        "message": f"{name} has entered the chat"
    }, to=room)
    rooms[room]["members"] += 1

We will handle message event that fired when the client or server sends a message to each other. This event handler expects a data payload where it retrieves the user’s message. It will then send the message to the chat room for everyone to see in rooms.

@socketio.on('message')
def handle_message(payload):
    room = session.get('room')
    name = session.get('name')

    if room not in rooms:
        return

    message = {
        "sender": name,
        "message": payload["message"]
    }
    send(message, to=room)
    rooms[room]["messages"].append(message)

We will also handle disconnect event that fired when user leaves a chat room. This event handler just removes the user from the chat room and lets everyone knows the user has left by sending a message event to the chat room.

@socketio.on('disconnect')
def handle_disconnect():
    room = session.get("room")
    name = session.get("name")
    leave_room(room)

    if room in rooms:
        rooms[room]["members"] -= 1
        if rooms[room]["members"] <= 0:
            del rooms[room]

    send({
        "message": f"{name} has left the chat",
        "sender": ""
    }, to=room)

In this tutorial, you have learned how to use SocketIO technology in Python using Flask and Flask-SocketIO. This is a simple web chat app, you can try to develop real-time bi-directional communication with SocketIO in your future projects.

You can download the complete source code of project from the Download link below.

Download