ADD: Endpoint for multi api requests

This commit is contained in:
Chris Lee
2015-06-01 13:35:45 -04:00
parent c82fd16b11
commit 49a94d2986
5 changed files with 186 additions and 12 deletions
+4 -11
View File
@@ -16,18 +16,11 @@ 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
from indicoio.utils.multi import predict_image, predict_text
apis = [
'political',
'posneg',
'sentiment',
'language',
'fer',
'facial_features',
'image_features',
'text_tags'
]
apis = dict((api, globals().get(api)) for api in apis)
from indicoio.config import API_NAMES
apis = dict((api, globals().get(api)) for api in API_NAMES)
for api in apis:
globals()[api] = partial(apis[api])
+15
View File
@@ -45,11 +45,26 @@ class Settings(ConfigParser.ConfigParser):
None
)
TEXT_APIS = [
'text_tags',
'political',
'sentiment',
'language'
]
IMAGE_APIS = [
'fer',
'facial_features',
'image_features'
]
API_NAMES = IMAGE_APIS + TEXT_APIS + ["predict_text", "predict_image"]
SETTINGS = Settings(files=[
os.path.expanduser("~/.indicorc"),
os.path.join(os.getcwd(), '.indicorc')
])
api_key = SETTINGS.api_key()
cloud = SETTINGS.cloud()
PUBLIC_API_HOST = 'apiv2.indico.io'
-1
View File
@@ -28,7 +28,6 @@ def api_handler(arg, cloud, api, batch=False, api_key=None, **kwargs):
url = url + "/batch" if batch else url
url += "?key=%s" % api_key
response = requests.post(url, data=json_data, headers=JSON_HEADERS)
if response.status_code == 503 and cloud != None:
raise Exception("Private cloud '%s' does not include api '%s'" % (cloud, api))
+121
View File
@@ -0,0 +1,121 @@
from indicoio.config import TEXT_APIS, IMAGE_APIS, API_NAMES
from indicoio.utils import api_handler
CLIENT_SERVER_MAP = dict((api, api.strip().replace("_", "").lower()) for api in API_NAMES)
SERVER_CLIENT_MAP = dict((v, k) for k, v in CLIENT_SERVER_MAP.iteritems())
def multi(data, type, apis, available, batch=False, **kwargs):
"""
Helper to make multi requests of different types.
:param data: data to be sent in JSON.
:param type: String type of API request
:param apis: List of apis to use.
:param apis: List of apis available for use.
:type data: str or image
:type type: str or unicode
:type apis: list of str
:type available: list of str
:rtype: Dictionary of api responses
"""
# Client side api name checking - strictly only accept func name api
invalid_apis = [api for api in apis if api not in available]
if invalid_apis:
raise ValueError("%s are not valid %s APIs. Please reference the available APIs below:\n%s"
% (", ".join(invalid_apis), type, ", ".join(available))
)
# Convert client api names to server names before sending request
apis = map(CLIENT_SERVER_MAP.get, apis)
result = api_handler(data, apis=apis, batch=batch, **kwargs)
if batch:
return [handle_response(each) for each in result]
return handle_response(result)
def handle_response(result):
try:
# Parse out the results to a dicionary of api: result
return dict((SERVER_CLIENT_MAP[api], parsed_response(res))
for api, res in result.iteritems())
except KeyError:
for api in result:
if "error" in result[api]:
raise ValueError(result[api]["error"])
raise Exception("Sorry, %s API returned an unexpected response:\n%s" % (api, result[api]))
def predict_text(input_text, apis, cloud=None, batch=False, api_key=None, **kwargs):
"""
Given input text, returns the results of specified text apis. Possible apis
include: [ 'text_tags', 'political', 'sentiment', 'language' ]
Example usage:
.. code-block:: python
>>> import indicoio
>>> text = 'Monday: Delightful with mostly sunny skies. Highs in the low 70s.'
>>> results = indicoio.text(data = text, apis = ["language", "sentiment"])
>>> language_results = results["langauge"]
>>> sentiment_results = results["sentiment"]
:param text: The text to be analyzed.
:param apis: List of apis to use.
:type text: str or unicode
:type apis: list of str
:rtype: Dictionary of api responses
"""
return multi(
api="apis",
data=input_text,
type="text",
available = TEXT_APIS,
cloud=cloud,
batch=batch,
api_key=api_key,
apis=apis,
**kwargs)
def predict_image(image, apis, cloud=None, batch=False, api_key=None, **kwargs):
"""
Given input image, returns the results of specified image apis. Possible apis
include: ['fer', 'facial_features', 'image_features']
Example usage:
.. code-block:: python
>>> import indicoio
>>> import numpy as np
>>> face = np.zeros((48,48)).tolist()
>>> results = indicoio.image(image = face, apis = ["fer", "facial_features"])
>>> fer = results["fer"]
>>> facial_features = results["facial_features"]
:param text: The text to be analyzed.
:param apis: List of apis to use.
:type text: str or unicode
:type apis: list of str
:rtype: Dictionary of api responses
"""
return multi(
api="apis",
data=image,
type="image",
available=IMAGE_APIS,
cloud=cloud,
batch=batch,
api_key=api_key,
apis=apis,
**kwargs)
def parsed_response(response):
result = response.get('results') or response.get('error', False)
if result:
return result
raise KeyError
+46
View File
@@ -9,6 +9,7 @@ from indicoio import config
from indicoio import political, sentiment, fer, facial_features, language, image_features, text_tags
from indicoio import batch_political, batch_sentiment, batch_fer, batch_facial_features
from indicoio import batch_language, batch_image_features, batch_text_tags
from indicoio import predict_image, predict_text, batch_predict_image, batch_predict_text
DIR = os.path.dirname(os.path.realpath(__file__))
@@ -107,6 +108,51 @@ class BatchAPIRun(unittest.TestCase):
self.assertTrue(isinstance(response, list))
self.assertTrue(response[0]['English'] > 0.25)
def test_multi_api_image(self):
test_data = generate_array((48,48))
response = predict_image(test_data, apis=config.IMAGE_APIS, api_key=self.api_key)
self.assertTrue(isinstance(response, dict))
self.assertTrue(set(response.keys()) == set(config.IMAGE_APIS))
def test_multi_api_text(self):
test_data = 'clearly an english sentence'
response = predict_text(test_data, apis=config.TEXT_APIS, api_key=self.api_key)
self.assertTrue(isinstance(response, dict))
self.assertTrue(set(response.keys()) == set(config.TEXT_APIS))
def test_batch_multi_api_image(self):
test_data = [generate_array((48,48))]
response = batch_predict_image(test_data, apis=config.IMAGE_APIS, api_key=self.api_key)
self.assertTrue(isinstance(response, list))
self.assertTrue(set(response[0].keys()) == set(config.IMAGE_APIS))
def test_batch_multi_api_text(self):
test_data = ['clearly an english sentence']
response = batch_predict_text(test_data, apis=config.TEXT_APIS, api_key=self.api_key)
self.assertTrue(isinstance(response, list))
self.assertTrue(set(response[0].keys()) == set(config.TEXT_APIS))
def test_multi_api_bad_api(self):
self.assertRaises(ValueError,
batch_predict_text,
"this shouldn't work",
apis=["sentiment", "somethingbad"])
def test_multi_bad_mixed_api(self):
self.assertRaises(ValueError,
predict_text,
"this shouldn't work",
apis=["fer", "sentiment", "facial_features"])
def test_batch_multi_bad_mixed_api(self):
self.assertRaises(ValueError,
batch_predict_text,
["this shouldn't work"],
apis=["fer", "sentiment", "facial_features"])
def test_batch_set_cloud(self):
test_data = ['clearly an english sentence']
self.assertRaises(ConnectionError,