\n
Turns out that I need to use Flask-socketio in conjunction with my existing flask. In the html I just need to have the line var socket = io.connect()
\n","author":{"@type":"Person","name":"DanielJomaa"},"upvoteCount":3,"answerCount":1,"acceptedAnswer":null}}Reputation: 497
Right now I have a chatbox that uses socket.io and mongoDB to communicate with a server that allows the text to be sent to the chatbox. If need be i can do away with the mongoDB as long as it does not interfere with the displaying of the text. All of this runs on a localhost port 5000 which i have exposed using ngrok which allows me to access it through a domain. The issue is that when i access the app from a domain, all of the functionality of my server does not do what its supposed to,(I have a server.js, index.html, and a flask-app.py), the index.html and the flask-app work. I'll include the domain for reference.
I think it may have somthing to deal with the fact that the server.js does not run in conjuction with the index and the flask-app that actually returns the render_template. I start the server using npm start.
I know I know the index.html is a mess and noob level please have mercy
Here is the server:
const mongo = require('mongodb').MongoClient;
const client = require('socket.io').listen(4000).sockets;
// Connect to mongo
mongo.connect('mongodb://127.0.0.1/mongochat', function(err, db){
if(err){
throw err;
}
console.log('MongoDB connected...');
// Connect to Socket.io
client.on('connection', function(socket){
let chat = db.collection('chats');
// Create function to send status
sendStatus = function(s){
socket.emit('status', s);
}
// Get chats from mongo collection
chat.find().limit(100).sort({_id:1}).toArray(function(err, res){
if(err){
throw err;
}
// Emit the messages
socket.emit('output', res);
});
// Handle input events
socket.on('input', function(data){
let name = data.name;
let message = data.message;
// Insert message
chat.insert({name: name, message: message}, function(){
client.emit('output', [data]);
// Send status object
sendStatus({
message: '',
clear: true
});
});
});
// Handle clear
socket.on('clear', function(data){
// Remove all chats from collection
chat.remove({}, function(){
// Emit cleared
socket.emit('cleared');
});
});
});// end of server
});
This is the index.html (sorry for the mess)
<!DOCTYPE html>
<html lang="en">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script type = "text/javascript">
//==============================================
//=
</script>
<script src = "bundle.js"></script>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<title>QuickORDR</title>
<style>
#messages{height:300px;}
</style>
<style>
{#.chat-message {#}
{# width: 100px;#}
{# word-break: break-word;#}
{# margin-bottom: 20px;#}
{#}#}
.break-all{
word-break: break-all;
}
preBot{
color:#317df7;
text-align:left;
display: block;
font-family: Helvetica;
white-space: pre;
margin: 1em 0;
}
preUser{
color:#09c64c;
display: block;
font-family: Helvetica;
white-space: pre;
margin: 1em 0;
text-align: right;
}
</style>
</head>
<body style ="background-color: #eee;">
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3 col-sm-12">
<br>
<h1 class="text-center">
Quik Ordr
<button id="clear" class="btn btn-warning">Clear</button>
</h1>
<div id="status"></div>
<div id="chat">
<input type="text" id="username" name = "username" class="form-control" placeholder="Enter name..." style="display:none;" wrap="soft">
<br>
<div class="card">
<div id="messages" class="card-block", style="overflow:auto" >
</div>
</div>
<br>
<textarea id="textarea" name = "message" class="form-control" placeholder="Enter message..."></textarea>
<br />
<div class="yes" style="display:none;"><button id="yes" class="btn btn-success" display ="none">Correct</button> <button id="no" class="btn btn-danger">Incorrect</button> </div>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
<script>
(function(){
sendStatus = function(s){
socket.emit('status', s);
}
var element = function(id){
return document.getElementById(id);
}
// Connect to socket.io
var socket = io.connect('http://127.0.0.1:4000');
//var socket = io.connect('http://1372aecb.ngrok.io:4000');
socket.emit('clear'); // need to make sure that text area is clear before it can work
// Get Elements
var status = element('status');
var messages = element('messages');
var textarea = element('textarea');
var username = element('username');
var clearBtn = element('clear');
var yesBtn = element('yes');
var noBtn = element('no');
// Set default status
var statusDefault = status.textContent;
var setStatus = function(s){
// Set status
status.textContent = s;
if(s !== statusDefault){
var delay = setTimeout(function(){
setStatus(statusDefault);
}, 4000);
}
}
// Check for connection
if(socket !== undefined){
console.log('Connected to socket...');
// Handle Output
socket.on('output', function(data){
//console.log(data);
if(data.length){
for(var x = 0;x < data.length;x++){
// Build out message div
var message = document.createElement('div');
message.setAttribute('class', 'chat-message');
if (data[x].name[0] != 'C'){
message.innerHTML = "<preBot>" + data[x].name+ data[x].message +'</preBot>';
}
else {
message.innerHTML = "<preUser>" + data[x].name + ": " + data[x].message + '</preUser>';
}
messages.appendChild(message);
messages.appendChild(document.createElement('hr'));
messages.classList.add('break-all');
console.log(message);
messages.insertBefore(message, messages.nextSibling);
}
}
});
// Get Status From Server
socket.on('status', function(data){
// get message status
setStatus((typeof data === 'object')? data.message : data);
// If status is clear, clear text
if(data.clear){
textarea.value = '';
}
});
// Handle Input
textarea.addEventListener('keydown', function(event){
if(event.which === 13 && event.shiftKey == false){
// Emit to server input
socket.emit('input', {
name:'Customer',
message:textarea.value
});
//takes the text from the user and sends it to the pythoncode
//returns the query code and emits it
$.ajax({
url: '/sendToBot',
data: $('textarea').serialize(),
type: 'POST',
}).done(function(data){
console.log(data);
item_summary = data['summary'];
auto_correct = data['autocorrect'];
console.log(item_summary);
console.log(auto_correct);
//emit the bot message summary
socket.emit('input',{
name: '',
message:item_summary
});
//emit the bot message autocorrect
// socket.emit('input',{
//name: 'SpellCorrect',
// message:auto_correct
//});
//dump the bot data
//if the item summary is there, activate the buttons
var bot_message = item_summary;
if(bot_message[0] == 'Q'){
$(".yes").show(1000);
}
});
event.preventDefault();
}
});//end of text click event
//use socket to clear to run the success/fail button execution
yesBtn.addEventListener('click', function(){
//ajax a trigger to add a correct tag to the messages
$.ajax({
url: '/correct',
data: $('textarea').serialize(),//just a placeholder
type: 'POST',
success: function(response){
console.log(response);
},
error: function(error){
console.log(error);
}
});
socket.emit('clear');
socket.emit('input',{
name: '',
message:'Thanks! Try Again'
});
$('.yes').hide(1000);
});
//handle the no button click
noBtn.addEventListener('click', function(){
//ajax a trigger to add an incorrect tag to the messages
$.ajax({
url: '/incorrect',
data: $('textarea').serialize(),//just a placeholder
type: 'POST',
success: function(response){
console.log(response);
},
error: function(error){
console.log(error);
}
});
//wipe the message box
socket.emit('clear');
//output the repeate code
socket.emit('input',{
name: '',
message:'Thanks! Try Again'
});
$('.yes').hide(1000);
});
// Handle Chat Clear
clearBtn.addEventListener('click', function(){
socket.emit('clear');
});
// Clear Message
socket.on('cleared', function(){
$('.yes').hide(1000);
messages.textContent = '';
});
}
})();
</script>
</body>
</html>
This is the flask-app:
import os
import time
from flask import Flask,render_template, request,json,jsonify
import chatbot
import pandas as pd
#pip install pandas
#pip install nltk
#pip install
app = Flask(__name__)
messagesList = [
]
#this basically just sets the excel file to a couple of empty cells
def reset_excel():
cols = ['User TimeStamp', 'Bot TimeStamp', 'User Message', 'Bot Message', 'Status']
empty_data = [['','','','','']]
df = pd.DataFrame(empty_data, columns=cols)
df.to_csv('database.csv', encoding='utf-8', index=False)
#this makes sure that the dict is in order for the excel file
def append_in_order(dictionary_list):
the_data = [[dictionary_list[0]['user_time'], dictionary_list[2]['bot time'],
dictionary_list[3]['user'],dictionary_list[1]['bot'],dictionary_list[4]['status']]]
return the_data
#function that dumps the data to a panda then a csv
def dumpData(messagesList):
cols = ['User TimeStamp', 'Bot TimeStamp', 'User Message', 'Bot Message', 'Status']
the_data = append_in_order(messagesList)
df = pd.DataFrame(the_data, columns= cols)
with open('database.csv', 'a') as file:
df.to_csv(file, header=False, index = False)
messagesList.clear()
#initialize the time variable
ts = time.gmtime()
def printmessage(txt):
if txt == 'message list':
print(messagesList)
elif txt == 'bot fail':
print('bot failed')
print(txt)
def dummmybot(txt):
msg = chatbot.bot(txt)
return {'message': msg}
#this will lauch the html page
@app.route('/')
def chat():
return render_template('index.html')
#this will collect the input from the user
@app.route('/sendToBot', methods=['POST'])
def sendToBot():
messagesList.clear()
message = request.form['message'] #this is a string that is returned from the ajax
if message == 'reset_excel_database': #sec
reset_excel()
message_time = time.strftime("%m-%d %H:%M:%S") #grab the timestamp for the user message
messagesList.append({'user_time':message_time})
bot_message = chatbot.bot(message)
item_summary = bot_message[0]
autocorrect = bot_message[1]
send_to_chat = {'summary': item_summary, 'autocorrect':autocorrect}#pass message into bot
printmessage(bot_message[0])
printmessage(bot_message[1])
messagesList.append({'bot':send_to_chat['summary']})#append the bot message
bot_message_time = time.strftime("%m-%d %H:%M:%S")
messagesList.append({'bot time':bot_message_time}) #append the bot time
new_message = {'user':message}
messagesList.append(new_message)
return jsonify(send_to_chat) #returns the message from the bot
@app.route('/correct', methods=['POST'])
def correct():
ignore = request.form['message']#just a placeholder
correct_id = {'status':'Correct'}
messagesList.append(correct_id)
#dump the message list to a csv file using pandas
printmessage('message list')
dumpData(messagesList)
return jsonify(correct_id)
@app.route('/incorrect', methods= ['POST'])
def incorrect():
ignore = request.form['message']#just a placeholder
incorrect_id = {'status':'inc orrect'}
messagesList.append(incorrect_id)
printmessage('message list')
#dump the message list int a csv file using pandas
dumpData(messagesList)
return jsonify(incorrect_id)
if __name__=="__main__":
app.run(port = 27017)
Turns out that I need to use Flask-socketio in conjunction with my existing flask. In the html I just need to have the line var socket = io.connect()
Upvotes: 3
Views: 1741
Reputation: 28639
You seem to have a few issues - here are two observations just looking at your client side interface ( I have not read your posted code at all )
Firstly, the client JS resource, https://143bd63a.ngrok.io/bundle.js
returns a 404, so if this is supposed to serve functional client side logic, it is never loaded into the browser.
Secondly, your web-app appears to making it's web-socket calls to the wrong host. If you use the 'Network Inspector' of your favorite browser, I can see that your outgoing requests for chat messages is going to:
http://127.0.0.1:4000/socket.io/?EIO=3&transport=polling&t=MFIA9lc
This is incorrect as my computer is not the one service the responses -
It seems like the app should actually be making it's socket request to
https://143bd63a.ngrok.io:4000
However, this port does not appear to be forwarded through your firewall - because even though it appears as if your app should listen on port 4000, this gives me a connection timeout when I attempt to open the socket.
Upvotes: 1