Skip to content

Commit

Permalink
feat: added local tensorflow image tagging. You can choose between th…
Browse files Browse the repository at this point in the history
…at or cloud based clarifai!
  • Loading branch information
elblogbruno committed Feb 1, 2021
1 parent b6d489e commit 648633e
Show file tree
Hide file tree
Showing 15 changed files with 252 additions and 149 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Created by https://www.toptal.com/developers/gitignore/api/images,video
# Edit at https://www.toptal.com/developers/gitignore?templates=images,video

/Python Server/app/.idea
/Python Server/app/image_tagging/temp_image_folder
/Python Server/app/__pycache__
*.zip
*.log
*.json
Expand Down
145 changes: 51 additions & 94 deletions Python Server/app/NotionAI.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,24 @@
import validators
import os

from custom_errors import OnImageNotFound, OnUrlNotValid, EmbedableContentNotFound, NoTagsFound, OnTokenV2NotValid
from custom_errors import OnImageNotFound, OnUrlNotValid, EmbedableContentNotFound, NoTagsFound

import requests
import json

from ClarifaiAI import *
from uuid import uuid1
from random import choice
from time import sleep

import threading

from image_tagging.image_tagging import ImageTagging


class NotionAI:
def __init__(self, logging):
print("Init NotionAI")
logging.info("Initiating NotionAI Class.")

if os.path.isfile('data.json'):
print("Initiating with a found config file.")
logging.info("Initiating with a found config file.")
Expand All @@ -28,36 +31,37 @@ def __init__(self, logging):
print("You should go to the homepage and set the config.")
logging.info("You should go to the homepage and set the config.")

def run(self,logging):
# Obtain the `token_v2` value by inspecting your browser cookies on a logged-in session on Notion.so
def run(self, logging):
loaded = False
options = {}
data = {}
with open('data.json') as json_file:
options = json.load(json_file)
data = json.load(json_file)
try:
self.client = NotionClient(token_v2=options['token'])
mind_page = self.client.get_block(options['url'])
self.logging = logging

self.logging.info("Running notionAI with " + str(data))

self.data = data

self.client = NotionClient(token_v2=data['token'])

mind_page = self.client.get_block(data['url'])

self.mind_id = mind_page.id

self.options = options
self.clarifai = ClarifaiAI(options['clarifai_key'])
self.image_tagger = ImageTagging(data, logging)

cv = self.client.get_collection_view(self.options['url'])
cv = self.client.get_collection_view(self.data['url'])

self.collection = cv.collection
print("Running notionAI with " + str(self.options))

self.logging = logging

self.logging.info("Running notionAI with " + str(self.options))
loaded = True
except requests.exceptions.HTTPError:
print("Incorrect token V2 from notion")
self.logging.info("Incorrect token V2 from notion")
return loaded

def add_url_to_database(self, url, title):
print("The url is " + url)
self.logging("Adding url {} to mind with title {}".format(url,title))
self.statusCode = 200 # at start we asume everything will go ok
try:
rowId = self.web_clipper_request(url, title)
Expand All @@ -68,18 +72,17 @@ def add_url_to_database(self, url, title):
self.logging.info(invalidUrl)
self.statusCode = 500

def add_url_thread(self,rowId):
def add_url_thread(self, rowId):
self.logging.info("Thread %s: starting", rowId)
row = self.client.get_block(rowId)
try:
page_content = self.get_content_from_row(row, 0)
img_url = self.extract_image_from_content(page_content)
try:
tags = self.clarifai.get_tags(img_url)
tags = self.image_tagger.get_tags(img_url)
print(tags)
self.logging.info(tags)
row.AITagsText = tags
self.add_new_multi_select_value("AITagsText", tags)
except NoTagsFound as e:
print(e)
self.logging.info(e)
Expand All @@ -97,49 +100,6 @@ def add_url_thread(self,rowId):
self.logging.info(e)
self.logging.info("Thread %s: finishing", rowId)

