Sending an array as json Flask to React.js - reactjs

I am using flask as a backend as a server for OpenCV's facial detection module. I cannot seem to access the x and y coordinates of the face and send them to the react.js front end. I am new to the flask, this is the error I am receiving:
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0.
I believe this is because the flask server is not sending readable JSON to react.js, but I am sure I am doing other things improperly. I am wondering how exactly I can save data into an array and send it to react in a JSON format.
camera.py:
import cv2
import json
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
class VideoCamera(object):
def __init__(self):
self.video = cv2.VideoCapture(0)
#must delete webcam otherwise the webcam will become "trapped" and you cannot use it for other apps until the computer restarts
def __del__(self):
self.video.release()
# geting the frame and converting it to jpeg format
def get_frame(self):
success, frame = self.video.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),3)
break #exit loop after rendering one face
ret, jpeg = cv2.imencode('.jpg', frame)
return jpeg.tobytes()
def get_axis(self):
success, frame = self.video.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
axisArr = []
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
axisArr = [x,y,w,h]
break #exit loop after rendering one face
return json.dumps(axisArr)
server.py:
from flask import Flask, render_template, Response
from camera import VideoCamera
app = Flask(__name__, template_folder='../../frontend/src')
def index():
return render_template('index.html')
def setAxis(axisGen):
global axis
axis = axisGen
def gen(camera):
while True:
frame = camera.get_frame()
axisGen = camera.get_axis()
setAxis(axisGen)
# creates html render template
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
#app.route('/video_feed')
def video_feed():
return Response(gen(VideoCamera()),
mimetype='multipart/x-mixed-replace; boundary=frame') #explains the type of response the html is receiving and sending it to the browser
#app.route('/members')
def members():
return {"members": axis}
# initialize the server to run the flask app on, debug mode means you do not need to close and reopen the server to see changes
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port='4999')

Related

Make stream accessible to multiple machines

