Welcome folks today in this blog post we will be using the flask-socket.io
library to create a chat app with image sending
support in browser using html5
forms in browser using javascript. All the full source code of the application is shown below.
Get Started
In order to get started you need to install the below libraries using the pip
command as shown below
pip install –upgrade Flask-SocketIO==5.2.0
pip install –upgrade python-engineio==4.3.3
pip install –upgrade python-socketio==5.7.1
pip install –upgrade simple-websocket==0.7.0
And now you need to create the app.py
file and copy paste the following code
app.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from flask import Flask, render_template from flask_socketio import SocketIO, send, emit app = Flask(__name__) app.config['SECRET_KEY'] = 'secret!' socketio = SocketIO(app) @app.route('/') def index(): return render_template('index.html') if __name__ == '__main__': app.debug = True socketio.run(app) |
As you can see in the above code we are importing all the flask
libraries and then we are starting the flask app at the port number 5000
.And also we are setting the debug
option to true to see the log messages. And also we are setting the secret key
of the flask app and then we are wrapping the flask
app inside the SocketIO
library. And also we are making a simple get
route at the /
endpoint. Whenever the user opens the homepage they will see the index.html
template file
Now you will need to create the templates
folder and inside it you need to create the index.html
file and copy paste the following code
templates/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<html> <head> <title>Chat</title> <script src="https:///cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.js"></script> </head> <body> <form id="form"> <input id="input" type="text" placeholder="Enter message here"> <input id="image" type="file" accept="image/*"> <button type="submit">Send</button> </form> <ul id="messages"></ul> </body> </html> |
As you can see we are including the cdn
for the socket.io
library at the client side inside the html and then we have the simple html
form where we have the input field where we allow the user to enter the chat message
and then we have the image upload
field where we allow the user to select
the images and then we have the button to send the message
. And then we have the ul
element where we are showing all the messages.
Now if you run the flask
app by executing the below command
python app.py
The app will start on http://localhost:5000.
And now if you open it you will see the html
form as shown below
And now we will be writing the javascript
code inside the index.html
file to add the functionality to the chat app
. Here we will be communicating with the backend at the flask
and socket.io
Just make a script.js
file and include the below javascript code
script.js
1 2 3 4 |
var socket = io(); var form = document.getElementById('form'); var input = document.getElementById('input'); var imageInput = document.getElementById('image'); |
As you can see we are getting the references of all the DOM
elements which are there inside the html file. And also we are starting the socket.io
server at the client side by invoking a new reference of the io()
method.
Sending Text Messages From Client to Backend
Now guys we will be taking the message which is submitted
by the user at the input
field and when the button is pressed this form submit event will be triggered
and inside it we will be emitting a event
to the socket.io server as shown below
1 2 3 4 5 6 |
form.addEventListener('submit', function(event) { event.preventDefault(); var message = input.value; socket.emit('message', message); input.value = ''; }); |
As you can see we are passing the actual message which is typed
by the user inside the input field and then we are using the emit()
method to send the event
to the socket.io server.
Receiving Message on Socket.io (Backend Side)
Now guys we will be catching the messages
or events passed at the client side in the backend side app.py
(flask) as shown below
1 2 3 4 |
@socketio.on('message') def handle_message(message): print('received message: ' + message) send(message, broadcast=True) |
As you can see we are wrapping the request
inside the @socketio.on('message')
decorator and inside it we are getting the message passed from the client side and inside we are broadcasting
this message to all the clients
connected using the send()
method and inside it we are passing the broadcast
option to True
Displaying Chat Text Messages
Now guys we need to again add some javascript
code inside the script.js
to catch the messages send by the backend
to all the clients whenever some client sends out
a message. We need to update the screen
with new messages as shown below
1 2 3 4 5 |
socket.on('message', function(message) { var li = document.createElement('li'); li.textContent = message; document.getElementById('messages').prepend(li) }); |
As you can see we are using the on()
method to receive the message
or event and inside it we are creating a new
li tag and inside it we are manipulating the text
content of the message and displaying it on the screen using the appendChild()
method.
Image Sending Using Socket.io
Now we need to repeat the same task
for the image sending as well in between multiple clients using socket.io
and javascript. First of all go to script.js
and add some code to it as shown below
1 2 3 4 5 6 7 8 |
imageInput.addEventListener('change', function(event) { var file = imageInput.files[0]; var reader = new FileReader(); reader.addEventListener('load', function() { socket.emit('image', reader.result); }); reader.readAsDataURL(file); }); |
As you can see we are selecting the image
which is selected by the user using the input field
by using FileReader()
class and after reading the content of the image file as base64
code we are passing that code to the backend using the emit()
method at the backend side to the socket.io server.
Receiving Base64 Code of Image at Backend
Now guys we will be receiving the base64
code of the image at the backend which is sent by the client side
everytime someone tries to upload the image
Now copy paste the below code inside the app.py
file
1 2 3 4 |
@socketio.on('image') def handle_image(image_data): print('received image: ' + image_data) emit('image', image_data, broadcast=True) |
As you can see this time we are using the socketio.on('image')
decorator to catch the base64
code of the image and the send
this code to all the connected clients
using the emit()
method and inside it we are passing the broadcast option to True.
Displaying Images in Browser
Now guys we will be displaying the images inside every client
browser using the base64 code which is passed from backend
side as shown below
1 2 3 4 5 6 7 8 9 |
socket.on('image', function(image_data) { var li = document.createElement('li'); var img = document.createElement('img'); img.src = image_data; img.width = 300 img.height = 300 li.appendChild(img) document.getElementById('messages').prepend(li) }); |
As you can see we are again using the on()
method to catch the event or data passed from the backend
side and inside it we are simply creating the dynamic
image element by attaching the dynamic
base64 code of the image. And then we are simply displaying the image using the appendChild()
method.
Full Source Code
templates/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<!-- templates/index.html --> <html> <head> <title>Chat</title> <script src="https:///cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.js"></script> </head> <body> <form id="form"> <input id="input" type="text" placeholder="Enter message here"> <input id="image" type="file" accept="image/*"> <button type="submit">Send</button> </form> <ul id="messages"></ul> <script> var socket = io(); var form = document.getElementById('form'); var input = document.getElementById('input'); var imageInput = document.getElementById('image'); form.addEventListener('submit', function(event) { event.preventDefault(); var message = input.value; socket.emit('message', message); input.value = ''; }); imageInput.addEventListener('change', function(event) { var file = imageInput.files[0]; var reader = new FileReader(); reader.addEventListener('load', function() { socket.emit('image', reader.result); }); reader.readAsDataURL(file); }); socket.on('message', function(message) { var li = document.createElement('li'); li.textContent = message; document.getElementById('messages').prepend(li) }); socket.on('image', function(image_data) { var li = document.createElement('li'); var img = document.createElement('img'); img.src = image_data; img.width = 300 img.height = 300 li.appendChild(img) document.getElementById('messages').prepend(li) }); </script> </body> </html> |
app.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# server.py from flask import Flask, render_template from flask_socketio import SocketIO, send, emit app = Flask(__name__) app.config['SECRET_KEY'] = 'secret!' socketio = SocketIO(app) @app.route('/') def index(): return render_template('index.html') @socketio.on('message') def handle_message(message): print('received message: ' + message) send(message, broadcast=True) @socketio.on('image') def handle_image(image_data): print('received image: ' + image_data) emit('image', image_data, broadcast=True) if __name__ == '__main__': app.debug = True socketio.run(app) |