Commit 79c83e34 authored by J. Fernando Sánchez's avatar J. Fernando Sánchez
Browse files

Added random plugin and other features

parent 37a09810
import json
import random
from senpy.plugins import SentimentPlugin
from senpy.models import Response, Opinion, Entry
class Sentiment140Plugin(SentimentPlugin):
def analyse(self, **params):
lang = params.get("language", "auto")
p = params.get("prefix", None)
response = Response(prefix=p)
#polarity_value = self.maxPolarityValue*int(res.json()["data"][0]["polarity"]) * 0.25
polarity_value = max(-1, min(1, random.gauss(0.2,0.2)))
polarity = "marl:Neutral"
if polarity_value > 0:
polarity = "marl:Positive"
elif polarity_value < 0:
polarity = "marl:Negative"
entry = Entry(id="Entry0",
text=params["input"],
prefix=p)
opinion = Opinion(id="Opinion0",
prefix=p,
hasPolarity=polarity,
polarityValue=polarity_value)
opinion["prov:wasGeneratedBy"] = self.id
entry.opinions.append(opinion)
entry.language = lang
response.entries.append(entry)
return response
{
"name": "rand",
"module": "rand",
"description": "What my plugin broadly does",
"author": "@balkian",
"version": "0.1",
"extra_params": {
"language": {
"aliases": ["language", "l"],
"required": false,
"options": ["es", "en", "auto"]
}
},
"requirements": {},
"marl:maxPolarityValue": "1",
"marl:minPolarityValue": "-1"
}
...@@ -15,15 +15,19 @@ class Sentiment140Plugin(SentimentPlugin): ...@@ -15,15 +15,19 @@ class Sentiment140Plugin(SentimentPlugin):
) )
) )
response = Response(base=params.get("prefix", None)) p = params.get("prefix", None)
polarity_value = int(res.json()["data"][0]["polarity"]) * 25 response = Response(prefix=p)
polarity_value = self.maxPolarityValue*int(res.json()["data"][0]["polarity"]) * 0.25
polarity = "marl:Neutral" polarity = "marl:Neutral"
if polarity_value > 50: if polarity_value > 50:
polarity = "marl:Positive" polarity = "marl:Positive"
elif polarity_value < 50: elif polarity_value < 50:
polarity = "marl:Negative" polarity = "marl:Negative"
entry = Entry(id="Entry0", text=params["input"]) entry = Entry(id="Entry0",
text=params["input"],
prefix=p)
opinion = Opinion(id="Opinion0", opinion = Opinion(id="Opinion0",
prefix=p,
hasPolarity=polarity, hasPolarity=polarity,
polarityValue=polarity_value) polarityValue=polarity_value)
opinion["prov:wasGeneratedBy"] = self.id opinion["prov:wasGeneratedBy"] = self.id
......
...@@ -11,5 +11,7 @@ ...@@ -11,5 +11,7 @@
"options": ["es", "en", "auto"] "options": ["es", "en", "auto"]
} }
}, },
"requirements": {} "requirements": {},
"maxPolarityValue": "1",
"minPolarityValue": "0"
} }
...@@ -3,4 +3,5 @@ gunicorn==19.0.0 ...@@ -3,4 +3,5 @@ gunicorn==19.0.0
requests==2.4.1 requests==2.4.1
GitPython==0.3.2.RC1 GitPython==0.3.2.RC1
Yapsy>=1.10.423 Yapsy>=1.10.423
gevent>=1.0.1 gevent>=1.0.1
\ No newline at end of file PyLD>=0.6.5
\ No newline at end of file
...@@ -38,8 +38,7 @@ if __name__ == '__main__': ...@@ -38,8 +38,7 @@ if __name__ == '__main__':
help='Logging level') help='Logging level')
parser.add_argument('--debug', parser.add_argument('--debug',
"-d", "-d",
metavar="debug", action='store_true',
type=bool,
default=False, default=False,
help='Run the application in debug mode') help='Run the application in debug mode')
parser.add_argument('--host', parser.add_argument('--host',
......
...@@ -62,7 +62,7 @@ def get_params(req, params=BASIC_PARAMS): ...@@ -62,7 +62,7 @@ def get_params(req, params=BASIC_PARAMS):
"parameters": outdict, "parameters": outdict,
"errors": {param: error for param, error in wrong_params.iteritems()} "errors": {param: error for param, error in wrong_params.iteritems()}
} }
raise ValueError(json.dumps(message)) raise ValueError(message)
return outdict return outdict
...@@ -88,13 +88,14 @@ def basic_analysis(params): ...@@ -88,13 +88,14 @@ def basic_analysis(params):
@nif_blueprint.route('/', methods=['POST', 'GET']) @nif_blueprint.route('/', methods=['POST', 'GET'])
def home(): def home():
try: try:
algo = get_params(request).get("algorithm", None) params = get_params(request)
algo = params.get("algorithm", None)
specific_params = current_app.senpy.parameters(algo) specific_params = current_app.senpy.parameters(algo)
params = get_params(request, specific_params) params.update(get_params(request, specific_params))
response = current_app.senpy.analyse(**params) response = current_app.senpy.analyse(**params)
return jsonify(response) return jsonify(response)
except ValueError as ex: except ValueError as ex:
return ex.message return jsonify(ex.message)
except Exception as ex: except Exception as ex:
return jsonify(status="400", message=ex.message) return jsonify(status="400", message=ex.message)
......
...@@ -12,6 +12,7 @@ import json ...@@ -12,6 +12,7 @@ import json
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
from .plugins import SenpyPlugin, SentimentPlugin, EmotionPlugin from .plugins import SenpyPlugin, SentimentPlugin, EmotionPlugin
from .models import Error
from .blueprints import nif_blueprint from .blueprints import nif_blueprint
from git import Repo, InvalidGitRepositoryError from git import Repo, InvalidGitRepositoryError
...@@ -70,12 +71,14 @@ class Senpy(object): ...@@ -70,12 +71,14 @@ class Senpy(object):
if self.plugins[algo].is_activated: if self.plugins[algo].is_activated:
plug = self.plugins[algo] plug = self.plugins[algo]
resp = plug.analyse(**params) resp = plug.analyse(**params)
resp.analysis.append(plug.jsonable()) resp.analysis.append(plug)
return resp return resp
logger.debug("Plugin not activated: {}".format(algo)) else:
logger.debug("Plugin not activated: {}".format(algo))
return Error(status=400, message="The algorithm '{}' is not activated yet".format(algo))
else: else:
logger.debug("The algorithm '{}' is not valid\nValid algorithms: {}".format(algo, self.plugins.keys())) logger.debug("The algorithm '{}' is not valid\nValid algorithms: {}".format(algo, self.plugins.keys()))
return {"status": 400, "message": "The algorithm '{}' is not valid".format(algo)} return Error(status=400, message="The algorithm '{}' is not valid".format(algo))
@property @property
def default_plugin(self): def default_plugin(self):
...@@ -156,9 +159,9 @@ class Senpy(object): ...@@ -156,9 +159,9 @@ class Senpy(object):
module = candidate(info=info) module = candidate(info=info)
try: try:
repo_path = root repo_path = root
module.repo = Repo(repo_path) module._repo = Repo(repo_path)
except InvalidGitRepositoryError: except InvalidGitRepositoryError:
module.repo = None module._repo = None
except Exception as ex: except Exception as ex:
logger.debug("Exception importing {}: {}".format(filename, ex)) logger.debug("Exception importing {}: {}".format(filename, ex))
return None, None return None, None
......
import json import json
import os import os
from collections import defaultdict from collections import defaultdict
from pyld import jsonld
class Leaf(defaultdict):
_prefix = None
def __init__(self, id=None, context=None, prefix=None, ofclass=list): class Leaf(dict):
super(Leaf, self).__init__(ofclass) _prefix = None
if context: _frame = {}
_context = {}
def __init__(self,
id=None,
context=None,
vocab=None,
prefix=None,
frame=None):
super(Leaf, self).__init__()
if context is not None:
self.context = context self.context = context
if id: elif self._context:
self.id = id self.context = self._context
else:
self.context = {}
if frame is not None:
self._frame = frame
self._prefix = prefix self._prefix = prefix
self.id = id
def __getattr__(self, key): def __getattr__(self, key):
return super(Leaf, self).__getitem__(self._get_key(key)) try:
return object.__getattr__(self, key)
except AttributeError:
try:
return super(Leaf, self).__getitem__(self._get_key(key))
except KeyError:
raise AttributeError()
def __setattr__(self, key, value): def __setattr__(self, key, value):
try: try:
...@@ -23,20 +43,40 @@ class Leaf(defaultdict): ...@@ -23,20 +43,40 @@ class Leaf(defaultdict):
object.__setattr__(self, key, value) object.__setattr__(self, key, value)
except AttributeError: except AttributeError:
key = self._get_key(key) key = self._get_key(key)
value = self.get_context(value) if key == "@context" else value if key == "@context":
value = self.get_context(value)
elif key == "@id":
value = self.get_id(value)
if key[0] == "_": if key[0] == "_":
object.__setattr__(self, key, value) object.__setattr__(self, key, value)
else: else:
super(Leaf, self).__setitem__(key, value) if value is None:
try:
super(Leaf, self).__delitem__(key)
except KeyError:
pass
else:
super(Leaf, self).__setitem__(key, value)
def get_id(self, id):
"""
This is not the most elegant solution to change the @id attribute, but it
is the quickest way to have it included in the dictionary without extra
boilerplate.
"""
if id and self._prefix and ":" not in id:
return "{}{}".format(self._prefix, id)
else:
return id
def __delattr__(self, key): def __delattr__(self, key):
return super(Leaf, self).__delitem__(self._get_key(key)) return super(Leaf, self).__delitem__(self._get_key(key))
def _get_key(self, key): def _get_key(self, key):
if key in ["context", "id"]: if key[0] == "_":
return key
elif key in ["context", "id"]:
return "@{}".format(key) return "@{}".format(key)
elif self._prefix:
return "{}:{}".format(self._prefix, key)
else: else:
return key return key
...@@ -56,55 +96,128 @@ class Leaf(defaultdict): ...@@ -56,55 +96,128 @@ class Leaf(defaultdict):
except IOError: except IOError:
return context return context
def compact(self):
return jsonld.compact(self, self.context)
def frame(self, frame=None, options=None):
if frame is None:
frame = self._frame
if options is None:
options = {}
return jsonld.frame(self, frame, options)
def jsonable(self, parameters=False, frame=None, options=None, context=None):
if frame is None:
frame = self._frame
if options is None:
options = {}
if context is None:
context = self._context
return jsonld.compact(jsonld.frame(self, frame, options), context)
#if parameters:
#resp["parameters"] = self.params
#elif self.extra_params:
#resp["extra_parameters"] = self.extra_params
#return resp
def to_JSON(self):
return json.dumps(self,
default=lambda o: o.__dict__,
sort_keys=True, indent=4)
class Response(Leaf): class Response(Leaf):
def __init__(self, context=None, base=None, *args, **kwargs): _frame = { "@context": {
"analysis": {
"@container": "@set",
"@id": "prov:wasInformedBy"
},
"date": {
"@id": "dc:date",
"@type": "xsd:dateTime"
},
"dc": "http://purl.org/dc/terms/",
"dc:subject": {
"@type": "@id"
},
"emotions": {
"@container": "@set",
"@id": "onyx:hasEmotionSet"
},
"entries": {
"@container": "@set",
"@id": "prov:generated"
},
"marl": "http://www.gsi.dit.upm.es/ontologies/marl/ns#",
"nif": "http://persistence.uni-leipzig.org/nlp2rdf/ontologies/nif-core#",
"onyx": "http://www.gsi.dit.upm.es/ontologies/onyx/ns#",
"opinions": {
"@container": "@set",
"@id": "marl:hasOpinion"
},
"prov": "http://www.w3.org/ns/prov#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"strings": {
"@container": "@set",
"@reverse": "nif:hasContext"
},
"wnaffect": "http://www.gsi.dit.upm.es/ontologies/wnaffect#",
"xsd": "http://www.w3.org/2001/XMLSchema#"
},
"analysis": {},
"entries": {}
}
def __init__(self, context=None, *args, **kwargs):
if context is None: if context is None:
context = "{}/context.jsonld".format(os.path.dirname( context = "{}/context.jsonld".format(os.path.dirname(
os.path.realpath(__file__))) os.path.realpath(__file__)))
super(Response, self).__init__(*args, context=context, **kwargs) super(Response, self).__init__(*args, context=context, **kwargs)
if base: self.analysis = []
self.context["@base"] = base self.entries = []
self["analysis"] = []
self["entries"] = []
class Entry(Leaf): class Entry(Leaf):
_context = {
"@vocab": "http://persistence.uni-leipzig.org/nlp2rdf/ontologies/nif-core#"
}
def __init__(self, text=None, emotion_sets=None, opinions=None, **kwargs): def __init__(self, text=None, emotion_sets=None, opinions=None, **kwargs):
super(Entry, self).__init__(**kwargs) super(Entry, self).__init__(**kwargs)
if text: if text:
self.text = text self.text = text
if emotion_sets: self.emotionSets = emotion_sets if emotion_sets else []
self.emotionSets = emotion_sets self.opinions = opinions if opinions else []
if opinions:
self.opinions = opinions
class Opinion(Leaf): class Opinion(Leaf):
#opinionContext = {"@vocab": "http://www.gsi.dit.upm.es/ontologies/marl/ns#"} _context = {
"@vocab": "http://www.gsi.dit.upm.es/ontologies/marl/ns#"
}
def __init__(self, polarityValue=None, hasPolarity=None, *args, **kwargs): def __init__(self, polarityValue=None, hasPolarity=None, *args, **kwargs):
super(Opinion, self).__init__( prefix="marl", super(Opinion, self).__init__(*args,
*args,
**kwargs) **kwargs)
if polarityValue is not None: if polarityValue is not None:
self.polarityValue = polarityValue self.hasPolarityValue = polarityValue
if hasPolarity is not None: if hasPolarity is not None:
self.hasPolarity = hasPolarity self.hasPolarity = hasPolarity
class EmotionSet(Leaf): class EmotionSet(Leaf):
emotionContext = {} _context = {}
def __init__(self, emotions=None, *args, **kwargs): def __init__(self, emotions=None, *args, **kwargs):
if not emotions: if not emotions:
emotions = [] emotions = []
super(EmotionSet, self).__init__(context=EmotionSet.emotionContext, super(EmotionSet, self).__init__(context=EmotionSet._context,
*args, *args,
**kwargs) **kwargs)
self.emotions = emotions or [] self.emotions = emotions or []
class Emotion(Leaf): class Emotion(Leaf):
emotionContext = {} _context = {}
def __init__(self, emotions=None, *args, **kwargs):
super(EmotionSet, self).__init__(context=Emotion.emotionContext, class Error(Leaf):
*args, def __init__(self, *args, **kwargs):
**kwargs) super(Error, self).__init__(*args)
self.update(kwargs)
import logging import logging
import ConfigParser import ConfigParser
from .models import Leaf
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -38,13 +39,24 @@ PARAMS = {"input": {"aliases": ["i", "input"], ...@@ -38,13 +39,24 @@ PARAMS = {"input": {"aliases": ["i", "input"],
} }
class SenpyPlugin(object): class SenpyPlugin(Leaf):
_context = {"@vocab": "http://www.gsi.dit.upm.es/ontologies/senpy/ns#",
"info": None}
_frame = { "@context": _context,
"name": {},
"@explicit": False,
"version": {},
"repo": None,
"info": None,
}
def __init__(self, info=None): def __init__(self, info=None):
if not info: if not info:
raise ValueError("You need to provide configuration information for the plugin.") raise ValueError("You need to provide configuration information for the plugin.")
logger.debug("Initialising {}".format(info)) logger.debug("Initialising {}".format(info))
super(SenpyPlugin, self).__init__()
self.name = info["name"] self.name = info["name"]
self.version = info["version"] self.version = info["version"]
self.id="{}_{}".format(self.name, self.version)
self.params = info.get("params", PARAMS.copy()) self.params = info.get("params", PARAMS.copy())
self.extra_params = info.get("extra_params", {}) self.extra_params = info.get("extra_params", {})
self.params.update(self.extra_params) self.params.update(self.extra_params)
...@@ -66,49 +78,15 @@ class SenpyPlugin(object): ...@@ -66,49 +78,15 @@ class SenpyPlugin(object):
def id(self): def id(self):
return "{}_{}".format(self.name, self.version) return "{}_{}".format(self.name, self.version)
def jsonable(self, parameters=False):
resp = {
"@id": "{}_{}".format(self.name, self.version),
"is_activated": self.is_activated,
}
if hasattr(self, "repo") and self.repo:
resp["repo"] = self.repo.remotes[0].url
if parameters:
resp["parameters"] = self.params
elif self.extra_params:
resp["extra_parameters"] = self.extra_params
return resp
class SentimentPlugin(SenpyPlugin): class SentimentPlugin(SenpyPlugin):
def __init__(self, def __init__(self, info, *args, **kwargs):
min_polarity_value=0, super(SentimentPlugin, self).__init__(info, *args, **kwargs)
max_polarity_value=1, self.minPolarityValue = float(info.get("minPolarityValue", 0))
**kwargs): self.maxPolarityValue = float(info.get("maxPolarityValue", 1))
super(SentimentPlugin, self).__init__(**kwargs)
self.minPolarityValue = min_polarity_value
self.maxPolarityValue = max_polarity_value
def jsonable(self, *args, **kwargs):
resp = super(SentimentPlugin, self).jsonable(*args, **kwargs)
resp["marl:maxPolarityValue"] = self.maxPolarityValue
resp["marl:minPolarityValue"] = self.minPolarityValue
return resp
class EmotionPlugin(SenpyPlugin): class EmotionPlugin(SenpyPlugin):
def __init__(self, def __init__(self, info, *args, **kwargs):
min_emotion_value=0, resp = super(EmotionPlugin, self).__init__(info, *args, **kwargs)
max_emotion_value=1, self.minEmotionValue = float(info.get("minEmotionValue", 0))
emotion_category=None, self.maxEmotionValue = float(info.get("maxEmotionValue", 0))
**kwargs):
super(EmotionPlugin, self).__init__(**kwargs)
self.minEmotionValue = min_emotion_value
self.maxEmotionValue = max_emotion_value
self.emotionCategory = emotion_category