I have a small USB camera connected to my Raspberry Pi 3b+. I would like to stream whatever that camera is looking at over the internet (or in this case, local network) to any other machine that visits certain address.
When it comes to software setup, the Raspberry Pi is hosting a simple Flask server (whose code you can find below) that's supposed to show the stream on its own page.
On my PC, I host another simple React server that just uses <iframe> tag to stream that video from Flask server on its webpage.
Once more: camera looks at something -> that's streamed on Flask server -> that's captured and streamed on React frontend.
The implementation seems to serve its purpose until two or more people (from different machines) want to look at the camera's stream (React.js frontend).
It's only available for the first person who looks at it.
One thing I would point out is the fact that I can't access camera globally, so I need to (for some reason) access it down there in the function.
app.py
from flask import Flask, render_template, Response, request, redirect
import cv2
import sys
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
def gen_frames(): # generate frame by frame from camera
camera = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
success, frame = camera.read() # read the camera frame
if not success:
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
#app.route('/video_feed')
def video_feed():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
#app.route('/move', methods=['POST'])
def move():
print(request.form.get('direction'))
return redirect("/")
#app.route('/')
def index():
"""Video streaming home page."""
return render_template('index.html')
if __name__ == '__main__':
app.run(host="192.168.1.4",port="1234",debug=True)
index.html
<html>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 offset-lg-2">
<h3 class="mt-5">Live Streaming</h3>
<img src="{{ url_for('video_feed') }}" width="100%">
</div>
</div>
</div>
</body>
</html>
React frontend:
import './App.css';
import React, { Component } from 'react'
// import axios from 'axios';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {stream: true};
}
loadStream = () => {
if(this.state.stream) {
return <>
<img width="500px" height="500px"
src="http://192.168.1.4:1111/video_feed">
</img>
<br/>
</>
}
}
render() {
return (
<>
{this.loadStream()}
</>
)
}
}
I think the problem is when the first client request video_feed the main process stays blocked then the second client request video_feed and the server throws a timeout therefore the server killed the process, create a new one and assign to the second client. I recently worked in a raspberry video streaming project using opencv and the official raspberry pi camera.
You should take a look at Miguel Grinberg's blog he implements threads in a fashionable way, basically managing its events and logic in base_camera class. You can implemented using opencv as follows:
app.py
from flask import Flask, render_template, Response, request, redirect
from flask_cors import CORS
from camera_opencv import Camera
app = Flask(__name__)
CORS(app)
def gen(camera):
"""Video streaming generator function."""
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
#app.route('/video_feed')
def video_feed():
"""Video streaming route. Put this in the src attribute of an img tag."""
return Response(gen(Camera()),
mimetype='multipart/x-mixed-replace; boundary=frame')
#app.route('/move', methods=['POST'])
def move():
print(request.form.get('direction'))
return redirect("/")
#app.route('/')
def index():
"""Video streaming home page."""
return render_template('index.html')
if __name__ == '__main__':
app.run(host="192.168.1.4",port="1234",debug=True)
camera_opencv.py
import os
import cv2
from base_camera import BaseCamera
class Camera(BaseCamera):
video_source = 0
def __init__(self):
super(Camera, self).__init__()
#staticmethod
def set_video_source(source):
Camera.video_source = source
#staticmethod
def frames():
camera = cv2.VideoCapture(Camera.video_source)
if not camera.isOpened():
raise RuntimeError('Could not start camera.')
while True:
# read current frame
_, img = camera.read()
# encode as a jpeg image and return it
yield cv2.imencode('.jpg', img)[1].tobytes()
base_camera.py
import time
import threading
try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident
class CameraEvent(object):
"""An Event-like class that signals all active clients when a new frame is
available.
"""
def __init__(self):
self.events = {}
def wait(self):
"""Invoked from each client's thread to wait for the next frame."""
ident = get_ident()
if ident not in self.events:
# this is a new client
# add an entry for it in the self.events dict
# each entry has two elements, a threading.Event() and a timestamp
self.events[ident] = [threading.Event(), time.time()]
return self.events[ident][0].wait()
def set(self):
"""Invoked by the camera thread when a new frame is available."""
now = time.time()
remove = None
for ident, event in self.events.items():
if not event[0].isSet():
# if this client's event is not set, then set it
# also update the last set timestamp to now
event[0].set()
event[1] = now
else:
# if the client's event is already set, it means the client
# did not process a previous frame
# if the event stays set for more than 5 seconds, then assume
# the client is gone and remove it
if now - event[1] > 5:
remove = ident
if remove:
del self.events[remove]
def clear(self):
"""Invoked from each client's thread after a frame was processed."""
self.events[get_ident()][0].clear()
class BaseCamera(object):
thread = None # background thread that reads frames from camera
frame = None # current frame is stored here by background thread
last_access = 0 # time of last client access to the camera
event = CameraEvent()
def __init__(self):
"""Start the background camera thread if it isn't running yet."""
if BaseCamera.thread is None:
BaseCamera.last_access = time.time()
# start background frame thread
BaseCamera.thread = threading.Thread(target=self._thread)
BaseCamera.thread.start()
# wait until frames are available
while self.get_frame() is None:
time.sleep(0)
def get_frame(self):
"""Return the current camera frame."""
BaseCamera.last_access = time.time()
# wait for a signal from the camera thread
BaseCamera.event.wait()
BaseCamera.event.clear()
return BaseCamera.frame
#staticmethod
def frames():
""""Generator that returns frames from the camera."""
raise RuntimeError('Must be implemented by subclasses.')
#classmethod
def _thread(cls):
"""Camera background thread."""
print('Starting camera thread.')
frames_iterator = cls.frames()
for frame in frames_iterator:
BaseCamera.frame = frame
BaseCamera.event.set() # send signal to clients
time.sleep(0)
# if there hasn't been any clients asking for frames in
# the last 10 seconds then stop the thread
if time.time() - BaseCamera.last_access > 10:
frames_iterator.close()
print('Stopping camera thread due to inactivity.')
break
BaseCamera.thread = None
wsgi.py
from app import app
if __name__ == "__main__":
app.run()
Gunicorn's script:
gunicorn --worker-class gevent --bind 0.0.0.0:1234 wsgi:app
I would recommend you to use gunicorn's worker as per coroutines request because is good for I/O bounded applications(for example stream using opencv) for that you must install asynchronous libraries as gevent or evenlet. If you you like to take a look to the different worker types of medium has a good intro.
Good luck, regards.

How do I take a mongodb json to flask to react?

