From 99d78295cfefc060606d3c53c13950a8a23fff42 Mon Sep 17 00:00:00 2001 From: Madison May Date: Thu, 25 Sep 2014 17:27:06 -0400 Subject: [PATCH 1/8] Updated change log and authors --- AUTHORS | 7 ++++--- CHANGES.txt | 3 ++- README | 5 +++++ README.md | 3 +-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 65ce50e..2aed9bb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,4 @@ -Slater Victoroff -Alec Radford -Aidan McLaughlin +Slater Victoroff +Alec Radford +Aidan McLaughlin +Madison May diff --git a/CHANGES.txt b/CHANGES.txt index 79f07c8..3a6f273 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -9,4 +9,5 @@ v0.4.0, Fri Aug 1 -- Changed api import to lowercase, added language example v0.4.1, Fri Aug 1 -- Updated __version__ variable to be accurate v0.4.2, Wed Aug 6 -- Updated README to accurately reflect political analysis results v0.4.3, Thu Sep 11 -- Added image features api and sphinx compliant documentation -v0.4.4, Thu Sep 25 -- Added dependencies installation to setup.py \ No newline at end of file +v0.4.4, Thu Sep 25 -- Added dependencies installation to setup.py +v0.4.5, Thu Sep 25 -- Added interface to local indico server diff --git a/README b/README index 12869f1..95cec92 100644 --- a/README +++ b/README @@ -55,7 +55,12 @@ Examples >>> sorted(language_dict.keys(), key=lambda x: language_dict[x], reverse=True) [u'Latin', u'Dutch', u'Greek', u'Portuguese', u'Spanish', u'Chinese', u'Lithuanian', u'Korean', u'Finnish', u'Persian (Farsi)', u'Hungarian', u'Danish', u'Norwegian', u'Japanese', u'Tagalog', u'Turkish', u'Swedish', u'Vietnamese', u'Russian', u'Esperanto', u'French', u'Arabic', u'English', u'German', u'Czech', u'Polish', u'Slovak', u'Thai', u'Bulgarian', u'Hebrew', u'Romanian', u'Italian', u'Indonesian'] +``` +If you have a local indico server running, simply import from `indicoio.local`. + +``` +>>> from indicoio.local import political, sentiment, fer, facial_features, language ``` Installation diff --git a/README.md b/README.md index 9b063c2..9a84123 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Examples Local -------- -When using a local version of the api you must remember to import '.local', otherwise it functions the exact same as the remote api documented above. +When using a local version of the api you must remember to import '.local', otherwise it functions the exact same as the remote api documented above. Local API versions are not yet available at this point in time. ``` >>> from indicoio.local import sentiment @@ -71,7 +71,6 @@ When using a local version of the api you must remember to import '.local', othe ``` - Installation ------------ ``` From c0a0317c333e44f383c55eac9793b7324779baa5 Mon Sep 17 00:00:00 2001 From: Madison May Date: Fri, 26 Sep 2014 14:41:05 -0400 Subject: [PATCH 2/8] Update version number --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 10b4e53..0cd7fed 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ except ImportError: setup( name="IndicoIo", - version='0.4.4', + version='0.4.5', packages=[ "indicoio", "indicoio.text", From dfce9ede9f9e3e996b537bb2e596c3eea699e4a1 Mon Sep 17 00:00:00 2001 From: Madison May Date: Fri, 26 Sep 2014 14:55:19 -0400 Subject: [PATCH 3/8] Add local package --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 0cd7fed..c1166f5 100644 --- a/setup.py +++ b/setup.py @@ -14,6 +14,7 @@ setup( "indicoio.text", "indicoio.images", "indicoio.utils", + "indicoio.local", "tests", ], description=""" From c4fd8ea30dd20cae16f1240b76a609a8864fb401 Mon Sep 17 00:00:00 2001 From: Madison May Date: Thu, 2 Oct 2014 13:54:27 -0400 Subject: [PATCH 4/8] Api standardization, feature importance folder --- .travis.yml | 24 ++++++++++++++++++++++++ indicoio/__init__.py | 14 +++++++------- indicoio/{utils => }/config.py | 0 indicoio/images/features.py | 20 +++----------------- indicoio/images/fer.py | 10 ++-------- indicoio/local/__init__.py | 2 +- indicoio/text/lang.py | 10 ++-------- indicoio/text/sentiment.py | 18 +++--------------- indicoio/utils/__init__.py | 13 ++++++++++++- requirements.txt | 4 ++++ setup.py | 2 +- tests/local/__init__.py | 0 tests/{ => local}/test_local.py | 0 tests/remote/__init__.py | 0 tests/{ => remote}/test_remote.py | 0 15 files changed, 59 insertions(+), 58 deletions(-) create mode 100644 .travis.yml rename indicoio/{utils => }/config.py (100%) create mode 100644 requirements.txt create mode 100644 tests/local/__init__.py rename tests/{ => local}/test_local.py (100%) create mode 100644 tests/remote/__init__.py rename tests/{ => remote}/test_remote.py (100%) diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f08471e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,24 @@ +language: python +python: + - 2.7 + +# Setup anaconda +before_install: + - wget http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh + - chmod +x miniconda.sh + - ./miniconda.sh -b + - export PATH=/home/travis/miniconda/bin:$PATH + - conda update --yes conda + # The next couple lines fix a crash with multiprocessing on Travis and are not specific to using Miniconda + - sudo rm -rf /dev/shm + - sudo ln -s /run/shm /dev/shm + +# Install packages +install: + - conda install --yes python=$TRAVIS_PYTHON_VERSION atlas numpy scipy matplotlib nose dateutil pandas statsmodels requests requests six scikit-image + - python setup.py install + +# Run test +script: + - nosetests -w ./tests/remote + \ No newline at end of file diff --git a/indicoio/__init__.py b/indicoio/__init__.py index 0646c43..d92b8ba 100644 --- a/indicoio/__init__.py +++ b/indicoio/__init__.py @@ -1,16 +1,16 @@ from functools import partial -from utils import config +import indicoio.config as config JSON_HEADERS = {'Content-type': 'application/json', 'Accept': 'text/plain'} Version, version, __version__, VERSION = ('0.4.5',) * 4 -from text.sentiment import political, posneg -from text.sentiment import posneg as sentiment -from text.lang import language -from images.fer import fer -from images.features import facial_features -from images.features import image_features +from indicoio.text.sentiment import political, posneg +from indicoio.text.sentiment import posneg as sentiment +from indicoio.text.lang import language +from indicoio.images.fer import fer +from indicoio.images.features import facial_features +from indicoio.images.features import image_features political = partial(political, config.api_root) posneg = partial(posneg, config.api_root) diff --git a/indicoio/utils/config.py b/indicoio/config.py similarity index 100% rename from indicoio/utils/config.py rename to indicoio/config.py diff --git a/indicoio/images/features.py b/indicoio/images/features.py index cd56087..f7c0f2a 100644 --- a/indicoio/images/features.py +++ b/indicoio/images/features.py @@ -3,8 +3,7 @@ import json import requests import numpy as np -from indicoio import JSON_HEADERS -from indicoio.utils import image_preprocess +from indicoio.utils import image_preprocess, api_handler def facial_features(api_root, image): """ @@ -28,14 +27,7 @@ def facial_features(api_root, image): :type image: list of lists :rtype: List containing feature responses """ - - data_dict = json.dumps({"face": image}) - response = requests.post(api_root + "facialfeatures", data=data_dict, headers=JSON_HEADERS) - response_dict = response.json() - if 'response' not in response_dict: - raise ValueError(response_dict.values()[0]) - else: - return response_dict['response'] + return api_handler(image, api_root + "facialfeatures") def image_features(api_root, image): """ @@ -68,10 +60,4 @@ def image_features(api_root, image): :rtype: List containing features """ image = image_preprocess(image) - data_dict = json.dumps({"image": image}) - response = requests.post(api_root + "imagefeatures", data=data_dict, headers=JSON_HEADERS) - response_dict = response.json() - if 'Features' not in response_dict: - raise ValueError(response_dict.values()[0]) - else: - return response_dict['Features'] \ No newline at end of file + return api_handler(image, api_root + "imagefeatures") diff --git a/indicoio/images/fer.py b/indicoio/images/fer.py index 27f8162..1e600aa 100644 --- a/indicoio/images/fer.py +++ b/indicoio/images/fer.py @@ -2,7 +2,7 @@ import json import requests import numpy as np -from indicoio import JSON_HEADERS +from indicoio.utils import api_handler def fer(api_root, image): """ @@ -28,10 +28,4 @@ def fer(api_root, image): :rtype: Dictionary containing emotion probability pairs """ - data_dict = json.dumps({"face": image}) - response = requests.post(api_root + "fer", data=data_dict, headers=JSON_HEADERS) - response_dict = response.json() - if len(response_dict) < 2: - raise ValueError(response_dict.values()[0]) - else: - return response_dict + return api_handler(image, api_root + "fer") diff --git a/indicoio/local/__init__.py b/indicoio/local/__init__.py index 2d50e7f..9d44439 100644 --- a/indicoio/local/__init__.py +++ b/indicoio/local/__init__.py @@ -1,5 +1,5 @@ from functools import partial -from indicoio.utils import config +import indicoio.config as config JSON_HEADERS = {'Content-type': 'application/json', 'Accept': 'text/plain'} diff --git a/indicoio/text/lang.py b/indicoio/text/lang.py index 665522d..169b415 100644 --- a/indicoio/text/lang.py +++ b/indicoio/text/lang.py @@ -1,7 +1,7 @@ import requests import json -from indicoio import JSON_HEADERS +from indicoio.utils import api_handler def language(api_root, text): """ @@ -26,10 +26,4 @@ def language(api_root, text): :rtype: Dictionary of language probability pairs """ - data_dict = json.dumps({'text': text}) - response = requests.post(api_root + "language", data=data_dict, headers=JSON_HEADERS) - response_dict = response.json() - if len(response_dict) < 2: - raise ValueError(response_dict.values()[0]) - else: - return response_dict \ No newline at end of file + return api_handler(text, api_root + "language") diff --git a/indicoio/text/sentiment.py b/indicoio/text/sentiment.py index b570f5f..e60cd42 100644 --- a/indicoio/text/sentiment.py +++ b/indicoio/text/sentiment.py @@ -2,7 +2,7 @@ import requests import json from indicoio import JSON_HEADERS -from indicoio.utils import normalize +from indicoio.utils import api_handler def political(api_root, text): """ @@ -30,13 +30,7 @@ def political(api_root, text): :rtype: Dictionary of party probability pairs """ - data_dict = json.dumps({'text': text}) - response = requests.post(api_root + "political", data=data_dict, headers=JSON_HEADERS) - response_dict = response.json() - if len(response_dict) < 2: - raise ValueError(response_dict.values()[0]) - else: - return response_dict + return api_handler(text, api_root + "political") def posneg(api_root, text): """ @@ -59,10 +53,4 @@ def posneg(api_root, text): :rtype: Float """ - data_dict = json.dumps({'text': text}) - response = requests.post(api_root + "sentiment", data=data_dict, headers=JSON_HEADERS) - response_dict = response.json() - if 'Sentiment' not in response_dict: - raise ValueError(response_dict.values()[0]) - else: - return response_dict['Sentiment'] + return api_handler(text, api_root + "sentiment") diff --git a/indicoio/utils/__init__.py b/indicoio/utils/__init__.py index 18ae6db..f01ac36 100644 --- a/indicoio/utils/__init__.py +++ b/indicoio/utils/__init__.py @@ -1,7 +1,18 @@ -import inspect +import inspect, json, requests import numpy as np from skimage.transform import resize +from indicoio import JSON_HEADERS + +def api_handler(arg, url): + data_dict = json.dumps({'data': arg}) + response = requests.post(url, data=data_dict, headers=JSON_HEADERS).json() + results = response.get('results', False) + if not results: + error = response.get('error') + raise ValueError(error) + return results + class TypeCheck(object): """ Decorator that performs a typecheck on the input to a function diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..bc40c5f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +numpy>=1.8.0 +six>=1.3.0 +scikit-image>=0.10.1 +requests>=2.2.1 diff --git a/setup.py b/setup.py index c1166f5..b0d3a21 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ except ImportError: setup( name="IndicoIo", - version='0.4.5', + version='0.4.6', packages=[ "indicoio", "indicoio.text", diff --git a/tests/local/__init__.py b/tests/local/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_local.py b/tests/local/test_local.py similarity index 100% rename from tests/test_local.py rename to tests/local/test_local.py diff --git a/tests/remote/__init__.py b/tests/remote/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_remote.py b/tests/remote/test_remote.py similarity index 100% rename from tests/test_remote.py rename to tests/remote/test_remote.py From 0af69efaae7e3ffb4cc3faee0a74539a7932d5be Mon Sep 17 00:00:00 2001 From: Madison May Date: Mon, 6 Oct 2014 20:24:55 -0400 Subject: [PATCH 5/8] Updated tests --- tests/local/test_local.py | 2 +- tests/remote/test_remote.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/local/test_local.py b/tests/local/test_local.py index 241d7da..a4365c1 100644 --- a/tests/local/test_local.py +++ b/tests/local/test_local.py @@ -16,11 +16,11 @@ class FullAPIRun(unittest.TestCase): self.assertEqual(political_set, set(response.keys())) def test_posneg(self): - posneg_set = set(['Sentiment']) test_string = "Worst song ever." response = sentiment(test_string) self.assertTrue(isinstance(response, float)) + self.assertTrue(response < 0.5) def test_good_fer(self): fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy']) diff --git a/tests/remote/test_remote.py b/tests/remote/test_remote.py index d5169cb..64d3b45 100644 --- a/tests/remote/test_remote.py +++ b/tests/remote/test_remote.py @@ -16,11 +16,11 @@ class FullAPIRun(unittest.TestCase): self.assertEqual(political_set, set(response.keys())) def test_posneg(self): - posneg_set = set(['Sentiment']) test_string = "Worst song ever." response = sentiment(test_string) self.assertTrue(isinstance(response, float)) + self.assertTrue(response < 0.5) def test_good_fer(self): fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy']) From 29df762b47d54ce817a747ad7799db2705edba2f Mon Sep 17 00:00:00 2001 From: Madison May Date: Tue, 7 Oct 2014 22:57:27 -0400 Subject: [PATCH 6/8] Update to new router for apis --- README.md | 2 +- indicoio/config.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9a84123..272b0bd 100644 --- a/README.md +++ b/README.md @@ -77,4 +77,4 @@ Installation pip install indicoio ``` -Announcement: Indico has partnered with Experfy, a data science consulting marketplace based in the Harvard Innovation Lab. Through Experfy, we are helping our data science community members find lucrative projects and advance their skills. Please signup for Experfy at https://www.experfy.com/ to get started. +Announcement: indico has partnered with Experfy, a data science consulting marketplace based in the Harvard Innovation Lab. Through Experfy, we are helping our data science community members find lucrative projects and advance their skills. Please signup for Experfy at https://www.experfy.com/ to get started. diff --git a/indicoio/config.py b/indicoio/config.py index f6b622e..150d0f9 100644 --- a/indicoio/config.py +++ b/indicoio/config.py @@ -1,2 +1,2 @@ local_api_root = "http://localhost:9438/" -api_root = "http://api.indico.io/" \ No newline at end of file +api_root = "http://apiv1.indico.io/" \ No newline at end of file From 42f19db69e96f7e7597a1f5e8246d52740002762 Mon Sep 17 00:00:00 2001 From: Madison May Date: Thu, 16 Oct 2014 13:05:45 -0400 Subject: [PATCH 7/8] Image features test --- setup.py | 2 +- tests/local/test_local.py | 9 ++++++++- tests/remote/test_remote.py | 9 ++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index b0d3a21..331195d 100644 --- a/setup.py +++ b/setup.py @@ -34,6 +34,6 @@ setup( "requests >= 1.2.3", "six >= 1.3.0", "numpy >= 1.8.1", - "scikit-image >= 0.10.1" + "scikit-image >= 0.10.1", ], ) diff --git a/tests/local/test_local.py b/tests/local/test_local.py index a4365c1..23dad4e 100644 --- a/tests/local/test_local.py +++ b/tests/local/test_local.py @@ -2,7 +2,7 @@ import unittest import numpy as np -from indicoio.local import political, sentiment, fer, facial_features, language +from indicoio.local import political, sentiment, fer, facial_features, language, image_features class FullAPIRun(unittest.TestCase): @@ -45,6 +45,13 @@ class FullAPIRun(unittest.TestCase): self.assertTrue(isinstance(response, list)) self.assertEqual(len(response), 48) + def test_good_image_features(self): + test_image = np.linspace(0,1,64*64*3).reshape(64,64,3).tolist() + response = image_features(test_image) + + self.assertTrue(isinstance(response, list)) + self.assertEqual(len(response), 2048) + def test_language(self): language_set = set([ 'English', diff --git a/tests/remote/test_remote.py b/tests/remote/test_remote.py index 64d3b45..c4fe600 100644 --- a/tests/remote/test_remote.py +++ b/tests/remote/test_remote.py @@ -2,7 +2,7 @@ import unittest import numpy as np -from indicoio import political, sentiment, fer, facial_features, language +from indicoio import political, sentiment, fer, facial_features, language, image_features class FullAPIRun(unittest.TestCase): @@ -44,6 +44,13 @@ class FullAPIRun(unittest.TestCase): self.assertTrue(isinstance(response, list)) self.assertEqual(len(response), 48) + + def test_good_image_features(self): + test_image = np.linspace(0,1,64*64*3).reshape(64,64,3).tolist() + response = image_features(test_image) + + self.assertTrue(isinstance(response, list)) + self.assertEqual(len(response), 2048) def test_language(self): language_set = set([ From ef7fb969158a4779732d4ea1ed797a16e09100af Mon Sep 17 00:00:00 2001 From: Madison May Date: Thu, 16 Oct 2014 13:42:33 -0400 Subject: [PATCH 8/8] linspace to random.rand --- tests/local/test_local.py | 17 ++++++++++++----- tests/remote/test_remote.py | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/tests/local/test_local.py b/tests/local/test_local.py index 23dad4e..f60ac59 100644 --- a/tests/local/test_local.py +++ b/tests/local/test_local.py @@ -24,7 +24,7 @@ class FullAPIRun(unittest.TestCase): def test_good_fer(self): fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy']) - test_face = np.linspace(0,50,48*48).reshape(48,48).tolist() + test_face = np.random.rand(48,48).tolist() response = fer(test_face) self.assertTrue(isinstance(response, dict)) @@ -32,21 +32,28 @@ class FullAPIRun(unittest.TestCase): def test_bad_fer(self): fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy']) - test_face = np.linspace(0,50,56*56).reshape(56,56).tolist() + test_face = np.random.rand(56,56).tolist() response = fer(test_face) self.assertTrue(isinstance(response, dict)) self.assertEqual(fer_set, set(response.keys())) def test_good_facial_features(self): - test_face = np.linspace(0,50,48*48).reshape(48,48).tolist() + test_face = np.random.rand(48,48).tolist() response = facial_features(test_face) self.assertTrue(isinstance(response, list)) self.assertEqual(len(response), 48) + + def test_good_image_features_greyscale(self): + test_image = np.random.rand(64, 64).tolist() + response = image_features(test_image) - def test_good_image_features(self): - test_image = np.linspace(0,1,64*64*3).reshape(64,64,3).tolist() + self.assertTrue(isinstance(response, list)) + self.assertEqual(len(response), 2048) + + def test_good_image_features_rgb(self): + test_image = np.random.rand(64, 64, 3).tolist() response = image_features(test_image) self.assertTrue(isinstance(response, list)) diff --git a/tests/remote/test_remote.py b/tests/remote/test_remote.py index c4fe600..962fa3d 100644 --- a/tests/remote/test_remote.py +++ b/tests/remote/test_remote.py @@ -24,7 +24,7 @@ class FullAPIRun(unittest.TestCase): def test_good_fer(self): fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy']) - test_face = np.linspace(0,50,48*48).reshape(48,48).tolist() + test_face = np.random.rand(48,48).tolist() response = fer(test_face) self.assertTrue(isinstance(response, dict)) @@ -32,21 +32,28 @@ class FullAPIRun(unittest.TestCase): def test_bad_fer(self): fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy']) - test_face = np.linspace(0,50,56*56).reshape(56,56).tolist() + test_face = np.random.rand(56,56).tolist() response = fer(test_face) self.assertTrue(isinstance(response, dict)) self.assertEqual(fer_set, set(response.keys())) def test_good_facial_features(self): - test_face = np.linspace(0,50,48*48).reshape(48,48).tolist() + test_face = np.random.rand(48,48).tolist() response = facial_features(test_face) self.assertTrue(isinstance(response, list)) self.assertEqual(len(response), 48) - def test_good_image_features(self): - test_image = np.linspace(0,1,64*64*3).reshape(64,64,3).tolist() + def test_good_image_features_greyscale(self): + test_image = np.random.rand(64, 64).tolist() + response = image_features(test_image) + + self.assertTrue(isinstance(response, list)) + self.assertEqual(len(response), 2048) + + def test_good_image_features_rgb(self): + test_image = np.random.rand(64, 64, 3).tolist() response = image_features(test_image) self.assertTrue(isinstance(response, list))