{"componentChunkName":"component---src-templates-blog-js","path":"/blog/fullstack-sentiment-analysis-app-react-flask-tesseract","result":{"data":{"contentfulBlogPost":{"title":"Full-stack Sentiment Analysis Application with React, Flask and Tesseract","publishedDate":"January 12th, 2021","body":{"json":{"nodeType":"document","data":{},"content":[{"nodeType":"paragraph","content":[{"nodeType":"text","value":"Hello everyone, in this post I'll try to demonstrate a full-stack AI based web application with React frontend and Flask backend. Nearly all the frontend code for this project comes from ","marks":[],"data":{}},{"nodeType":"hyperlink","content":[{"nodeType":"text","value":"this","marks":[],"data":{}}],"data":{"uri":"https://github.com/stacksapien/react-tesseract-ocr"}},{"nodeType":"text","value":" repository so don't forget to go ahead and drop a star to the original OCR React code of the project. Actually as you can see the ","marks":[],"data":{}},{"nodeType":"hyperlink","content":[{"nodeType":"text","value":"final version","marks":[],"data":{}}],"data":{"uri":"https://github.com/eren23/react-tesseract-ocr"}},{"nodeType":"text","value":" of the project is also a fork of the React repo, I just added the backend and sentiment analysis, changed the folder structure and rebased the project. ","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"The ultimate goal of this project to show you that can use perfectly engineered developer friendly tools from the awesome community to tackle some truly hard problems in CS and you don't have to get your hands dirty if you don't want to basically.","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"I'll not explain the code line by line in this tutorial, instead I'll explain how each part works briefly and then you'll have a base image for creating similar image base sentiment analysis applications with the support of AI.","marks":[],"data":{}}],"data":{}},{"nodeType":"hr","content":[],"data":{}},{"nodeType":"heading-2","content":[{"nodeType":"text","value":"React and Tesseract","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"As I've explained above I'll not walk you through on the each step of the application, I'll however explain how you can get this code and make it run on your own local environment.","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"First we need to clone the repo, we can get it from the ","marks":[],"data":{}},{"nodeType":"hyperlink","content":[{"nodeType":"text","value":"final version","marks":[],"data":{}}],"data":{"uri":"https://github.com/eren23/react-tesseract-ocr"}},{"nodeType":"text","value":" link here ( same as above ) then we can either download the zip version or you can clone it via git.","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"After that folder structure should look like the one below.","marks":[],"data":{}}],"data":{}},{"nodeType":"embedded-asset-block","content":[],"data":{"target":{"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"qv0hcw26u3ts","contentful_id":"qv0hcw26u3ts"}},"id":"c4J5OtyA2qZ6nYqTP72f8Pu","type":"Asset","createdAt":"2021-01-12T19:31:34.547Z","updatedAt":"2021-01-12T19:31:34.547Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment","contentful_id":"master"}},"revision":1,"contentful_id":"4J5OtyA2qZ6nYqTP72f8Pu"},"fields":{"title":{"en-US":"sentiment-fs-folder-structure"},"file":{"en-US":{"url":"//images.ctfassets.net/qv0hcw26u3ts/4J5OtyA2qZ6nYqTP72f8Pu/22ab913fa34de6097a76aa080ee43f2c/Screen_Shot_2021-01-12_at_20.31.08.png","details":{"size":8209,"image":{"width":187,"height":57}},"fileName":"Screen Shot 2021-01-12 at 20.31.08.png","contentType":"image/png"}}}}}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"We should go ahead and install the npm packages first, for that we can go into \"react-tesseract-ocr\" folder and run the following commands:","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"npm install","marks":[{"type":"code"}],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"npm start","marks":[{"type":"code"}],"data":{}}],"data":{}},{"nodeType":"hr","content":[],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"After if everything works just fine we should see a page like that one below.","marks":[],"data":{}}],"data":{}},{"nodeType":"embedded-asset-block","content":[],"data":{"target":{"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"qv0hcw26u3ts","contentful_id":"qv0hcw26u3ts"}},"id":"c34yb4w02FXwWw7BGM7Q0Td","type":"Asset","createdAt":"2021-01-12T19:38:51.375Z","updatedAt":"2021-01-12T19:38:51.375Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment","contentful_id":"master"}},"revision":1,"contentful_id":"34yb4w02FXwWw7BGM7Q0Td"},"fields":{"title":{"en-US":"react-tesseract-plain"},"file":{"en-US":{"url":"//images.ctfassets.net/qv0hcw26u3ts/34yb4w02FXwWw7BGM7Q0Td/b96fc621745d80b62f696a0a202caa54/Screen_Shot_2021-01-12_at_20.13.20.png","details":{"size":195495,"image":{"width":1176,"height":365}},"fileName":"Screen Shot 2021-01-12 at 20.13.20.png","contentType":"image/png"}}}}}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"On this page actually we can run OCR(Optical Character Recognition) with the any image we would like to try. OCR is actually quite complicated as a concept and running such project from scratch is absolutely a nightmare ( at least if you don't have much experience just like me). The repo we forked is using Google's Tesseract library and that basically automates all the OCR process for us, actually a JS port of the original Tesseract.","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"The only place we'll change for the tutorial is this part below.","marks":[],"data":{}}],"data":{}},{"nodeType":"embedded-asset-block","content":[],"data":{"target":{"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"qv0hcw26u3ts","contentful_id":"qv0hcw26u3ts"}},"id":"FBfjSEkah3a2PVH7tSNsy","type":"Asset","createdAt":"2021-01-12T19:46:57.530Z","updatedAt":"2021-01-12T19:46:57.530Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment","contentful_id":"master"}},"revision":1,"contentful_id":"FBfjSEkah3a2PVH7tSNsy"},"fields":{"title":{"en-US":"react-tesseract-place-to-change"},"file":{"en-US":{"url":"//images.ctfassets.net/qv0hcw26u3ts/FBfjSEkah3a2PVH7tSNsy/8bf2c05304b7215273106dc828044ba5/Screen_Shot_2021-01-12_at_19.55.38.png","details":{"size":27759,"image":{"width":553,"height":169}},"fileName":"Screen Shot 2021-01-12 at 19.55.38.png","contentType":"image/png"}}}}}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":" This part is where the original author of the React project used to print extracted text from the picture. We replaced that part with a \"POST\" request to the given endpoint at port 8080 and added the extracted text into the body of the request basically.","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"From that point we can quickly move to our backend.","marks":[],"data":{}}],"data":{}},{"nodeType":"hr","content":[],"data":{}},{"nodeType":"heading-2","content":[{"nodeType":"text","value":"Flask and Naive Bayes","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"For the sake of simplicity I also moved over the part where we usually take the data and train the model. Usually that's should be the painful part of such a project and I'm not trying to deny this fact with my approach. In fact you can go ahead and train your own model by using the tutorial in the ","marks":[],"data":{}},{"nodeType":"hyperlink","content":[{"nodeType":"text","value":"link","marks":[],"data":{}}],"data":{"uri":"https://www.digitalocean.com/community/tutorials/how-to-perform-sentiment-analysis-in-python-3-using-the-natural-language-toolkit-nltk"}},{"nodeType":"text","value":". I personally did it that way in some time ago.","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"So in order to run the backend we have 2 dependencies installed in our Python environment, ","marks":[],"data":{}},{"nodeType":"hyperlink","content":[{"nodeType":"text","value":"nltk","marks":[],"data":{}}],"data":{"uri":"https://anaconda.org/anaconda/nltk"}},{"nodeType":"text","value":" and ","marks":[],"data":{}},{"nodeType":"hyperlink","content":[{"nodeType":"text","value":"Flask","marks":[],"data":{}}],"data":{"uri":"https://anaconda.org/anaconda/flask"}},{"nodeType":"text","value":" from the following links ( They are conda guides because I'm using Anaconda in my local environment, if you want to learn more about ","marks":[],"data":{}},{"nodeType":"hyperlink","content":[{"nodeType":"text","value":"Anaconda","marks":[],"data":{}}],"data":{"uri":"https://anaconda.org/"}},{"nodeType":"text","value":")","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"As you can see we have our model in the root directory of \"sentiment-backend\" folder. After we have all our dependencies running the server is quite easy. All we need to do is to run ","marks":[],"data":{}},{"nodeType":"text","value":"\"python server.py\" and our server should up and running.","marks":[{"type":"code"}],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"Our server.py file looks like this one below.","marks":[{"type":"code"}],"data":{}}],"data":{}},{"nodeType":"embedded-asset-block","content":[],"data":{"target":{"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"qv0hcw26u3ts","contentful_id":"qv0hcw26u3ts"}},"id":"c2sKDSvdyutjFtSY6LrPJ6S","type":"Asset","createdAt":"2021-01-12T20:14:41.211Z","updatedAt":"2021-01-12T20:14:41.211Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment","contentful_id":"master"}},"revision":1,"contentful_id":"2sKDSvdyutjFtSY6LrPJ6S"},"fields":{"title":{"en-US":"fullstack-sentiment-backend-code"},"file":{"en-US":{"url":"//images.ctfassets.net/qv0hcw26u3ts/2sKDSvdyutjFtSY6LrPJ6S/d0a502ebd69dc0f18dc7f34858f9c202/Screen_Shot_2021-01-12_at_19.56.05.png","details":{"size":67608,"image":{"width":546,"height":469}},"fileName":"Screen Shot 2021-01-12 at 19.56.05.png","contentType":"image/png"}}}}}},{"nodeType":"unordered-list","content":[{"nodeType":"list-item","content":[{"nodeType":"paragraph","content":[{"nodeType":"text","value":"First we pick up our model and create our classifier","marks":[],"data":{}}],"data":{}}],"data":{}},{"nodeType":"list-item","content":[{"nodeType":"paragraph","content":[{"nodeType":"text","value":"Then we initialize the Flask and the CORS. CORS stands for Cross-Origin resource sharing and we need that for sharing information between our Flask backend with React frontend. More about CORS ","marks":[],"data":{}},{"nodeType":"hyperlink","content":[{"nodeType":"text","value":"here","marks":[],"data":{}}],"data":{"uri":"https://developer.mozilla.org/tr/docs/Web/HTTP/CORS"}},{"nodeType":"text","value":".","marks":[],"data":{}}],"data":{}}],"data":{}}],"data":{}},{"nodeType":"hr","content":[],"data":{}},{"nodeType":"heading-2","content":[{"nodeType":"text","value":"Testing Our System","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"I added 1 positive and 1 negative text containing images in the Frontend directory. We can simply go ahead and select one of them from the UI now.","marks":[],"data":{}}],"data":{}},{"nodeType":"embedded-asset-block","content":[],"data":{"target":{"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"qv0hcw26u3ts","contentful_id":"qv0hcw26u3ts"}},"id":"I90cMpHUo79UBK5TpcsGX","type":"Asset","createdAt":"2021-01-12T20:32:11.428Z","updatedAt":"2021-01-12T20:32:11.428Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment","contentful_id":"master"}},"revision":1,"contentful_id":"I90cMpHUo79UBK5TpcsGX"},"fields":{"title":{"en-US":"react-ocr-file-upload"},"file":{"en-US":{"url":"//images.ctfassets.net/qv0hcw26u3ts/I90cMpHUo79UBK5TpcsGX/5629bccb678c6e9217442ff540728016/Screen_Shot_2021-01-12_at_19.45.30.png","details":{"size":209170,"image":{"width":803,"height":450}},"fileName":"Screen Shot 2021-01-12 at 19.45.30.png","contentType":"image/png"}}}}}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"After we select our image to apply OCR and then sentiment analysis, our React app automatically start to do the OCR, after everything is resolved if our system can provide a meaningful text we can receive a response from the server.","marks":[],"data":{}}],"data":{}},{"nodeType":"embedded-asset-block","content":[],"data":{"target":{"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"qv0hcw26u3ts","contentful_id":"qv0hcw26u3ts"}},"id":"c3WXcMm5s3S9eklHBj1JJ4V","type":"Asset","createdAt":"2021-01-12T20:34:19.080Z","updatedAt":"2021-01-12T20:34:19.080Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment","contentful_id":"master"}},"revision":1,"contentful_id":"3WXcMm5s3S9eklHBj1JJ4V"},"fields":{"title":{"en-US":"ocr-positive"},"file":{"en-US":{"url":"//images.ctfassets.net/qv0hcw26u3ts/3WXcMm5s3S9eklHBj1JJ4V/ef796a95dc3d8b38ac8dc9fc80e9f6db/Screen_Shot_2021-01-12_at_19.46.04.png","details":{"size":631845,"image":{"width":1916,"height":664}},"fileName":"Screen Shot 2021-01-12 at 19.46.04.png","contentType":"image/png"}}}}}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"As we can see below our system can understand that our image contains a positive text. Now let's try a bad one.","marks":[],"data":{}}],"data":{}},{"nodeType":"embedded-asset-block","content":[],"data":{"target":{"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"qv0hcw26u3ts","contentful_id":"qv0hcw26u3ts"}},"id":"c6WEPmFGdSS16d5MVg2obYX","type":"Asset","createdAt":"2021-01-12T20:35:26.985Z","updatedAt":"2021-01-12T20:35:26.985Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment","contentful_id":"master"}},"revision":1,"contentful_id":"6WEPmFGdSS16d5MVg2obYX"},"fields":{"title":{"en-US":"ocr-negative"},"file":{"en-US":{"url":"//images.ctfassets.net/qv0hcw26u3ts/6WEPmFGdSS16d5MVg2obYX/c516e854334a452e0f564165830a6b12/Screen_Shot_2021-01-12_at_19.46.49.png","details":{"size":608149,"image":{"width":1916,"height":633}},"fileName":"Screen Shot 2021-01-12 at 19.46.49.png","contentType":"image/png"}}}}}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"It says it's negative and I agree. I mean I might suck but not this model so far :P.","marks":[],"data":{}}],"data":{}},{"nodeType":"hr","content":[],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"That's it everyone, I hope that this tutorial is helpful to you, I really believe it will be very useful for many people this time.","marks":[],"data":{}}],"data":{}},{"nodeType":"paragraph","content":[{"nodeType":"text","value":"Until next time, take care. :)","marks":[],"data":{}}],"data":{}}]}}}},"pageContext":{"slug":"fullstack-sentiment-analysis-app-react-flask-tesseract"}}}