So I want to take my mongo db and use it in react, its small so it won't overpower react. My Flask looks like this
import subprocess
from flask import Flask, request, jsonify, json
from flask_cors import CORS, cross_origin
import pymongo
disaster = ""
app = Flask(__name__)
CORS(app, support_credentials=True)
client = pymongo.MongoClient("NOT IMPORTANT FOR GITHUB")
db = client["twitterdb"]
col = db["tweets"]
our_mongo_database_compressed = col.find({},{'user.created_at':1, 'user.location':1,'_id':0})
def request_tweets(disaster):
print(disaster)
#subprocess.call("./../../../backend/get_tweets", disaster)
#app.route('/refresh_data', methods=['GET', 'POST'])
##cross_origin(supports_credentials=True)
def refresh_data():
disaster = request.get_json()
request_tweets(disaster)
x = 0
y = []
for datas in our_mongo_database_compressed:
y.append(datas)
if(x > 100):
break
x+=1
#print(y)
return str(y)
and my react function looks like
this.setState({
disaster: event.target.value
})
axios.post('http://localhost:5000/refresh_data', [this.state.disaster])
.then(function(response){
console.log(JSON.parse(response.data));
})
}
I keep getting a " Unexpected token ' in JSON at position 2" and I just want the data to be sent to react
So I figured it out and I want anyone who has this problem in the future to be able to see this.
for datas in our_mongo_database_compressed:
y.append(datas)
This creates an array of dictionaries. so y[0]["user"]["location"] would be how you'd get an element from this array.
With that in mind we need to change this array to a JSON String which is a data type that you use to transfer between flask and react so you'd return
return json.dumps(y)
Now you might think this means that you got a string in React when you write
JSON.parse(response.data)
NO. That would be too easy, you have a response object that secretly a string. So you'd need to change the response object into a string with JSON stringify
JSON.parse(JSON.stringify(response.data))
Now you have your json in react

Flask only accept single json variable and crashed when setting two variables

I am building a web crawler app on Google App Engine. I want to use a post method to pass the variable to Flask. Then, the received variable became the input of my web crawler app. However, Flask only accept single variable from post. If I add another variable in the funciton, Flask would crash.
I have limited knowledge in Flask and Google app engine. I struggled with the problem for several days and your help will be highly appreciated.
Failed function
#server-side function that does not work,with 2 variable passed
#app.route('/bac',methods=['GET', 'POST'])
def bac():
request_json = request.get_json()
filename = request_json["filename"]
url = request_json["url"]
#baseconnect.Baseconnect(url=url,filename=filename).run()
return filename,url
#The function to post on client side
import requests
req = requests.Session()
data = req.post('https://project.appspot.com/bac',json={"filename":"yuan","url":"https:...f5"})
print(data.text)
#output:
Internal server eror 500
Succeeded function
#server-side function that works,with 1 variable passed
#app.route('/bac',methods=['GET', 'POST'])
def bac():
request_json = request.get_json()
filename = request_json["filename"]
#url = request_json["url"]
#baseconnect.Baseconnect(url=url,filename=filename).run()
return filename
#The function to post on client side
import requests
req = requests.Session()
data = req.post('https://project.appspot.com/bac',json={"filename":"yuan"})
print(data.text)
#output:
yuan
Flask seems only accept single variable. What is the problem....
The problem you have here is that Flask only returns Response object, and Flask will consider return filename, url a shortcut of return Response, status or header.
In this case, url becomes the http status code or header, which is obviously not right.
You need flask.jsonify() to return the proper format of so called 'multiple variables'.
Something like this: (only the important part)
# In server-side code
from flask import jsonify
#app.route('/bac',methods=['GET', 'POST'])
def bac():
request_json = request.get_json()
filename = request_json["filename"]
url = request_json["url"]
# Do your logic here
return jsonify({ filename_returned: filename, url_returned: url })
# client-side
import requests
req = requests.Session()
json_data = req.post('https://project.appspot.com/bac',json={"filename":"yuan", "url": "http:xxxxxxx"})
real_data = json.loads(json_data)
# real_data should be the result you want

how to use web scraped data to webpage