def add_new_multi_select_value(self, prop, value, color=None):
colors = [
"default",
"gray",
"brown",
"orange",
"yellow",
"green",
"blue",
"purple",
"pink",
"red",
]

"""`prop` is the name of the multi select property."""
if color is None:
color = choice(colors)

collection_schema = self.collection.get("schema")
prop_schema = next(
(v for k, v in collection_schema.items() if v["name"] == prop), None
)
if not prop_schema:
raise ValueError(
'{} property does not exist on the collection!'.format(prop)
)
if prop_schema["type"] != "multi_select":
raise ValueError('{} is not a multi select property!'.format(prop))

if "options" not in prop_schema:
prop_schema["options"] = []

dupe = next(
(o for o in prop_schema["options"] if o["value"] == value), None
)
if dupe:
raise ValueError(f'"{value}" already exists in the schema!')

prop_schema["options"].append(
{"id": str(uuid1()), "value": value, "color": color}
)
self.collection.set("schema", collection_schema)

def extract_image_from_content(self, page_content):
url = " "
for element in page_content:
Expand Down Expand Up @@ -171,7 +131,7 @@ def get_content_from_row(self, row, n):

def web_clipper_request(self, url, title):
cookies = {
'token_v2': self.options['token'],
'token_v2': self.data['token'],
}

headers = {
Expand Down Expand Up @@ -200,7 +160,7 @@ def web_clipper_request(self, url, title):
data=data)
response_text = response.text
json_response = json.loads(response_text)
#self.logging.info(str(json_response))
# self.logging.info(str(json_response))
rowId = json_response['createdBlockIds'][0]
return rowId
else:
Expand Down Expand Up @@ -229,6 +189,7 @@ def add_image_to_database(self, url, image_src, image_src_url):
print("The Image is " + image_src + " context: " + image_src_url)
self.statusCode = 200 # at start we asume everything will go ok
row = self.collection.add_row()

self.row = row

try:
Expand All @@ -238,20 +199,9 @@ def add_image_to_database(self, url, image_src, image_src_url):
img_block.source = image_src
row.icon = img_block.source
row.person = self.client.current_user
try:
tags = self.clarifai.get_tags(image_src)
self.logging.info("tags from image {0} : {1}".format(image_src_url,tags))
row.AITagsText = tags
self.add_new_multi_select_value("AITags", tags)
except NoTagsFound as e:
print(e)
self.logging.info(e)
except ValueError as e:
print(e)
self.logging.info(e)
except Exception as e:
print(e)
self.logging.info(e)
x = threading.Thread(target=self.analyze_image_thread, args=(image_src, row, image_src_url))
x.start()

except requests.exceptions.HTTPError as invalidUrl:
print(invalidUrl)
self.logging.info(invalidUrl)
Expand All @@ -270,21 +220,28 @@ def add_image_to_database_by_post(self, image_src):
img_block.upload_file(image_src)
row.icon = img_block.source
row.person = self.client.current_user
try:
tags = self.clarifai.get_tags(img_block.source)
print(tags)
row.AITagsText = tags
self.add_new_multi_select_value("AITagsText", tags)
except NoTagsFound as e:
print(e)
self.logging.info(e)
except ValueError as e:
print(e)
self.logging.info(e)
except Exception as e:
print(e)
self.logging.info(e)

x = threading.Thread(target=self.analyze_image_thread, args=(image_src, row))
x.start()
except requests.exceptions.HTTPError as invalidUrl:
print(invalidUrl)
self.logging.info(invalidUrl)
self.statusCode = 500

def analyze_image_thread(self, image_src,row, image_src_url="no context"):
try:
self.logging.info("Image tag Thread %s: starting", row.id)
tags = self.image_tagger.get_tags(image_src)
self.logging.info("Tags from image {0} : {1}".format(image_src_url, tags))
row.AITagsText = tags
self.logging.info("Image tag Thread %s: finished", row.id)
except NoTagsFound as e:
print(e)
self.logging.info(e)
except ValueError as e:
print(e)
self.logging.info(e)
except Exception as e:
print(e)
self.logging.info(e)

