diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e47435..0eeca55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.9] + +### Added + +- Faster and more reliable thanks to switching to an async based server with Quart. +- Added json responses on server with built-in responses that would be translated to other languages. When requesting to the API, it returns the same text and status code on chrome, firefox and android/ios platforms. +- Updated app to work with these changes. +- When clicking on the message box, you can go to the url of the added content and see it. + +### Fixed + +- Refactored code, made it easier for example to implement in the near future a way to translate to different languages, and removed unused code. +- No message was shown when trying to add something witouth having entered credentials. + ## [1.8] ### Added diff --git a/Chrome Extension/js/background.js b/Chrome Extension/js/background.js index b8a597c..7d96552 100644 --- a/Chrome Extension/js/background.js +++ b/Chrome Extension/js/background.js @@ -67,12 +67,11 @@ async function AddUrlToMind(tab) { var url = tab.url; var title = tab.title; const urlParams = `add_url_to_mind?url=${url}&title=${title}`; - req.open("GET", baseUrl+urlParams, true); req.onreadystatechange = function() { // Call a function when the state changes. if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { - switchResponse(this.responseText); + parseAndSwitchResponse(this.responseText); } else if (this.status === 0) { switchResponse("-1"); } @@ -97,7 +96,7 @@ async function AddTextToMind(info,tab) { req.onreadystatechange = function() { // Call a function when the state changes. if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { - switchResponse(this.responseText); + parseAndSwitchResponse(this.responseText); } else if (this.status === 0) { switchResponse("-1"); } @@ -135,13 +134,13 @@ async function ProcessSelection(info,tab) { default: break; } - + alert(baseUrl+urlParams); req.open("GET", baseUrl+urlParams, true); req.send(); req.onreadystatechange = function() { // Call a function when the state changes. if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { - switchResponse(this.responseText); + parseAndSwitchResponse(this.responseText); } else if (this.status === 0) { switchResponse("-1"); } @@ -151,31 +150,31 @@ async function ProcessSelection(info,tab) { } } +function parseAndSwitchResponse(response_from_api){ + var myObj = JSON.parse(response_from_api); + switchResponse(String(myObj['status_code']), String(myObj['block_url']),String(myObj['status_text']),String(myObj['text_response'])); +} -function switchResponse(response){ - switch (response) { - case '200': - createHandler( - () => - showNotification({ - message: "Added to your mind.", - status: "success", - redirect: "http://www.laguiaempresarial.com/item/10731/", - }) - ); - break; - case '-1': - createHandler( - () => - showNotification({ - message: "Error during accessing server. Make sure the ip/port are corrects, and the server is running.", - status: "error", - redirect: "http://www.laguiaempresarial.com/item/10731/", - }) - ); - break; - default: - break; +function switchResponse(status_code,block_url,status_text,text_response) +{ + if (status_code == '-1'){ + createHandler( + () => + showNotification({ + message: "Error during accessing server. Make sure the ip/port are corrects, and the server is running.", + status: "error", + redirect: "https://github.com/elblogbruno/NotionAI-MyMind#love-to-try-it", + }) + ); + }else{ + createHandler( + () => + showNotification({ + message: text_response, + status: status_text, + redirect: block_url, + }) + ); } } @@ -207,6 +206,10 @@ chrome.cookies.onChanged.addListener(function(info) } }); +chrome.runtime.onMessage.addListener(function(request, sender) { + openNewTab(request.redirect); +}); + // undefined function createHandler(callback) { chrome.tabs.insertCSS({ @@ -270,6 +273,25 @@ function isEmpty(str) { return (!str || 0 === str.length); } +async function GetMindUrl(){ + const req = new XMLHttpRequest(); + // var mainUrl = getServerUrl(); + let permission = await getFromStorage("serverIP"); + if(!isEmpty(permission)){ + const baseUrl = permission; + const urlParams = `get_current_mind_url`; + + req.open("GET", baseUrl+urlParams, true); + + req.onreadystatechange = function() { // Call a function when the state changes. + if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { + return this.responseText; + } + } + req.send(); + } +} + async function openMindUrl(){ const req = new XMLHttpRequest(); // var mainUrl = getServerUrl(); diff --git a/Chrome Extension/js/notificationBehaviour.js b/Chrome Extension/js/notificationBehaviour.js index aa3a83f..971c76b 100644 --- a/Chrome Extension/js/notificationBehaviour.js +++ b/Chrome Extension/js/notificationBehaviour.js @@ -1,13 +1,9 @@ (() => { const usePromise = typeof browser !== "undefined"; - const { id, icon, item, message, status, redirect } = window.naimm; + const { id, icon, message, status, redirect } = window.naimm; const events = {}; - const tags = []; - const tagCache = {}; - - let previousValue = ""; const createListener = (id, target, name, callback) => { events[id] = { @@ -44,7 +40,7 @@ createListener("click", notificationInner, "click", event => { if (redirect && redirect !== "undefined") { - chrome.runtime.sendMessage({ openTab: redirect }); + chrome.runtime.sendMessage({redirect: redirect}); } createRemovalTimeout(0, true); diff --git a/Chrome Extension/manifest.json b/Chrome Extension/manifest.json index ad1f7c3..d212bc7 100644 --- a/Chrome Extension/manifest.json +++ b/Chrome Extension/manifest.json @@ -3,7 +3,7 @@ "name": "Notion AI My Mind", "description": "This extension allows to click to add any image or website to your MIND in notion, and forget about everything else.", - "version": "1.0.6", + "version": "1.0.7", "browser_action": { "default_icon": "icon/icon.png", diff --git a/Firefox Extension/js/background.js b/Firefox Extension/js/background.js index b4c837c..461e248 100644 --- a/Firefox Extension/js/background.js +++ b/Firefox Extension/js/background.js @@ -72,7 +72,7 @@ async function AddUrlToMind(tab) { req.onreadystatechange = function() { // Call a function when the state changes. if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { - switchResponse(this.responseText); + parseAndSwitchResponse(this.responseText); } else if (this.status === 0) { switchResponse("-1"); } @@ -97,7 +97,7 @@ async function AddTextToMind(info,tab) { req.onreadystatechange = function() { // Call a function when the state changes. if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { - switchResponse(this.responseText); + parseAndSwitchResponse(this.responseText); } else if (this.status === 0) { switchResponse("-1"); } @@ -141,7 +141,7 @@ async function ProcessSelection(info,tab) { req.onreadystatechange = function() { // Call a function when the state changes. if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { - switchResponse(this.responseText); + parseAndSwitchResponse(this.responseText); } else if (this.status === 0) { switchResponse("-1"); } @@ -152,34 +152,36 @@ async function ProcessSelection(info,tab) { } -function switchResponse(response){ - switch (response) { - case '200': - createHandler( - () => - showNotification({ - message: "Added to your mind.", - status: "success", - redirect: "http://www.laguiaempresarial.com/item/10731/", - }) - ); - break; - case '-1': - createHandler( - () => - showNotification({ - message: "Error during accessing server. Make sure the ip/port are corrects, and the server is running.", - status: "error", - redirect: "http://www.laguiaempresarial.com/item/10731/", - }) - ); - break; - default: - break; +function parseAndSwitchResponse(response_from_api){ + var myObj = JSON.parse(response_from_api); + switchResponse(String(myObj['status_code']), String(myObj['block_url']),String(myObj['status_text']),String(myObj['text_response'])); +} + +function switchResponse(status_code,block_url,status_text,text_response) +{ + if (status_code == '-1'){ + createHandler( + () => + showNotification({ + message: "Error during accessing server. Make sure the ip/port are corrects, and the server is running.", + status: "error", + redirect: "https://github.com/elblogbruno/NotionAI-MyMind#love-to-try-it", + }) + ); + }else{ + createHandler( + () => + showNotification({ + message: text_response, + status: status_text, + redirect: block_url, + }) + ); } } + browser.cookies.onChanged.addListener(function(info) { if(info['cookie']['domain'] == ".notion.so" && info['cookie']['name'] == "token_v2") @@ -207,6 +209,10 @@ browser.cookies.onChanged.addListener(function(info) } }); +browser.runtime.onMessage.addListener(function(request, sender) { + openNewTab(request.redirect); +}); + // undefined function createHandler(callback) { browser.tabs.insertCSS({ diff --git a/Firefox Extension/js/notificationBehaviour.js b/Firefox Extension/js/notificationBehaviour.js index aa3a83f..fa0e365 100644 --- a/Firefox Extension/js/notificationBehaviour.js +++ b/Firefox Extension/js/notificationBehaviour.js @@ -1,13 +1,9 @@ (() => { const usePromise = typeof browser !== "undefined"; - const { id, icon, item, message, status, redirect } = window.naimm; + const { id, icon, message, status, redirect } = window.naimm; const events = {}; - const tags = []; - const tagCache = {}; - - let previousValue = ""; const createListener = (id, target, name, callback) => { events[id] = { @@ -44,7 +40,7 @@ createListener("click", notificationInner, "click", event => { if (redirect && redirect !== "undefined") { - chrome.runtime.sendMessage({ openTab: redirect }); + chrome.runtime.sendMessage({redirect: redirect}); } createRemovalTimeout(0, true); diff --git a/Firefox Extension/manifest.json b/Firefox Extension/manifest.json index 8dfa4c1..013d96a 100644 --- a/Firefox Extension/manifest.json +++ b/Firefox Extension/manifest.json @@ -3,7 +3,7 @@ "name": "Notion AI My Mind", "description": "This extension allows to click to add any image or website to your MIND in notion, and forget about everything else.", - "version": "1.0.6", + "version": "1.0.7", "browser_action": { "default_icon": "icon/icon.png", diff --git a/Python Server/app/NotionAI.py b/Python Server/app/NotionAI.py index 2647344..18b5285 100644 --- a/Python Server/app/NotionAI.py +++ b/Python Server/app/NotionAI.py @@ -9,9 +9,10 @@ import requests import json -import threading +from threading import Thread from image_tagging.image_tagging import ImageTagging +from lang_utils import get_response_text class NotionAI: @@ -51,7 +52,9 @@ def run(self, logging, email=None, password=None): return self.token_v2 = token_v2 + print("Token V2: " + str(token_v2)) + mind_page = self.client.get_block(data['url']) self.mind_id = mind_page.id @@ -72,73 +75,77 @@ def add_url_to_database(self, url, title): self.statusCode = 200 # at start we asume everything will go ok try: rowId = self.web_clipper_request(url, title) - self.add_url_thread(rowId) + + thread = Thread(target=self.add_url_thread, args=(rowId,)) + thread.daemon = True # Daemonize thread + thread.start() # Start the execution + + return self.create_json_response(rowId=rowId) + except OnUrlNotValid as invalidUrl: - print(invalidUrl) self.logging.info(invalidUrl) self.statusCode = 500 + return self.create_json_response() + except AttributeError as e: + self.logging.info(e) + print(e) + self.statusCode = 404 + return self.create_json_response() def add_text_to_database(self, text, url): self.logging.info("Adding text to mind: {0} {1}".format(url.encode('utf8'), text.encode('utf8'))) self.statusCode = 200 # at start we asume everything will go ok - row = self.collection.add_row() - self.row = row try: if url == "" or text == "": - self.statusCode = 409 + self.statusCode = 500 + return self.create_json_response() else: - row.name = "Extract from " + url - text_block = row.children.add_new(TextBlock) - text_block.title = text - row.person = self.client.current_user - row.url = url - except requests.exceptions.HTTPError as invalidUrl: - print(invalidUrl) - self.logging.info(invalidUrl) - self.statusCode = 500 - def add_image_to_database(self, url, image_src, image_src_url): - self.logging.info("Adding image to mind: {0} {1} {2}".format(url.encode('utf8'), image_src.encode('utf8'), - image_src_url.encode('utf8'))) - self.statusCode = 200 # at start we asume everything will go ok - row = self.collection.add_row() - self.row = row - try: - row.name = "Image from " + image_src_url - row.url = image_src_url - img_block = row.children.add_new(ImageBlock) - img_block.source = image_src - row.icon = img_block.source - row.person = self.client.current_user - self.analyze_image_thread(image_src, row, image_src_url) - # x = threading.Thread(target=self.analyze_image_thread, args=(image_src, row, image_src_url)) - # x.start() + thread = Thread(target=self.add_text_thread, args=(url, text,)) + thread.daemon = True # Daemonize thread + thread.start() # Start the execution + return self.create_json_response() except requests.exceptions.HTTPError as invalidUrl: print(invalidUrl) self.logging.info(invalidUrl) self.statusCode = 500 - def add_image_to_database_by_post(self, image_src): - self.logging.info("Adding image to mind by post: {0}".format(image_src.encode('utf8'))) + return self.statusCode + except AttributeError as e: + self.logging.info(e) + print(e) + self.statusCode = 404 + return self.create_json_response() + + def add_image_to_database(self, image_src, url=None, image_src_url=None): + is_local = image_src_url is None and url is None + + if is_local: + self.logging.info("Adding image to mind: {0}".format(image_src.encode('utf8'))) + else: + self.logging.info("Adding image to mind: {0} {1} {2}".format(url.encode('utf8'), image_src.encode('utf8'), + image_src_url.encode('utf8'))) + self.statusCode = 200 # at start we asume everything will go ok - row = self.collection.add_row() - self.row = row try: - row.name = "Image from " + image_src - row.url = image_src - img_block = row.children.add_new(ImageBlock) - img_block.upload_file(image_src) - row.icon = img_block.source - row.person = self.client.current_user - x = threading.Thread(target=self.analyze_image_thread, args=(image_src, row, True)) - x.start() + thread = Thread(target=self.add_image_thread, args=(image_src, url, image_src_url, is_local,)) + thread.daemon = True # Daemonize thread + thread.start() # Start the execution + + return self.create_json_response() + except requests.exceptions.HTTPError as invalidUrl: - print(invalidUrl) self.logging.info(invalidUrl) self.statusCode = 500 + return self.create_json_response() + except AttributeError as e: + self.logging.info(e) + print(e) + self.statusCode = 404 + return self.create_json_response() def row_callback(self, record, difference): if len(self.row.AITagsText) == 0: @@ -149,7 +156,7 @@ def row_callback(self, record, difference): img_url = self.extract_image_from_content(self.page_content) try: self.row.remove_callbacks(self.row_callback) - self.add_tags_to_row(img_url,False) + self.add_tags_to_row(img_url, False) except NoTagsFound as e: print(e) self.logging.info(e) @@ -170,7 +177,7 @@ def row_callback(self, record, difference): print("This row is added already") def add_url_thread(self, rowId): - self.logging.info("Thread %s: starting", rowId) + self.logging.info("Thread adding url %s: starting", rowId) self.page_content = None self.row = self.client.get_block(rowId) @@ -181,9 +188,47 @@ def add_url_thread(self, rowId): self.logging.info("Thread %s: finishing", rowId) - def add_tags_to_row(self, img_url,is_image_local): + def add_text_thread(self, url, text): + row = self.collection.add_row() + self.row = row + + self.logging.info("Add text Thread %s: starting", row.id) + + row.name = "Extract from " + url + + text_block = row.children.add_new(TextBlock) + text_block.title = text + + row.person = self.client.current_user + row.url = url + self.logging.info("Add text Thread %s: finished", row.id) + + def add_image_thread(self, image_src, url=None, image_src_url=None, is_local=False): + row = self.collection.add_row() + + self.row = row + + self.logging.info("Image add Thread %s: starting", row.id) + + img_block = row.children.add_new(ImageBlock) + + if is_local: + img_block.upload_file(image_src) + row.name = "Image from phone" + + else: + img_block.source = image_src + row.name = "Image from " + str(image_src_url) + row.url = url + + row.icon = img_block.source + row.person = self.client.current_user + + self.analyze_image_thread(image_src, row, is_image_local=is_local) + + def add_tags_to_row(self, img_url, is_image_local): self.logging.info("Adding tags to image {0}".format(img_url)) - tags = self.image_tagger.get_tags(img_url,is_image_local) + tags = self.image_tagger.get_tags(img_url, is_image_local) self.logging.info("Tags from image {0} : {1}".format(img_url, tags)) self.row.AITagsText = tags @@ -238,9 +283,8 @@ def web_clipper_request(self, url, title): else: raise OnUrlNotValid("Invalid url was sent", self) - def analyze_image_thread(self, image_src, row, is_image_local=False, image_src_url="no context"): + def analyze_image_thread(self, image_src, row, is_image_local=False): try: - self.logging.info("Image tag Thread %s: starting", row.id) self.add_tags_to_row(image_src, is_image_local) self.logging.info("Image tag Thread %s: finished", row.id) except NoTagsFound as e: @@ -258,3 +302,28 @@ def analyze_image_thread(self, image_src, row, is_image_local=False, image_src_u except EmbedableContentNotFound as e: print(e) self.logging.info(e) + + def create_json_response(self, status_code=None, rowId=None): + url = "https://github.com/elblogbruno/NotionAI-MyMind#love-to-try-it" + + if status_code is None: + status_code = self.statusCode + + if rowId is not None: + rowIdExtracted = rowId.split("-") + str1 = ''.join(str(e) for e in rowIdExtracted) + url = "https://www.notion.so/" + str1 + + text_response, status_text = get_response_text(status_code) + + x = { + "status_code": status_code, + "text_response": text_response, + "status_text": status_text, + "block_url": url + } + + # convert into JSON: + json_response = json.dumps(x) + + return json_response diff --git a/Python Server/app/custom_errors.py b/Python Server/app/custom_errors.py index 050137c..e467f4c 100644 --- a/Python Server/app/custom_errors.py +++ b/Python Server/app/custom_errors.py @@ -4,8 +4,8 @@ def __init__(self, *args): self.message = args[0] else: self.message = None - args[1].imageStatusCode = 409 - + #args[1].imageStatusCode = 409 + args[1].statusCode = 200 def __str__(self): if self.message: return 'OnImageNotFound, {0} '.format(self.message) @@ -19,7 +19,7 @@ def __init__(self, *args): self.message = args[0] else: self.message = None - args[1].imageStatusCode = 500 + args[1].statusCode = 500 def __str__(self): if self.message: diff --git a/Python Server/app/image_tagging/image_tagging.py b/Python Server/app/image_tagging/image_tagging.py index 27f7093..142c6e6 100644 --- a/Python Server/app/image_tagging/image_tagging.py +++ b/Python Server/app/image_tagging/image_tagging.py @@ -5,7 +5,7 @@ class ImageTagging: - def __init__(self,data,logging): + def __init__(self, data, logging): options = {} with open('options.json') as json_file: options = json.load(json_file) @@ -16,17 +16,19 @@ def __init__(self,data,logging): logging.info("Using clarifai predictor") else: self.predictor = TensorFlowTag(options['delete_after_tagging']) - logging.info("Using tensorflow predictor, with delete_after_tagging = {}".format(options['delete_after_tagging'])) + logging.info("Using tensorflow predictor, with delete_after_tagging = {}".format( + options['delete_after_tagging'])) except FileNotFoundError: logging.info("options.json not found") print("Wrong file or file path") - def get_tags(self, image_url,is_image_local): + def get_tags(self, image_url, is_image_local): self.print_current_detector() - return self.predictor.get_tags(image_url,is_image_local) + return self.predictor.get_tags(image_url, is_image_local) def print_current_detector(self): if self.options['use_clarifai']: print("Using clarifai predictor") else: - print("Using tensorflow predictor, with delete_after_tagging = {}".format(self.options['delete_after_tagging'])) \ No newline at end of file + print("Using tensorflow predictor, with delete_after_tagging = {}".format( + self.options['delete_after_tagging'])) diff --git a/Python Server/app/image_tagging/tensorflow_tagging/tensorflow_tagging.py b/Python Server/app/image_tagging/tensorflow_tagging/tensorflow_tagging.py index 0ba89ed..0b4677e 100644 --- a/Python Server/app/image_tagging/tensorflow_tagging/tensorflow_tagging.py +++ b/Python Server/app/image_tagging/tensorflow_tagging/tensorflow_tagging.py @@ -14,12 +14,10 @@ class TensorFlowTag: def __init__(self, delete_image_after_tagging=True): self.delete_after_tagging = delete_image_after_tagging - + self.model = InceptionV3(weights='imagenet') createFolder("./image_tagging/temp_image_folder") def get_tags(self, image_url, is_local_image): - model = InceptionV3(weights='imagenet') - if is_local_image: file = "./uploads/"+image_url.split("/")[-1] else: @@ -30,14 +28,15 @@ def get_tags(self, image_url, is_local_image): x = np.expand_dims(x, axis=0) x = preprocess_input(x) - preds = model.predict(x) - prediction_decoded = decode_predictions(preds, top=5)[0] + preds = self.model.predict(x) + prediction_decoded = decode_predictions(preds, top=20)[0] print('Predicted:', prediction_decoded) tags = [] for element in prediction_decoded: - tags.append(element[1]) + if element[2] > 0.20: + tags.append(element[1]) if self.delete_after_tagging: os.remove(file) diff --git a/Python Server/app/lang_utils.py b/Python Server/app/lang_utils.py index e69de29..d521236 100644 --- a/Python Server/app/lang_utils.py +++ b/Python Server/app/lang_utils.py @@ -0,0 +1,9 @@ +def get_response_text(status_code): + print("Sending response {}".format(status_code)) + + if status_code == 200: + return "Added to your mind.", "success" + elif status_code == 404: + return "No Notion credentials where provided. Please add them on the server.", "error" + else: + return "Invalid url or text was provided.", "error" diff --git a/Python Server/app/requirements.txt b/Python Server/app/requirements.txt index fbba15c..b4eadf4 100644 --- a/Python Server/app/requirements.txt +++ b/Python Server/app/requirements.txt @@ -2,13 +2,14 @@ flask==1.1.2 gunicorn==20.0.4 clarifai-grpc==6.7.1 -Flask==1.1.2 notion==0.0.28 requests==2.24.0 urllib3==1.25.10 validators==0.17.1 Werkzeug==1.0.1 -tensorflow +tensorflow~=2.3.1 keras Pillow -pillow \ No newline at end of file +pillow +Quart~=0.14.1 +numpy~=1.18.5 \ No newline at end of file diff --git a/Python Server/app/server.py b/Python Server/app/server.py index ecb4d00..c9c4da0 100644 --- a/Python Server/app/server.py +++ b/Python Server/app/server.py @@ -1,23 +1,18 @@ -import os import logging -from flask import send_from_directory -from flask import render_template -from flask import Flask, flash, request, redirect, url_for +from quart import Quart, render_template, flash, request, redirect from werkzeug.utils import secure_filename -import json import secrets -from utils import ask_server_port, save_options, save_data, append_data, createFolder +from utils import ask_server_port, save_options, save_data, createFolder from NotionAI import * -from threading import Thread - UPLOAD_FOLDER = '../app/uploads/' -ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif']) +ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif','webp']) + +app = Quart(__name__) -app = Flask(__name__) app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER logging.basicConfig(filename='app.log', filemode='w', format='%(name)s - %(levelname)s - %(message)s', level=logging.INFO) @@ -26,45 +21,25 @@ @app.route('/add_url_to_mind') -def add_url_to_mind(): +async def add_url_to_mind(): url = request.args.get('url') title = request.args.get('title') - thread = Thread(target=notion.add_url_to_database, args=(url, title)) - thread.daemon = True - thread.start() - return "200" + return str(notion.add_url_to_database(url, title)) @app.route('/add_text_to_mind') -def add_text_to_mind(): +async def add_text_to_mind(): url = request.args.get('url') text = request.args.get('text') - thread = Thread(target=notion.add_text_to_database, args=(str(text), str(url))) - thread.daemon = True - thread.start() - return "200" + return str(notion.add_text_to_database(text, url)) @app.route('/add_image_to_mind') -def add_image_to_mind(): +async def add_image_to_mind(): url = request.args.get('url') image_src = request.args.get('image_src') image_src_url = request.args.get('image_src_url') - thread = Thread(target=notion.add_image_to_database, args=(str(url), str(image_src), str(image_src_url))) - thread.daemon = True - thread.start() - return "200" - - -@app.route('/add_video_to_mind') -def add_video_to_mind(): - url = request.args.get('url') - video_src = request.args.get('video_src') - video_src_url = request.args.get('video_src_url') - - # notion.add_text_to_database(str(url),str(text)) - # print(str(notion.statusCode)) - return str(notion.statusCode) + return str(notion.add_image_to_database(url, image_src, image_src_url)) def allowed_file(filename): @@ -72,55 +47,41 @@ def allowed_file(filename): filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS -@app.route('/upload_file', methods=['GET', 'POST']) -def upload_file(): +@app.route('/upload_file', methods=['POST']) +async def upload_file(): createFolder("uploads") - if request.method == 'POST': - # check if the post request has the file part - if 'file' not in request.files: - flash('No file part') - return redirect(request.url) - file = request.files['file'] - # if user does not select file, browser also - # submit an empty part without filename - if file.filename == '': - flash('No selected file') - return redirect(request.url) - if file and allowed_file(file.filename): - filename = secure_filename(file.filename) - file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) - uri = os.path.join(app.config['UPLOAD_FOLDER'], filename) - - thread = Thread(target=notion.add_image_to_database_by_post,args=(uri,)) - thread.daemon = True - thread.start() - # notion.add_image_to_database_by_post(os.path.join(app.config['UPLOAD_FOLDER'], filename)) - return "File Uploaded Succesfully" - - -@app.route('/add_audio_to_mind') -def add_audio_to_mind(): - url = request.args.get('url') - audio_src = request.args.get('audio_src') - audio_src_url = request.args.get('audio_src_url') - - # notion.add_text_to_database(str(url),str(text)) - # print(str(notion.statusCode)) - return str(notion.statusCode) + status_code = 200 + # check if the post request has the file part + request_files = await request.files + + if 'file' not in request_files: + flash('No file part') + status_code = 500 + + file = request_files['file'] + # if user does not select file, browser also + # submit an empty part without filename + if file.filename == '': + flash('No selected file') + status_code = 500 + if file and allowed_file(file.filename): + filename = secure_filename(file.filename) + file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) + uri = os.path.join(app.config['UPLOAD_FOLDER'], filename) + return str(notion.add_image_to_database(uri)) + else: + print("This file is not allowed to be post") + status_code = 500 + return str(notion.create_json_response(status_code=status_code)) @app.route('/get_current_mind_url') -def get_current_mind_url(): +async def get_current_mind_url(): return str(notion.data['url']) -@app.route('/get_notion_token_v2') -def get_notion_token_v2(): - return str(notion.data['token']) - - @app.route('/update_notion_tokenv2') -def update_notion_tokenv2(): +async def update_notion_tokenv2(): token_from_extension = request.args.get('tokenv2') changed = False with open('data.json') as json_file: @@ -145,38 +106,44 @@ def update_notion_tokenv2(): @app.route('/') -def show_settings_home_menu(): - return render_template("options.html") +async def show_settings_home_menu(): + return await render_template("options.html") @app.route('/handle_data', methods=['POST']) -def handle_data(): - notion_url = request.form['notion_url'] - notion_token = request.form['notion_token'] +async def handle_data(): + data = await request.get_json() + print(data) + notion_url = data['notion_url'] + + notion_token = data['notion_token'] - use_email = request.form['email'] and request.form['password'] + use_email = data['email'] and data['password'] - if request.form['clarifai_key']: - clarifai_key = request.form['clarifai_key'] + if data['clarifai_key']: + clarifai_key = data['clarifai_key'] save_data(logging, url=notion_url, token=notion_token, clarifai_key=clarifai_key) use_clarifai = True else: save_data(logging, url=notion_url, token=notion_token) use_clarifai = False - delete_after_tagging = request.form.getlist('delete_after_tagging') + if "delete_after_tagging" in data: + delete_after_tagging = data['delete_after_tagging'] + else: + delete_after_tagging = False save_options(logging, use_clarifai=use_clarifai, delete_after_tagging=delete_after_tagging) if use_email: - has_run = notion.run(logging, email=request.form['email'], password=request.form['password']) + has_run = notion.run(logging, email=data['email'], password=data['password']) else: has_run = notion.run(logging) if has_run: - return render_template("thank_you.html") + return "200" else: - return render_template("error.html") + return "500" if __name__ == "__main__": diff --git a/Python Server/app/static/error.html b/Python Server/app/static/error.html index 32f0ec8..04d3d13 100644 --- a/Python Server/app/static/error.html +++ b/Python Server/app/static/error.html @@ -21,7 +21,7 @@

