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.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.2 Fri Aug 14 -- Add intersections API, analyzeText, analyzeImage
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from functools import wraps, partial
|
||||
import warnings
|
||||
|
||||
Version, version, __version__, VERSION = ('0.9.1',) * 4
|
||||
Version, version, __version__, VERSION = ('0.9.2',) * 4
|
||||
|
||||
JSON_HEADERS = {
|
||||
'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.features import image_features
|
||||
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
|
||||
|
||||
|
||||
+7
-1
@@ -63,7 +63,13 @@ IMAGE_APIS = [
|
||||
'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=[
|
||||
os.path.expanduser("~/.indicorc"),
|
||||
|
||||
@@ -19,7 +19,6 @@ def api_handler(arg, cloud, api, url_params=None, **kwargs):
|
||||
cloud = cloud or config.cloud
|
||||
host = "%s.indico.domains" % cloud if cloud else config.PUBLIC_API_HOST
|
||||
url = create_url(host, api, url_params)
|
||||
|
||||
response = requests.post(url, data=json_data, headers=JSON_HEADERS)
|
||||
|
||||
if response.status_code == 503 and cloud != None:
|
||||
|
||||
+54
-15
@@ -11,19 +11,59 @@ AVAILABLE_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):
|
||||
"""
|
||||
Helper to make multi requests of different types.
|
||||
|
||||
:param data: data to be sent in JSON.
|
||||
:param type: String type of API request
|
||||
:param data: Data to be sent in API request
|
||||
:param datatype: 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
|
||||
:param batch: Is this a batch request?
|
||||
:rtype: Dictionary of api responses
|
||||
"""
|
||||
# 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
|
||||
apis = map(CLIENT_SERVER_MAP.get, apis)
|
||||
cloud = kwargs.pop("cloud", None)
|
||||
api_key = kwargs.pop('api_key', None)
|
||||
result = api_handler(
|
||||
data,
|
||||
cloud=cloud,
|
||||
api='apis',
|
||||
api='apis/multiapi',
|
||||
url_params={
|
||||
"apis":apis,
|
||||
"batch":batch,
|
||||
@@ -55,11 +94,11 @@ def multi(data, datatype, apis, batch=False, **kwargs):
|
||||
|
||||
def handle_response(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())
|
||||
|
||||
|
||||
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
|
||||
include: [ 'text_tags', 'political', 'sentiment', 'language' ]
|
||||
@@ -70,8 +109,8 @@ def predict_text(input_text, apis=TEXT_APIS, **kwargs):
|
||||
|
||||
>>> 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"]
|
||||
>>> results = indicoio.analyze_text(data = text, apis = ["language", "sentiment"])
|
||||
>>> language_results = results["language"]
|
||||
>>> sentiment_results = results["sentiment"]
|
||||
|
||||
: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
|
||||
include: ['fer', 'facial_features', 'image_features']
|
||||
@@ -108,7 +147,7 @@ def predict_image(image, apis=IMAGE_APIS, **kwargs):
|
||||
>>> import indicoio
|
||||
>>> import numpy as np
|
||||
>>> 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"]
|
||||
>>> facial_features = results["facial_features"]
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ except ImportError:
|
||||
|
||||
setup(
|
||||
name="IndicoIo",
|
||||
version="0.9.1",
|
||||
version="0.9.2",
|
||||
packages=[
|
||||
"indicoio",
|
||||
"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 twitter_engagement, batch_twitter_engagement
|
||||
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
|
||||
|
||||
DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
@@ -158,7 +158,7 @@ class BatchAPIRun(unittest.TestCase):
|
||||
def test_batch_multi_api_image(self):
|
||||
test_data = [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(set(response.keys()) == set(config.IMAGE_APIS))
|
||||
@@ -166,32 +166,32 @@ class BatchAPIRun(unittest.TestCase):
|
||||
|
||||
def test_batch_multi_api_text(self):
|
||||
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(set(response.keys()) == set(config.TEXT_APIS))
|
||||
|
||||
def test_default_multi_api_text(self):
|
||||
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(set(response.keys()) == set(config.TEXT_APIS))
|
||||
|
||||
def test_multi_api_bad_api(self):
|
||||
self.assertRaises(IndicoError,
|
||||
predict_text,
|
||||
analyze_text,
|
||||
"this shouldn't work",
|
||||
apis=["sentiment", "somethingbad"])
|
||||
|
||||
def test_multi_bad_mixed_api(self):
|
||||
self.assertRaises(IndicoError,
|
||||
predict_text,
|
||||
analyze_text,
|
||||
"this shouldn't work",
|
||||
apis=["fer", "sentiment", "facial_features"])
|
||||
def test_batch_multi_bad_mixed_api(self):
|
||||
self.assertRaises(IndicoError,
|
||||
predict_text,
|
||||
analyze_text,
|
||||
["this shouldn't work"],
|
||||
apis=["fer", "sentiment", "facial_features"])
|
||||
|
||||
@@ -470,18 +470,58 @@ class FullAPIRun(unittest.TestCase):
|
||||
|
||||
def test_multi_api_image(self):
|
||||
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(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)
|
||||
response = analyze_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_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):
|
||||
language_set = set([
|
||||
|
||||
Reference in New Issue
Block a user