26 changes: 4 additions & 22 deletions Python Server/app/app.log
Original file line number Diff line number Diff line change
@@ -1,27 +1,9 @@
root - INFO - You should go to the homepage and set the config.
root - INFO - Initiating NotionAI Class.
root - INFO - Initiating with a found config file.
root - INFO - Running notionAI with {'url': 'https://www.notion.so/glassear/d4e43dbfe7244e0a83f18e14506e74ae?v=2b6755006a15418c978d5067180baae0', 'token': 'e6517083645826700a071fdf1644a844b6a9dba7252010c8a99efaae991f990575fd6160ce2c9a30c9ed78057261bb49f3245e227d80c3a8a630f3f4e839e66d90d75c24a26671a29fc072020f6d'}
root - INFO - Using tensorflow predictor, with delete_after_tagging = True
root - INFO - Initiating with a found port.json file.
root - INFO - Using 8080 port
werkzeug - WARNING - * Debugger is active!
werkzeug - INFO - * Debugger PIN: 207-644-306
werkzeug - INFO - * Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
root - INFO - Adding url to mind: b'https://github.com/elblogbruno/NotionAI-MyMind' b'elblogbruno/NotionAI-MyMind: This repo uses AI and the wonderful Notion to enable you to add anything on the web to your "Mind" and forget about everything else.'
werkzeug - INFO - 192.168.1.42 - - [30/Jan/2021 11:09:39] "GET /add_url_to_mind?url=https://github.com/elblogbruno/NotionAI-MyMind&title=elblogbruno/NotionAI-MyMind:%20This%20repo%20uses%20AI%20and%20the%20wonderful%20Notion%20to%20enable%20you%20to%20add%20anything%20on%20the%20web%20to%20your%20%22Mind%22%20and%20forget%20about%20everything%20else. HTTP/1.1" 500 -
werkzeug - ERROR - 192.168.1.42 - - [30/Jan/2021 11:10:13] code 400, message Bad request version ('��\x13\x01\x13\x02\x13\x03�+�/�,�0̨̩�\x13�\x14\x00\x9c\x00\x9d\x00/\x005\x01\x00\x01\x93��\x00\x00\x00\x17\x00\x00�\x01\x00\x01\x00\x00')
werkzeug - ERROR - 192.168.1.42 - - [30/Jan/2021 11:10:13] code 400, message Bad HTTP/0.9 request type ('\x16\x03\x01\x02\x00\x01\x00\x01�\x03\x032��\x9e�P�\x92�\x88\x94\x10��\x7f�\x80\x80��,B\x82\x02_��')
werkzeug - ERROR - 192.168.1.42 - - [30/Jan/2021 11:10:13] code 400, message Bad request version ('Ȧ\x0e��V���\x9c�\x98�x\x83')
werkzeug - ERROR - 192.168.1.42 - - [30/Jan/2021 11:10:13] code 400, message Bad request version ('2-\x07³�\x0f�w\x13�۬$�\\\x00"JJ\x13\x01\x13\x02\x13\x03�+�/�,�0̨̩�\x13�\x14\x00\x9c\x00\x9d\x00/\x005\x00')
werkzeug - INFO - 192.168.1.42 - - [30/Jan/2021 11:10:18] "GET / HTTP/1.1" 200 -
root - INFO - Running notionAI with {'url': 'https://www.notion.so/glassear/d4e43dbfe7244e0a83f18e14506e74ae?v=2b6755006a15418c978d5067180baae0', 'token': 'e6517083645826700a071fdf1644a844b6a9dba7252010c8a99efaae991f990575fd6160ce2c9a30c9ed78057261bb49f3245e227d80c3a8a630f3f4e839e66d90d75c24a26671a29fc072020f6d', 'clarifai_key': '7d13a00d87c5408b96fa94d16ad3c521'}
werkzeug - INFO - 192.168.1.42 - - [30/Jan/2021 11:10:24] "POST /handle_data HTTP/1.1" 200 -
root - INFO - Adding url to mind: b'https://github.com/elblogbruno/NotionAI-MyMind' b'elblogbruno/NotionAI-MyMind: This repo uses AI and the wonderful Notion to enable you to add anything on the web to your "Mind" and forget about everything else.'
root - INFO - {"type": "block", "blockId": "d4e43dbf-e724-4e0a-83f1-8e14506e74ae", "property": "P#~d", "items": [{"url": "https://github.com/elblogbruno/NotionAI-MyMind", "title": "elblogbruno/NotionAI-MyMind: This repo uses AI and the wonderful Notion to enable you to add anything on the web to your \"Mind\" and forget about everything else."}], "from": "chrome"}
root - INFO - Thread 058a46df-5f41-401e-be3f-f197d2112859: starting
werkzeug - INFO - 192.168.1.42 - - [30/Jan/2021 11:10:30] "GET /add_url_to_mind?url=https://github.com/elblogbruno/NotionAI-MyMind&title=elblogbruno/NotionAI-MyMind:%20This%20repo%20uses%20AI%20and%20the%20wonderful%20Notion%20to%20enable%20you%20to%20add%20anything%20on%20the%20web%20to%20your%20%22Mind%22%20and%20forget%20about%20everything%20else. HTTP/1.1" 200 -
root - INFO - No content available yet 0
root - INFO - No content available yet 1
root - INFO - No content available yet 2
root - INFO - None
root - INFO - Request failed, status code: 10020
root - INFO - Thread 058a46df-5f41-401e-be3f-f197d2112859: finishing
root - INFO - Adding url to mind: b'chrome-extension://ocjdfdihgfjfflddjlkohpeifglmibig/options.html?serverip=http://192.168.1.42:8080/' b'Notion AI My Mind Options!'
werkzeug - INFO - 192.168.1.42 - - [30/Jan/2021 11:11:59] "GET /add_url_to_mind?url=chrome-extension://ocjdfdihgfjfflddjlkohpeifglmibig/options.html?serverip=http%3A%2F%2F192.168.1.42%3A8080%2F&title=Notion%20AI%20My%20Mind%20Options! HTTP/1.1" 500 -
Binary file not shown.
File renamed without changes.
Binary file not shown.
32 changes: 32 additions & 0 deletions Python Server/app/image_tagging/image_tagging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from image_tagging.clarifai_tagging.ClarifaiAI import ClarifaiAI
from image_tagging.tensorflow_tagging.tensorflow_tagging import TensorFlowTag
import json


