diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f08471e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -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/CHANGES.txt b/CHANGES.txt index 3cfc560..67a8c7d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -13,4 +13,5 @@ v0.4.4, Thu Sep 25 -- Added dependencies installation to setup.py v0.4.5, Thu Sep 25 -- Added interface to local indico server v0.4.6, Fri Oct 27 -- Updated to point to new indico api servers, cleaner REST API v0.4.8, Fri Nov 7 -- Updated API interface to include new text tags API -v0.4.11, Wed Dec 18 -- Updated tests for text tags \ No newline at end of file +v0.4.11, Wed Dec 18 -- Updated tests for text tags +v0.4.12, Thu Dec 19 -- Added batch support interface \ No newline at end of file diff --git a/README.md b/README.md index 637556b..38cecde 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,14 @@ If you have a local indico server running, simply import from `indicoio.local`. >>> from indicoio.local import political, sentiment, fer, facial_features, language ``` +If you'd like to use our batch api interface, please send an email to contact@indico.io. + +``` +>>> from indicio import batch_sentiment +batch_sentiment(['Text to analyze', 'More text'], auth=("example@example.com", "********")) +``` + + Installation ------------ ``` diff --git a/indicoio/__init__.py b/indicoio/__init__.py index f395523..c8c3548 100644 --- a/indicoio/__init__.py +++ b/indicoio/__init__.py @@ -3,7 +3,7 @@ import indicoio.config as config JSON_HEADERS = {'Content-type': 'application/json', 'Accept': 'text/plain'} -Version, version, __version__, VERSION = ('0.4.11',) * 4 +Version, version, __version__, VERSION = ('0.4.12',) * 4 from indicoio.text.sentiment import political, posneg from indicoio.text.sentiment import posneg as sentiment @@ -13,12 +13,14 @@ 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) -sentiment = partial(sentiment, config.api_root) -posneg = partial(sentiment, config.api_root) -language = partial(language, config.api_root) -fer = partial(fer, config.api_root) -facial_features = partial(facial_features, config.api_root) -image_features = partial(image_features, config.api_root) -text_tags = partial(text_tags, config.api_root) +apis = ['political', 'posneg', 'sentiment', 'language', 'fer', + 'facial_features', 'image_features', 'text_tags'] +apis = dict((api, globals().get(api)) for api in apis) +class Namespace(object): pass +local = Namespace() + +for api in apis: + globals()[api] = partial(apis[api], config.api_root) + globals()['batch_' + api] = partial(apis[api], config.api_root, batch=True) + setattr(local, api, partial(apis[api], config.local_api_root)) + setattr(local, 'batch_' + api, partial(apis[api], config.local_api_root, batch=True)) diff --git a/indicoio/images/features.py b/indicoio/images/features.py index f7c0f2a..776ef8e 100644 --- a/indicoio/images/features.py +++ b/indicoio/images/features.py @@ -5,7 +5,7 @@ import numpy as np from indicoio.utils import image_preprocess, api_handler -def facial_features(api_root, image): +def facial_features(api_root, image, batch=False, auth=None): """ Given an grayscale input image of a face, returns a 48 dimensional feature vector explaining that face. Useful as a form of feature engineering for face oriented tasks. @@ -27,9 +27,9 @@ def facial_features(api_root, image): :type image: list of lists :rtype: List containing feature responses """ - return api_handler(image, api_root + "facialfeatures") + return api_handler(image, api_root + "facialfeatures", batch=batch, auth=auth) -def image_features(api_root, image): +def image_features(api_root, image, batch=False, auth=None): """ Given an input image, returns a 2048 dimensional sparse feature vector explaining that image. Useful as a form of feature engineering for image oriented tasks. @@ -60,4 +60,4 @@ def image_features(api_root, image): :rtype: List containing features """ image = image_preprocess(image) - return api_handler(image, api_root + "imagefeatures") + return api_handler(image, api_root + "imagefeatures", batch=batch, auth=auth) diff --git a/indicoio/images/fer.py b/indicoio/images/fer.py index 1e600aa..ecbddd6 100644 --- a/indicoio/images/fer.py +++ b/indicoio/images/fer.py @@ -4,7 +4,7 @@ import requests import numpy as np from indicoio.utils import api_handler -def fer(api_root, image): +def fer(api_root, image, batch=False, auth=None): """ Given a grayscale input image of a face, returns a probability distribution over emotional state. Input should be in a list of list format, resizing will be attempted internally but for best @@ -28,4 +28,4 @@ def fer(api_root, image): :rtype: Dictionary containing emotion probability pairs """ - return api_handler(image, api_root + "fer") + return api_handler(image, api_root + "fer", batch=batch, auth=auth) diff --git a/indicoio/local/__init__.py b/indicoio/local/__init__.py deleted file mode 100644 index 428186e..0000000 --- a/indicoio/local/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -from functools import partial -import indicoio.config as config - -JSON_HEADERS = {'Content-type': 'application/json', 'Accept': 'text/plain'} - -from indicoio.text.sentiment import political, posneg -from indicoio.text.sentiment import posneg as sentiment -from indicoio.text.lang import language -from indicoio.text.tagging import text_tags -from indicoio.images.fer import fer -from indicoio.images.features import facial_features -from indicoio.images.features import image_features - -political = partial(political, config.local_api_root) -posneg = partial(posneg, config.local_api_root) -sentiment = partial(sentiment, config.local_api_root) -posneg = partial(sentiment, config.local_api_root) -language = partial(language, config.local_api_root) -fer = partial(fer, config.local_api_root) -facial_features = partial(facial_features, config.local_api_root) -image_features = partial(image_features, config.local_api_root) -text_tags = partial(text_tags, config.local_api_root) diff --git a/indicoio/text/lang.py b/indicoio/text/lang.py index 068d45d..2e0e65f 100644 --- a/indicoio/text/lang.py +++ b/indicoio/text/lang.py @@ -1,6 +1,6 @@ from indicoio.utils import api_handler -def language(api_root, text): +def language(api_root, text, batch=False, auth=None): """ Given input text, returns a probability distribution over 33 possible languages of what language the text was written in. @@ -23,4 +23,4 @@ def language(api_root, text): :rtype: Dictionary of language probability pairs """ - return api_handler(text, api_root + "language") + return api_handler(text, api_root + "language", batch=batch, auth=auth) diff --git a/indicoio/text/sentiment.py b/indicoio/text/sentiment.py index 81f0363..acb88ac 100644 --- a/indicoio/text/sentiment.py +++ b/indicoio/text/sentiment.py @@ -1,7 +1,7 @@ from indicoio import JSON_HEADERS from indicoio.utils import api_handler -def political(api_root, text): +def political(api_root, text, batch=False, auth=None): """ Given input text, returns a probability distribution over the political alignment of the speaker. @@ -27,9 +27,9 @@ def political(api_root, text): :rtype: Dictionary of party probability pairs """ - return api_handler(text, api_root + "political") + return api_handler(text, api_root + "political", batch=batch, auth=auth) -def posneg(api_root, text): +def posneg(api_root, text, batch=False, auth=None): """ Given input text, returns a scalar estimate of the sentiment of that text. Values are roughly in the range 0 to 1 with 0.5 indicating neutral sentiment. @@ -50,4 +50,4 @@ def posneg(api_root, text): :rtype: Float """ - return api_handler(text, api_root + "sentiment") + return api_handler(text, api_root + "sentiment", batch=batch, auth=auth) diff --git a/indicoio/text/tagging.py b/indicoio/text/tagging.py index 3f182ad..a2d8ad6 100644 --- a/indicoio/text/tagging.py +++ b/indicoio/text/tagging.py @@ -1,6 +1,6 @@ from indicoio.utils import api_handler -def text_tags(api_root, text): +def text_tags(api_root, text, batch=False, auth=None): """ Given input text, returns a probability distribution over 100 document categories @@ -22,4 +22,4 @@ def text_tags(api_root, text): :rtype: Dictionary of class probability pairs """ - return api_handler(text, api_root + "texttags") + return api_handler(text, api_root + "texttags", batch=batch, auth=None) diff --git a/indicoio/utils/__init__.py b/indicoio/utils/__init__.py index f01ac36..0369dc5 100644 --- a/indicoio/utils/__init__.py +++ b/indicoio/utils/__init__.py @@ -1,12 +1,32 @@ -import inspect, json, requests +import inspect, json, getpass, os +import requests import numpy as np from skimage.transform import resize from indicoio import JSON_HEADERS -def api_handler(arg, url): +def auth_query(): + email = os.environ.get("INDICO_EMAIL") + password = os.environ.get("INDICO_PASSWORD") + + # store settings + if not email: + email = raw_input("Email: ") + os.environ["INDICO_EMAIL"] = email + + if not password: + password = getpass.getpass("Password: ") + os.environ["INDICO_PASSWORD"] = password + + return (email, password) + +def api_handler(arg, url, batch=False, auth=None): data_dict = json.dumps({'data': arg}) - response = requests.post(url, data=data_dict, headers=JSON_HEADERS).json() + if batch: + url += "/batch" + if not auth: + auth = auth_query() + response = requests.post(url, data=data_dict, headers=JSON_HEADERS, auth=auth).json() results = response.get('results', False) if not results: error = response.get('error') diff --git a/setup.py b/setup.py index 8070614..2edb68a 100644 --- a/setup.py +++ b/setup.py @@ -8,13 +8,12 @@ except ImportError: setup( name="IndicoIo", - version='0.4.11', + version='0.4.12', packages=[ "indicoio", "indicoio.text", "indicoio.images", "indicoio.utils", - "indicoio.local", "tests", ], description=""" diff --git a/tests/local/test_local.py b/tests/local/test_local.py index 48cc0f5..2f66ce6 100644 --- a/tests/local/test_local.py +++ b/tests/local/test_local.py @@ -1,4 +1,5 @@ import unittest +import os import numpy as np