mirror of
https://github.com/wassname/IndicoIo-python.git
synced 2026-08-10 11:50:18 +08:00
Merge pull request #65 from IndicoDataSolutions/development
Development
This commit is contained in:
@@ -24,3 +24,4 @@ v0.5.2, Tue March 7 -- Required API keys, configuration settings
|
|||||||
v0.5.3, Wed Apr 15 -- Added scipy to requirements, edited Readme to not break pypi page
|
v0.5.3, Wed Apr 15 -- Added scipy to requirements, edited Readme to not break pypi page
|
||||||
v0.6.0, Thu May 29 -- Remove numpy / scipy dependency in favor of Pillow
|
v0.6.0, Thu May 29 -- Remove numpy / scipy dependency in favor of Pillow
|
||||||
v0.7.0, Tue Jun 9 -- Added support for calling multiple APIs in a single function and accepting filenames as image API inputs
|
v0.7.0, Tue Jun 9 -- Added support for calling multiple APIs in a single function and accepting filenames as image API inputs
|
||||||
|
v0.7.1 Thu Jun 11 -- High quality sentiment API for private beta, fix for multi API support
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
Version, version, __version__, VERSION = ('0.7.0',) * 4
|
Version, version, __version__, VERSION = ('0.7.1',) * 4
|
||||||
|
|
||||||
JSON_HEADERS = {
|
JSON_HEADERS = {
|
||||||
'Content-type': 'application/json',
|
'Content-type': 'application/json',
|
||||||
@@ -9,7 +9,7 @@ JSON_HEADERS = {
|
|||||||
'version-number': VERSION
|
'version-number': VERSION
|
||||||
}
|
}
|
||||||
|
|
||||||
from indicoio.text.sentiment import political, posneg
|
from indicoio.text.sentiment import political, posneg, sentiment_hq
|
||||||
from indicoio.text.sentiment import posneg as sentiment
|
from indicoio.text.sentiment import posneg as sentiment
|
||||||
from indicoio.text.lang import language
|
from indicoio.text.lang import language
|
||||||
from indicoio.text.tagging import text_tags
|
from indicoio.text.tagging import text_tags
|
||||||
|
|||||||
+2
-1
@@ -49,7 +49,8 @@ TEXT_APIS = [
|
|||||||
'text_tags',
|
'text_tags',
|
||||||
'political',
|
'political',
|
||||||
'sentiment',
|
'sentiment',
|
||||||
'language'
|
'language',
|
||||||
|
'sentiment_hq'
|
||||||
]
|
]
|
||||||
|
|
||||||
IMAGE_APIS = [
|
IMAGE_APIS = [
|
||||||
|
|||||||
@@ -50,3 +50,26 @@ def posneg(text, cloud=None, batch=False, api_key=None, **kwargs):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
return api_handler(text, cloud=cloud, api="sentiment", url_params={"batch":batch, "api_key":api_key}, **kwargs)
|
return api_handler(text, cloud=cloud, api="sentiment", url_params={"batch":batch, "api_key":api_key}, **kwargs)
|
||||||
|
|
||||||
|
def sentiment_hq(text, cloud=None, batch=False, api_key=None, **kwargs):
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
For reference, 0 suggests very negative sentiment and 1 suggests very positive sentiment.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> from indicoio import sentimenthq
|
||||||
|
>>> text = 'Thanks everyone for the birthday wishes!! It was a crazy few days ><'
|
||||||
|
>>> sentiment = sentimenthq(text)
|
||||||
|
>>> sentiment
|
||||||
|
0.6210052967071533
|
||||||
|
|
||||||
|
:param text: The text to be analyzed.
|
||||||
|
:type text: str or unicode
|
||||||
|
:rtype: Float
|
||||||
|
"""
|
||||||
|
|
||||||
|
return api_handler(text, cloud=cloud, api="sentimenthq", url_params={"batch":batch, "api_key":api_key}, **kwargs)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ def api_handler(arg, cloud, api, url_params = {"batch":False, "api_key":None}, *
|
|||||||
|
|
||||||
if cloud:
|
if cloud:
|
||||||
host = "%s.indico.domains" % cloud
|
host = "%s.indico.domains" % cloud
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# default to indico public cloud
|
# default to indico public cloud
|
||||||
host = config.PUBLIC_API_HOST
|
host = config.PUBLIC_API_HOST
|
||||||
@@ -24,8 +25,14 @@ def api_handler(arg, cloud, api, url_params = {"batch":False, "api_key":None}, *
|
|||||||
url = config.url_protocol + "//%s/%s" % (host, api)
|
url = config.url_protocol + "//%s/%s" % (host, api)
|
||||||
url = url + "/batch" if url_params.get("batch", False) else url
|
url = url + "/batch" if url_params.get("batch", False) else url
|
||||||
url += "?key=%s" % (url_params.get("api_key", None) or config.api_key)
|
url += "?key=%s" % (url_params.get("api_key", None) or config.api_key)
|
||||||
if "apis" in url_params:
|
apis = url_params.get("apis", [])
|
||||||
url += "&apis=%s" % ",".join(url_params["apis"])
|
if apis:
|
||||||
|
url += "&apis=%s" % ",".join(apis)
|
||||||
|
|
||||||
|
# private beta
|
||||||
|
if host == config.PUBLIC_API_HOST:
|
||||||
|
if (api == 'sentimenthq') or ('sentimenthq' in apis):
|
||||||
|
raise IndicoError("The high quality sentiment API is currently in private beta.")
|
||||||
|
|
||||||
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:
|
||||||
|
|||||||
+41
-15
@@ -6,8 +6,12 @@ from indicoio.utils.errors import IndicoError
|
|||||||
|
|
||||||
CLIENT_SERVER_MAP = dict((api, api.strip().replace("_", "").lower()) for api in API_NAMES)
|
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())
|
SERVER_CLIENT_MAP = dict((v, k) for k, v in CLIENT_SERVER_MAP.iteritems())
|
||||||
|
AVAILABLE_APIS = {
|
||||||
|
'text': TEXT_APIS,
|
||||||
|
'image': IMAGE_APIS
|
||||||
|
}
|
||||||
|
|
||||||
def multi(data, type, apis, available, 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.
|
||||||
|
|
||||||
@@ -22,23 +26,39 @@ def multi(data, type, apis, available, batch=False, **kwargs):
|
|||||||
: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
|
||||||
|
available = AVAILABLE_APIS.get(datatype)
|
||||||
invalid_apis = [api for api in apis if api not in available]
|
invalid_apis = [api for api in apis if api not in available]
|
||||||
if invalid_apis:
|
if invalid_apis:
|
||||||
raise IndicoError("%s are not valid %s APIs. Please reference the available APIs below:\n%s"
|
raise IndicoError(
|
||||||
% (", ".join(invalid_apis), type, ", ".join(available))
|
"%s are not valid %s APIs. Please reference the available APIs below:\n%s"
|
||||||
)
|
% (", ".join(invalid_apis), datatype, ", ".join(available))
|
||||||
|
)
|
||||||
|
|
||||||
# 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)
|
apis = map(CLIENT_SERVER_MAP.get, apis)
|
||||||
result = api_handler(data, url_params = {"apis":apis, "batch":batch}, **kwargs)
|
cloud = kwargs.pop("cloud", None)
|
||||||
|
api_key = kwargs.pop('api_key', None)
|
||||||
|
result = api_handler(
|
||||||
|
data,
|
||||||
|
cloud=cloud,
|
||||||
|
api='apis',
|
||||||
|
url_params={
|
||||||
|
"apis":apis,
|
||||||
|
"batch":batch,
|
||||||
|
"api_key":api_key
|
||||||
|
},
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
return handle_response(result)
|
return handle_response(result)
|
||||||
|
|
||||||
|
|
||||||
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((SERVER_CLIENT_MAP[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, cloud=None, batch=False, api_key=None, **kwargs):
|
def predict_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' ]
|
||||||
@@ -60,19 +80,22 @@ def predict_text(input_text, apis=TEXT_APIS, cloud=None, batch=False, api_key=No
|
|||||||
:rtype: Dictionary of api responses
|
:rtype: Dictionary of api responses
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
cloud = kwargs.pop('cloud', None)
|
||||||
|
batch = kwargs.pop('batch', False)
|
||||||
|
api_key = kwargs.pop('api_key', None)
|
||||||
|
|
||||||
return multi(
|
return multi(
|
||||||
api="apis",
|
|
||||||
data=input_text,
|
data=input_text,
|
||||||
type="text",
|
datatype="text",
|
||||||
available = TEXT_APIS,
|
|
||||||
cloud=cloud,
|
cloud=cloud,
|
||||||
batch=batch,
|
batch=batch,
|
||||||
api_key=api_key,
|
api_key=api_key,
|
||||||
apis=apis,
|
apis=apis,
|
||||||
**kwargs)
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def predict_image(image, apis=IMAGE_APIS, cloud=None, batch=False, api_key=None, **kwargs):
|
def predict_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']
|
||||||
@@ -95,16 +118,19 @@ def predict_image(image, apis=IMAGE_APIS, cloud=None, batch=False, api_key=None,
|
|||||||
:rtype: Dictionary of api responses
|
:rtype: Dictionary of api responses
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
cloud = kwargs.pop('cloud', None)
|
||||||
|
batch = kwargs.pop('batch', False)
|
||||||
|
api_key = kwargs.pop('api_key', None)
|
||||||
|
|
||||||
return multi(
|
return multi(
|
||||||
api="apis",
|
|
||||||
data=image_preprocess(image, batch=batch),
|
data=image_preprocess(image, batch=batch),
|
||||||
type="image",
|
datatype="image",
|
||||||
available=IMAGE_APIS,
|
|
||||||
cloud=cloud,
|
cloud=cloud,
|
||||||
batch=batch,
|
batch=batch,
|
||||||
api_key=api_key,
|
api_key=api_key,
|
||||||
apis=apis,
|
apis=apis,
|
||||||
**kwargs)
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
def parsed_response(api, response):
|
def parsed_response(api, response):
|
||||||
result = response.get('results', False)
|
result = response.get('results', False)
|
||||||
|
|||||||
@@ -9,9 +9,13 @@ from indicoio import config
|
|||||||
from indicoio import political, sentiment, fer, facial_features, language, image_features, text_tags
|
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_political, batch_sentiment, batch_fer, batch_facial_features
|
||||||
from indicoio import batch_language, batch_image_features, batch_text_tags
|
from indicoio import batch_language, batch_image_features, batch_text_tags
|
||||||
|
from indicoio import sentiment_hq, batch_sentiment_hq
|
||||||
from indicoio import predict_image, predict_text, batch_predict_image, batch_predict_text
|
from indicoio import predict_image, predict_text, batch_predict_image, batch_predict_text
|
||||||
from indicoio.utils.errors import IndicoError
|
from indicoio.utils.errors import IndicoError
|
||||||
|
|
||||||
|
# TODO: remove once sentiment_hq is added to the public API
|
||||||
|
config.TEXT_APIS.remove("sentiment_hq")
|
||||||
|
|
||||||
DIR = os.path.dirname(os.path.realpath(__file__))
|
DIR = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
class BatchAPIRun(unittest.TestCase):
|
class BatchAPIRun(unittest.TestCase):
|
||||||
@@ -37,6 +41,13 @@ class BatchAPIRun(unittest.TestCase):
|
|||||||
self.assertTrue(isinstance(response, list))
|
self.assertTrue(isinstance(response, list))
|
||||||
self.assertTrue(response[0] < 0.5)
|
self.assertTrue(response[0] < 0.5)
|
||||||
|
|
||||||
|
# TODO: uncomment once the high quality sentiment API is publicly released
|
||||||
|
# def test_batch_sentiment_hq(self):
|
||||||
|
# test_data = ['Worst song ever', 'Best song ever']
|
||||||
|
# response = batch_sentiment_hq(test_data, api_key=self.api_key)
|
||||||
|
# self.assertTrue(isinstance(response, list))
|
||||||
|
# self.assertTrue(response[0] < 0.5)
|
||||||
|
|
||||||
def test_batch_political(self):
|
def test_batch_political(self):
|
||||||
test_data = ["Guns don't kill people, people kill people."]
|
test_data = ["Guns don't kill people, people kill people."]
|
||||||
response = batch_political(test_data, api_key=self.api_key)
|
response = batch_political(test_data, api_key=self.api_key)
|
||||||
@@ -220,6 +231,19 @@ class FullAPIRun(unittest.TestCase):
|
|||||||
self.assertTrue(isinstance(response, float))
|
self.assertTrue(isinstance(response, float))
|
||||||
self.assertTrue(response > 0.5)
|
self.assertTrue(response > 0.5)
|
||||||
|
|
||||||
|
# TODO: uncomment when the high quality sentiment API is publicly released
|
||||||
|
# def test_sentiment_hq(self):
|
||||||
|
# test_string = "Worst song ever."
|
||||||
|
# response = sentiment_hq(test_string)
|
||||||
|
|
||||||
|
# self.assertTrue(isinstance(response, float))
|
||||||
|
# self.assertTrue(response < 0.5)
|
||||||
|
|
||||||
|
# test_string = "Best song ever."
|
||||||
|
# response = sentiment_hq(test_string)
|
||||||
|
# self.assertTrue(isinstance(response, float))
|
||||||
|
# self.assertTrue(response > 0.5)
|
||||||
|
|
||||||
def test_good_fer(self):
|
def test_good_fer(self):
|
||||||
fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy'])
|
fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy'])
|
||||||
test_face = generate_array((48,48))
|
test_face = generate_array((48,48))
|
||||||
|
|||||||
Reference in New Issue
Block a user