class ImageTagging:

def __init__(self,data,logging):
options = {}
with open('options.json') as json_file:
options = json.load(json_file)
try:
self.options = options
if options['use_clarifai']:
self.predictor = ClarifaiAI(data['clarifai_key'])
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']))
except FileNotFoundError:
logging.info("options.json not found")
print("Wrong file or file path")

def get_tags(self, image_url):
self.print_current_detector()
return self.predictor.get_tags(image_url)

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']))
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np

from tensorflow.python.keras.applications.inception_v3 import InceptionV3, preprocess_input, decode_predictions
from tensorflow.python.keras.preprocessing import image
import os
from utils import download_image_from_url, createFolder


class TensorFlowTag:

def __init__(self, delete_image_after_tagging=True):
self.delete_after_tagging = delete_image_after_tagging

createFolder("./image_tagging/temp_image_folder")

def get_tags(self, image_url):
model = InceptionV3(weights='imagenet')
file = download_image_from_url(image_url)
img = image.load_img(file, target_size=(299, 299))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)

preds = model.predict(x)
prediction_decoded = decode_predictions(preds, top=5)[0]

print('Predicted:', prediction_decoded)

tags = []
for element in prediction_decoded:
tags.append(element[1])

if self.delete_after_tagging:
os.remove(file)

str1 = ','.join(str(e) for e in tags)

return str1
Binary file modified Python Server/app/requirements.txt
Binary file not shown.
Loading

0 comments on commit 648633e

Please sign in to comment.