mirror of
https://github.com/wassname/IndicoIo-python.git
synced 2026-06-27 16:10:34 +08:00
Merge pull request #116 from IndicoDataSolutions/development
Development
This commit is contained in:
@@ -34,3 +34,5 @@ v0.8.0 Fri Jul 10 -- Add Content Filtering API, Named Entities API, Facial Emoti
|
|||||||
v0.8.1 Wed Jul 22 -- Add Sentiment HQ to predict_text API
|
v0.8.1 Wed Jul 22 -- Add Sentiment HQ to predict_text API
|
||||||
v0.9.0 Tue Jul 28 -- Deprecate batch function calls in favor of type inference
|
v0.9.0 Tue Jul 28 -- Deprecate batch function calls in favor of type inference
|
||||||
v0.9.1 Mon Aug 3 -- Add Facial Localization API, image resizing updates
|
v0.9.1 Mon Aug 3 -- Add Facial Localization API, image resizing updates
|
||||||
|
v0.9.2 Fri Aug 14 -- Add intersections API, analyzeText, analyzeImage
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from functools import wraps, partial
|
from functools import wraps, partial
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
Version, version, __version__, VERSION = ('0.9.1',) * 4
|
Version, version, __version__, VERSION = ('0.9.2',) * 4
|
||||||
|
|
||||||
JSON_HEADERS = {
|
JSON_HEADERS = {
|
||||||
'Content-type': 'application/json',
|
'Content-type': 'application/json',
|
||||||
@@ -22,7 +22,7 @@ from indicoio.images.features import facial_features
|
|||||||
from indicoio.images.faciallocalization import facial_localization
|
from indicoio.images.faciallocalization import facial_localization
|
||||||
from indicoio.images.features import image_features
|
from indicoio.images.features import image_features
|
||||||
from indicoio.images.filtering import content_filtering
|
from indicoio.images.filtering import content_filtering
|
||||||
from indicoio.utils.multi import predict_image, predict_text
|
from indicoio.utils.multi import analyze_image, analyze_text, intersections
|
||||||
|
|
||||||
from indicoio.config import API_NAMES
|
from indicoio.config import API_NAMES
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -63,7 +63,13 @@ IMAGE_APIS = [
|
|||||||
'content_filtering'
|
'content_filtering'
|
||||||
]
|
]
|
||||||
|
|
||||||
API_NAMES = IMAGE_APIS + TEXT_APIS + ["predict_text", "predict_image"]
|
OTHER_APIS = [
|
||||||
|
"analyze_text",
|
||||||
|
"analyze_image",
|
||||||
|
"intersections"
|
||||||
|
]
|
||||||
|
|
||||||
|
API_NAMES = IMAGE_APIS + TEXT_APIS + OTHER_APIS
|
||||||
|
|
||||||
SETTINGS = Settings(files=[
|
SETTINGS = Settings(files=[
|
||||||
os.path.expanduser("~/.indicorc"),
|
os.path.expanduser("~/.indicorc"),
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ def api_handler(arg, cloud, api, url_params=None, **kwargs):
|
|||||||
cloud = cloud or config.cloud
|
cloud = cloud or config.cloud
|
||||||
host = "%s.indico.domains" % cloud if cloud else config.PUBLIC_API_HOST
|
host = "%s.indico.domains" % cloud if cloud else config.PUBLIC_API_HOST
|
||||||
url = create_url(host, api, url_params)
|
url = create_url(host, api, url_params)
|
||||||
|
|
||||||
response = requests.post(url, data=json_data, headers=JSON_HEADERS)
|
response = requests.post(url, data=json_data, headers=JSON_HEADERS)
|
||||||
|
|
||||||
if response.status_code == 503 and cloud != None:
|
if response.status_code == 503 and cloud != None:
|
||||||
|
|||||||
+54
-15
@@ -11,19 +11,59 @@ AVAILABLE_APIS = {
|
|||||||
'image': IMAGE_APIS
|
'image': IMAGE_APIS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def invert_dictionary(d):
|
||||||
|
return {
|
||||||
|
element: key for key, values in d.iteritems()
|
||||||
|
for element in values
|
||||||
|
}
|
||||||
|
|
||||||
|
API_TYPES = invert_dictionary(AVAILABLE_APIS)
|
||||||
|
|
||||||
|
|
||||||
|
def intersections(data, apis = None, **kwargs):
|
||||||
|
"""
|
||||||
|
Helper to make multi requests of different types.
|
||||||
|
|
||||||
|
:param data: Data to be sent in API request
|
||||||
|
:param type: String type of API request
|
||||||
|
:rtype: Dictionary of api responses
|
||||||
|
"""
|
||||||
|
# Client side api name checking
|
||||||
|
|
||||||
|
# remove auto-inserted batch param
|
||||||
|
kwargs.pop('batch', None)
|
||||||
|
|
||||||
|
if not isinstance(apis, list) or len(apis) != 2:
|
||||||
|
raise IndicoError("Argument 'apis' must be of length 2")
|
||||||
|
if isinstance(data, list) and len(data) < 3:
|
||||||
|
raise IndicoError(
|
||||||
|
"At least 3 examples are required to use the intersections API"
|
||||||
|
)
|
||||||
|
|
||||||
|
api_types = map(API_TYPES.get, apis)
|
||||||
|
if api_types[0] != api_types[1]:
|
||||||
|
raise IndicoError(
|
||||||
|
"Both `apis` must accept the same kind of input to use the intersections API"
|
||||||
|
)
|
||||||
|
|
||||||
|
cloud = kwargs.get("cloud", None)
|
||||||
|
|
||||||
|
url_params = {
|
||||||
|
'batch': False,
|
||||||
|
'api_key': kwargs.pop('api_key', None),
|
||||||
|
'apis': apis
|
||||||
|
}
|
||||||
|
|
||||||
|
return api_handler(data, cloud=cloud, api="apis/intersections", url_params=url_params, **kwargs)
|
||||||
|
|
||||||
def multi(data, datatype, apis, batch=False, **kwargs):
|
def multi(data, datatype, apis, batch=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
Helper to make multi requests of different types.
|
Helper to make multi requests of different types.
|
||||||
|
|
||||||
:param data: data to be sent in JSON.
|
:param data: Data to be sent in API request
|
||||||
:param type: String type of API request
|
:param datatype: String type of API request
|
||||||
:param apis: List of apis to use.
|
:param apis: List of apis to use.
|
||||||
:param apis: List of apis available for use.
|
:param batch: Is this a batch request?
|
||||||
: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
|
:rtype: Dictionary of api responses
|
||||||
"""
|
"""
|
||||||
# Client side api name checking - strictly only accept func name api
|
# Client side api name checking - strictly only accept func name api
|
||||||
@@ -36,13 +76,12 @@ def multi(data, datatype, apis, batch=False, **kwargs):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Convert client api names to server names before sending request
|
# Convert client api names to server names before sending request
|
||||||
apis = map(CLIENT_SERVER_MAP.get, apis)
|
|
||||||
cloud = kwargs.pop("cloud", None)
|
cloud = kwargs.pop("cloud", None)
|
||||||
api_key = kwargs.pop('api_key', None)
|
api_key = kwargs.pop('api_key', None)
|
||||||
result = api_handler(
|
result = api_handler(
|
||||||
data,
|
data,
|
||||||
cloud=cloud,
|
cloud=cloud,
|
||||||
api='apis',
|
api='apis/multiapi',
|
||||||
url_params={
|
url_params={
|
||||||
"apis":apis,
|
"apis":apis,
|
||||||
"batch":batch,
|
"batch":batch,
|
||||||
@@ -55,11 +94,11 @@ def multi(data, datatype, apis, batch=False, **kwargs):
|
|||||||
|
|
||||||
def handle_response(result):
|
def handle_response(result):
|
||||||
# Parse out the results to a dicionary of api: result
|
# Parse out the results to a dicionary of api: result
|
||||||
return dict((SERVER_CLIENT_MAP[api], parsed_response(api, res))
|
return dict((api, parsed_response(api, res))
|
||||||
for api, res in result.iteritems())
|
for api, res in result.iteritems())
|
||||||
|
|
||||||
|
|
||||||
def predict_text(input_text, apis=TEXT_APIS, **kwargs):
|
def analyze_text(input_text, apis=TEXT_APIS, **kwargs):
|
||||||
"""
|
"""
|
||||||
Given input text, returns the results of specified text apis. Possible apis
|
Given input text, returns the results of specified text apis. Possible apis
|
||||||
include: [ 'text_tags', 'political', 'sentiment', 'language' ]
|
include: [ 'text_tags', 'political', 'sentiment', 'language' ]
|
||||||
@@ -70,8 +109,8 @@ def predict_text(input_text, apis=TEXT_APIS, **kwargs):
|
|||||||
|
|
||||||
>>> import indicoio
|
>>> import indicoio
|
||||||
>>> text = 'Monday: Delightful with mostly sunny skies. Highs in the low 70s.'
|
>>> text = 'Monday: Delightful with mostly sunny skies. Highs in the low 70s.'
|
||||||
>>> results = indicoio.text(data = text, apis = ["language", "sentiment"])
|
>>> results = indicoio.analyze_text(data = text, apis = ["language", "sentiment"])
|
||||||
>>> language_results = results["langauge"]
|
>>> language_results = results["language"]
|
||||||
>>> sentiment_results = results["sentiment"]
|
>>> sentiment_results = results["sentiment"]
|
||||||
|
|
||||||
:param text: The text to be analyzed.
|
:param text: The text to be analyzed.
|
||||||
@@ -96,7 +135,7 @@ def predict_text(input_text, apis=TEXT_APIS, **kwargs):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def predict_image(image, apis=IMAGE_APIS, **kwargs):
|
def analyze_image(image, apis=IMAGE_APIS, **kwargs):
|
||||||
"""
|
"""
|
||||||
Given input image, returns the results of specified image apis. Possible apis
|
Given input image, returns the results of specified image apis. Possible apis
|
||||||
include: ['fer', 'facial_features', 'image_features']
|
include: ['fer', 'facial_features', 'image_features']
|
||||||
@@ -108,7 +147,7 @@ def predict_image(image, apis=IMAGE_APIS, **kwargs):
|
|||||||
>>> import indicoio
|
>>> import indicoio
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
>>> face = np.zeros((48,48)).tolist()
|
>>> face = np.zeros((48,48)).tolist()
|
||||||
>>> results = indicoio.image(image = face, apis = ["fer", "facial_features"])
|
>>> results = indicoio.analyze_image(image = face, apis = ["fer", "facial_features"])
|
||||||
>>> fer = results["fer"]
|
>>> fer = results["fer"]
|
||||||
>>> facial_features = results["facial_features"]
|
>>> facial_features = results["facial_features"]
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ except ImportError:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="IndicoIo",
|
name="IndicoIo",
|
||||||
version="0.9.1",
|
version="0.9.2",
|
||||||
packages=[
|
packages=[
|
||||||
"indicoio",
|
"indicoio",
|
||||||
"indicoio.text",
|
"indicoio.text",
|
||||||
|
|||||||
+49
-9
@@ -15,7 +15,7 @@ from indicoio import keywords, batch_keywords
|
|||||||
from indicoio import sentiment_hq, batch_sentiment_hq
|
from indicoio import sentiment_hq, batch_sentiment_hq
|
||||||
from indicoio import twitter_engagement, batch_twitter_engagement
|
from indicoio import twitter_engagement, batch_twitter_engagement
|
||||||
from indicoio import named_entities, batch_named_entities
|
from indicoio import named_entities, batch_named_entities
|
||||||
from indicoio import predict_image, predict_text, batch_predict_image, batch_predict_text
|
from indicoio import intersections, analyze_image, analyze_text, batch_analyze_image, batch_analyze_text
|
||||||
from indicoio.utils.errors import IndicoError
|
from indicoio.utils.errors import IndicoError
|
||||||
|
|
||||||
DIR = os.path.dirname(os.path.realpath(__file__))
|
DIR = os.path.dirname(os.path.realpath(__file__))
|
||||||
@@ -158,7 +158,7 @@ class BatchAPIRun(unittest.TestCase):
|
|||||||
def test_batch_multi_api_image(self):
|
def test_batch_multi_api_image(self):
|
||||||
test_data = [os.path.normpath(os.path.join(DIR, "data/48by48.png")),
|
test_data = [os.path.normpath(os.path.join(DIR, "data/48by48.png")),
|
||||||
os.path.normpath(os.path.join(DIR, "data/48by48.png"))]
|
os.path.normpath(os.path.join(DIR, "data/48by48.png"))]
|
||||||
response = predict_image(test_data, apis=config.IMAGE_APIS, api_key=self.api_key)
|
response = analyze_image(test_data, apis=config.IMAGE_APIS, api_key=self.api_key)
|
||||||
|
|
||||||
self.assertTrue(isinstance(response, dict))
|
self.assertTrue(isinstance(response, dict))
|
||||||
self.assertTrue(set(response.keys()) == set(config.IMAGE_APIS))
|
self.assertTrue(set(response.keys()) == set(config.IMAGE_APIS))
|
||||||
@@ -166,32 +166,32 @@ class BatchAPIRun(unittest.TestCase):
|
|||||||
|
|
||||||
def test_batch_multi_api_text(self):
|
def test_batch_multi_api_text(self):
|
||||||
test_data = ['clearly an english sentence']
|
test_data = ['clearly an english sentence']
|
||||||
response = predict_text(test_data, apis=config.TEXT_APIS, api_key=self.api_key)
|
response = analyze_text(test_data, apis=config.TEXT_APIS, api_key=self.api_key)
|
||||||
|
|
||||||
self.assertTrue(isinstance(response, dict))
|
self.assertTrue(isinstance(response, dict))
|
||||||
self.assertTrue(set(response.keys()) == set(config.TEXT_APIS))
|
self.assertTrue(set(response.keys()) == set(config.TEXT_APIS))
|
||||||
|
|
||||||
def test_default_multi_api_text(self):
|
def test_default_multi_api_text(self):
|
||||||
test_data = ['clearly an english sentence']
|
test_data = ['clearly an english sentence']
|
||||||
response = predict_text(test_data, api_key=self.api_key)
|
response = analyze_text(test_data, api_key=self.api_key)
|
||||||
|
|
||||||
self.assertTrue(isinstance(response, dict))
|
self.assertTrue(isinstance(response, dict))
|
||||||
self.assertTrue(set(response.keys()) == set(config.TEXT_APIS))
|
self.assertTrue(set(response.keys()) == set(config.TEXT_APIS))
|
||||||
|
|
||||||
def test_multi_api_bad_api(self):
|
def test_multi_api_bad_api(self):
|
||||||
self.assertRaises(IndicoError,
|
self.assertRaises(IndicoError,
|
||||||
predict_text,
|
analyze_text,
|
||||||
"this shouldn't work",
|
"this shouldn't work",
|
||||||
apis=["sentiment", "somethingbad"])
|
apis=["sentiment", "somethingbad"])
|
||||||
|
|
||||||
def test_multi_bad_mixed_api(self):
|
def test_multi_bad_mixed_api(self):
|
||||||
self.assertRaises(IndicoError,
|
self.assertRaises(IndicoError,
|
||||||
predict_text,
|
analyze_text,
|
||||||
"this shouldn't work",
|
"this shouldn't work",
|
||||||
apis=["fer", "sentiment", "facial_features"])
|
apis=["fer", "sentiment", "facial_features"])
|
||||||
def test_batch_multi_bad_mixed_api(self):
|
def test_batch_multi_bad_mixed_api(self):
|
||||||
self.assertRaises(IndicoError,
|
self.assertRaises(IndicoError,
|
||||||
predict_text,
|
analyze_text,
|
||||||
["this shouldn't work"],
|
["this shouldn't work"],
|
||||||
apis=["fer", "sentiment", "facial_features"])
|
apis=["fer", "sentiment", "facial_features"])
|
||||||
|
|
||||||
@@ -470,18 +470,58 @@ class FullAPIRun(unittest.TestCase):
|
|||||||
|
|
||||||
def test_multi_api_image(self):
|
def test_multi_api_image(self):
|
||||||
test_data = os.path.normpath(os.path.join(DIR, "data/48by48.png"))
|
test_data = os.path.normpath(os.path.join(DIR, "data/48by48.png"))
|
||||||
response = predict_image(test_data, apis=config.IMAGE_APIS, api_key=self.api_key)
|
response = analyze_image(test_data, apis=config.IMAGE_APIS, api_key=self.api_key)
|
||||||
|
|
||||||
self.assertTrue(isinstance(response, dict))
|
self.assertTrue(isinstance(response, dict))
|
||||||
self.assertTrue(set(response.keys()) == set(config.IMAGE_APIS))
|
self.assertTrue(set(response.keys()) == set(config.IMAGE_APIS))
|
||||||
|
|
||||||
def test_multi_api_text(self):
|
def test_multi_api_text(self):
|
||||||
test_data = 'clearly an english sentence'
|
test_data = 'clearly an english sentence'
|
||||||
response = predict_text(test_data, apis=config.TEXT_APIS, api_key=self.api_key)
|
response = analyze_text(test_data, apis=config.TEXT_APIS, api_key=self.api_key)
|
||||||
|
|
||||||
self.assertTrue(isinstance(response, dict))
|
self.assertTrue(isinstance(response, dict))
|
||||||
self.assertTrue(set(response.keys()) == set(config.TEXT_APIS))
|
self.assertTrue(set(response.keys()) == set(config.TEXT_APIS))
|
||||||
|
|
||||||
|
def test_intersections_not_enough_data(self):
|
||||||
|
test_data = ['test_Data']
|
||||||
|
self.assertRaises(
|
||||||
|
IndicoError,
|
||||||
|
intersections,
|
||||||
|
test_data,
|
||||||
|
apis=['text_tags', 'sentiment']
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_intersections_wrong_number_of_apis(self):
|
||||||
|
test_data = ['test data']*3
|
||||||
|
self.assertRaises(
|
||||||
|
IndicoError,
|
||||||
|
intersections,
|
||||||
|
test_data,
|
||||||
|
apis=['text_tags', 'sentiment', 'language']
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_intersections_bad_api_type(self):
|
||||||
|
test_data = ['test data']*3
|
||||||
|
self.assertRaises(
|
||||||
|
IndicoError,
|
||||||
|
intersections,
|
||||||
|
test_data,
|
||||||
|
apis=['text_tags', 'fer']
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_intersections_valid_input(self):
|
||||||
|
test_data = ['test data']*3
|
||||||
|
apis = ['text_tags', 'sentiment']
|
||||||
|
results = intersections(test_data, apis=apis)
|
||||||
|
assert set(results.keys()) < set(apis)
|
||||||
|
|
||||||
|
def test_intersections_valid_raw_input(self):
|
||||||
|
test_data = {
|
||||||
|
'sentiment': [0.1, 0.2, 0.3],
|
||||||
|
'twitter_engagement': [0.1, 0.2, 0.3]
|
||||||
|
}
|
||||||
|
results = intersections(test_data, apis=['sentiment', 'twitter_engagement'])
|
||||||
|
assert set(results.keys()) < set(test_data.keys())
|
||||||
|
|
||||||
def test_language(self):
|
def test_language(self):
|
||||||
language_set = set([
|
language_set = set([
|
||||||
|
|||||||
Reference in New Issue
Block a user