Error!

Having trouble? Post an issue on github

- Go back to settings + Go back to settings

Continue to repo's homepage diff --git a/Python Server/app/static/thank_you.html b/Python Server/app/static/thank_you.html index 88178e0..ec6c727 100644 --- a/Python Server/app/static/thank_you.html +++ b/Python Server/app/static/thank_you.html @@ -21,7 +21,7 @@

Thank You!

Having trouble? Post an issue on github

- Go back to settings + Go back to settings

Continue to repo's homepage diff --git a/Python Server/app/templates/options.html b/Python Server/app/templates/options.html index 9cfaad9..24ea862 100644 --- a/Python Server/app/templates/options.html +++ b/Python Server/app/templates/options.html @@ -48,7 +48,7 @@

Image tagging options:

- + @@ -92,13 +92,12 @@

Image tagging options:

// Should be 'OK' if everything was successful console.log(text); - console.log({{ url_for('static',filename='thank_you.html') }}); if (text == "200") { - window.location.href = url_for('thank_you.html'); + window.location.href = '{{ url_for('static',filename='thank_you.html') }}'; }else{ - window.location.href = url_for('error.html'); + window.location.href = '{{ url_for('static',filename='error.html') }}'; } }); } diff --git a/Python Server/app/utils.py b/Python Server/app/utils.py index 88f7673..f2b0a85 100644 --- a/Python Server/app/utils.py +++ b/Python Server/app/utils.py @@ -90,6 +90,7 @@ def append_data(logging, **kwargs): def download_image_from_url(image_url): + print("Downloading this {} image".format(image_url)) filename = "./image_tagging/temp_image_folder/" + str(uuid.uuid4()) # Open the url image, set stream to True, this will return the stream content. diff --git a/flutter-android-ios-app/notion_ai_my_mind/lib/api/api.dart b/flutter-android-ios-app/notion_ai_my_mind/lib/api/api.dart index f10579b..5379a72 100644 --- a/flutter-android-ios-app/notion_ai_my_mind/lib/api/api.dart +++ b/flutter-android-ios-app/notion_ai_my_mind/lib/api/api.dart @@ -1,7 +1,10 @@ import 'dart:convert'; +import 'package:flutter/cupertino.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:http/http.dart' as http; +import 'package:notion_ai_my_mind/api/apiresponse.dart'; +import 'package:notion_ai_my_mind/resources/strings.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:path/path.dart'; import 'package:async/async.dart'; @@ -29,7 +32,7 @@ class Api { } } - Future addUrlToMind(String urlToAdd) async { + Future addUrlToMind(String urlToAdd) async { try { RegExp exp = new RegExp(r'(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-?=%.]+'); Iterable matches = exp.allMatches(urlToAdd); @@ -46,9 +49,9 @@ class Api { http.Response response = await http.get(finalUrl); if (response.statusCode == 200) { - return '200'; + return parseResponse(response.body); } else { - return '-1'; + return createBadResponse(); } } else if(urlToAdd == matches.first.group(0)) { @@ -65,9 +68,9 @@ class Api { if (response.statusCode == 200) { - return '200'; + return parseResponse(response.body); } else { - return '-1'; + return createBadResponse(); } }else{ print(matches.first.group(0)); @@ -82,9 +85,9 @@ class Api { http.Response response = await http.get(finalUrl); if (response.statusCode == 200) { - return '200'; + return parseResponse(response.body); } else { - return '-1'; + return createBadResponse(); } } @@ -96,7 +99,7 @@ class Api { toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM); - return '-1'; + return createBadResponse(); } } @@ -122,7 +125,7 @@ class Api { } - Future uploadImage(File imageFile) async { + Future uploadImage(File imageFile) async { var stream = new http.ByteStream(DelegatingStream.typed(imageFile.openRead())); var length = await imageFile.length(); @@ -140,16 +143,17 @@ class Api { var response = await request.send(); print(response.statusCode); + var response1 = await http.Response.fromStream(response); + if (response.statusCode == 200) { - return '200'; + return parseResponse(response1.body); } else { - return '-1'; + return createBadResponse(); } } - Future addContentToMind(String url,bool isImage) async{ + Future addContentToMind(String url,bool isImage) async{ print("addContentToMind: " + url + " " + isImage.toString()); - String response = "Content is invalid or no content was added"; if(url != null){ print("Widget url: " + url); if(isImage){ @@ -161,10 +165,24 @@ class Api { return addUrlToMind(url); } }else{ - return response; + return createBadResponse(); } } + APIResponse parseResponse(String responseBody) { + Map userMap = jsonDecode(responseBody); + var response = APIResponse.fromJson(userMap); + return response; + } + + APIResponse createBadResponse() { + return APIResponse( + status_code: -1, + text_response: Strings.badResultResponse, + status_text: Strings.badResultResponse, + block_url: Strings.badResultResponse, + ); + } setServerUrl(String value) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); diff --git a/flutter-android-ios-app/notion_ai_my_mind/lib/api/apiresponse.dart b/flutter-android-ios-app/notion_ai_my_mind/lib/api/apiresponse.dart index f4e7462..3dafa23 100644 --- a/flutter-android-ios-app/notion_ai_my_mind/lib/api/apiresponse.dart +++ b/flutter-android-ios-app/notion_ai_my_mind/lib/api/apiresponse.dart @@ -1,13 +1,13 @@ -class Response { +class APIResponse { final int status_code; final String text_response; final String status_text; final String block_url; - Response({this.status_code, this.text_response, this.status_text,this.block_url}); + APIResponse({this.status_code, this.text_response, this.status_text,this.block_url}); - factory Response.fromJson(Map json) { - return Response( + factory APIResponse.fromJson(Map json) { + return APIResponse( status_code: json['status_code'] as int, text_response: json['text_response'] as String, status_text: json['status_text'] as String, diff --git a/flutter-android-ios-app/notion_ai_my_mind/lib/overlay_view.dart b/flutter-android-ios-app/notion_ai_my_mind/lib/overlay_view.dart index 9011cc1..010913c 100644 --- a/flutter-android-ios-app/notion_ai_my_mind/lib/overlay_view.dart +++ b/flutter-android-ios-app/notion_ai_my_mind/lib/overlay_view.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:notion_ai_my_mind/Arguments.dart'; +import 'package:notion_ai_my_mind/api/apiresponse.dart'; import 'package:notion_ai_my_mind/main.dart'; import 'package:notion_ai_my_mind/resources/strings.dart'; import 'package:fluttertoast/fluttertoast.dart'; @@ -18,14 +19,14 @@ class AddLinkPage extends StatelessWidget { appBar: AppBar( title: const Text(Strings.titleAddNewLinkPage), ), - body: FutureBuilder( + body: FutureBuilder( future: Api().addContentToMind(args.url,args.isImage), // a previously-obtained Future or null - builder: (BuildContext context, AsyncSnapshot snapshot) { + builder: (BuildContext context, AsyncSnapshot snapshot) { List children; if (snapshot.hasData) { - return _buildText(context,snapshot.data.toString(), snapshot.data == '-1'); + return _buildText(context,snapshot.data, snapshot.data.status_text == 'error'); } else if (snapshot.hasError) { - return _buildText(context,snapshot.error.toString(), true); + return _buildText(context,snapshot.error, true); } else { children = [ SizedBox( @@ -51,11 +52,8 @@ class AddLinkPage extends StatelessWidget { ); } - Widget _buildText(BuildContext context,String text,bool error) { + Widget _buildText(BuildContext context,APIResponse response,bool error) { List children; - if(text == '200'){ - text = Strings.goodResultResponse; - } if(error){ children = [ Icon( @@ -65,7 +63,7 @@ class AddLinkPage extends StatelessWidget { ), Padding( padding: const EdgeInsets.only(top: 16), - child: Text(text,textAlign: TextAlign.center ,style: new TextStyle(fontSize: 20.0, color: Colors.black)), + child: Text(response.text_response,textAlign: TextAlign.center ,style: new TextStyle(fontSize: 20.0, color: Colors.black)), ), SizedBox(height: 50), RaisedButton( @@ -76,6 +74,15 @@ class AddLinkPage extends StatelessWidget { Strings.exitButtonText, style: new TextStyle(fontSize: 20.0, color: Colors.white), ), + ), + RaisedButton( + onPressed:()=> Api().launchURL(response.block_url), + splashColor: Color(0xFFDD5237), + color: Colors.teal, + child: new Text( + Strings.openAddedContentText, + style: new TextStyle(fontSize: 20.0, color: Colors.white), + ), ) ]; }else{ @@ -87,7 +94,7 @@ class AddLinkPage extends StatelessWidget { ), Padding( padding: const EdgeInsets.only(top: 16), - child: Text(text,textAlign: TextAlign.center ,style: new TextStyle(fontSize: 20.0, color: Colors.black)), + child: Text(response.text_response,textAlign: TextAlign.center ,style: new TextStyle(fontSize: 20.0, color: Colors.black)), ), SizedBox(height: 50), RaisedButton( @@ -98,6 +105,15 @@ class AddLinkPage extends StatelessWidget { Strings.exitButtonText, style: new TextStyle(fontSize: 20.0, color: Colors.white), ), + ), + RaisedButton( + onPressed:()=> Api().launchURL(response.block_url), + splashColor: Color(0xFFDD5237), + color: Colors.teal, + child: new Text( + Strings.openAddedContentText, + style: new TextStyle(fontSize: 20.0, color: Colors.white), + ), ) ]; } diff --git a/flutter-android-ios-app/notion_ai_my_mind/lib/resources/strings.dart b/flutter-android-ios-app/notion_ai_my_mind/lib/resources/strings.dart index 1977e57..09875fd 100644 --- a/flutter-android-ios-app/notion_ai_my_mind/lib/resources/strings.dart +++ b/flutter-android-ios-app/notion_ai_my_mind/lib/resources/strings.dart @@ -1,7 +1,7 @@ class Strings { static const title = 'Notion AI My Mind'; static const titleAddNewLinkPage = 'Add new link'; - static const goodResultResponse = 'Added to your mind.'; + static const openAddedContentText = 'Open added content'; static const exitButtonText = 'Ok.'; static const waitText = 'Awaiting result...'; static const badResultResponse = 'Content could not be added to your mind.';