I saw codes and I would like to try/implement it to a web page to put some datas. (you can see it on the image below)
[enter image description here][1]
import requests
from bs4 import BeautifulSoup
import time
def get_count():
url = "https://data-live.flightradar24.com/zones/fcgi/feed.js?bounds=59.09,52.64,-58.77,-47.71&faa=1&mlat=1&flarm=1&adsb=1&gnd=1&air=1&vehicles=1&estimated=1&maxage=7200&gliders=1&stats=1"
# Request with fake header, otherwise you will get an 403 HTTP error
r = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
# Parse the JSON
data = r.json()
counter = 0
# Iterate over the elements to get the number of total flights
for element in data["stats"]["total"]:
counter += data["stats"]["total"][element]
return counter
while True:
print(get_count())
time.sleep(8)
I am just starting to learn web scraping with beautiful soup.

Google App Engine - Error uploading file to blobstore from Python code

I am working on an app to process emails hitting my mailbox. I have modified my mail settings to forward incoming mails to myapp. The mails reaching myapp will be routed to the handler script ("handle_incoming_email.py") where it will be processed. My app.yaml file looks like this
app.yaml
application: myapp
version: 1-1
runtime: python27
api_version: 1
threadsafe: false
default_expiration: "360d"
handlers:
- url: /_ah/mail/.+
script: myapp/utils/handle_incoming_email.py
The mail handler script is given below
handle_incoming_email.py
import logging
import urllib
import base64
import traceback
from google.appengine.ext import webapp
from google.appengine.ext import blobstore
from google.appengine.api import urlfetch
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler
class ReceiveEmail(InboundMailHandler):
def receive(self, message):
try:
for filename, filecontents in message.attachments:
if filecontents.encoding:
# data = filecontents
data = filecontents.decode()
# data = filecontents.payload
# data = filecontents.payload.decode()
# data = base64.b64decode(filecontents.decode())
# data = base64.b64decode(filecontents.payload)
# data = base64.b64decode(filecontents.payload.decode())
upload_url = blobstore.create_upload_url('http://myapp.appspot.com/settings/saveItem/')
form_fields = {'field_name': data}
form_data = urllib.urlencode(form_fields)
result = urlfetch.fetch(url=upload_url,
payload=form_data,
method=urlfetch.POST,
headers={'Content-Type': 'application/x-www-form-urlencoded'})
logging.info(result)
except Exception, e:
traceback.print_exc()
application = webapp.WSGIApplication([ReceiveEmail.mapping()], debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
My requirement is to create an entity corresponding to each mail with attachment. For this, I need to parse the attachment from the mail and upload it to blobstore. However, when I try to upload the attachment to blobstore, I get the following error:
The request's content type is not accepted on this URL.
As you can see in the commented code in "handle_incoming_email.py", I tried different methods (trial-and-error) to get the data correct, but to no avail.
Could someone guide me in fixing this!
Thanks!!!
I think this code sample will solve you problem. You probably need to use only encode_multipart_formdata function from this code. And do not forget to set properly content type.
class BlobstoreUpload(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file')
blob_info = upload_files[0]
return self.response.write(blob_info.key())
#classmethod
def encode_multipart_formdata(cls, fields, files, mimetype='image/png'):
"""
Args:
fields: A sequence of (name, value) elements for regular form fields.
files: A sequence of (name, filename, value) elements for data to be
uploaded as files.
Returns:
A sequence of (content_type, body) ready for urlfetch.
"""
boundary = 'paLp12Buasdasd40tcxAp97curasdaSt40bqweastfarcUNIQUE_STRING'
crlf = '\r\n'
line = []
for (key, value) in fields:
line.append('--' + boundary)
line.append('Content-Disposition: form-data; name="%s"' % key)
line.append('')
line.append(value)
for (key, filename, value) in files:
line.append('--' + boundary)
line.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
line.append('Content-Type: %s' % mimetype)
line.append('')
line.append(value)
line.append('--%s--' % boundary)
line.append('')
body = crlf.join(line)
content_type = 'multipart/form-data; boundary=%s' % boundary
return content_type, body
class UserProfile(webapp2.RequestHandler):
def post(self):
picture = self.request.POST.get('picture')
# Write new picture to blob
content_type, body = BlobstoreUpload.encode_multipart_formdata(
[], [('file', name, image)])
response = urlfetch.fetch(
url=blobstore.create_upload_url(self.uri_for('blobstore-upload')),
payload=body,
method=urlfetch.POST,
headers={'Content-Type': content_type},
deadline=30
)
blob_key = response.content

Resources