add support for picoAPI sentiment analysis
The more the merrier
diff --git a/src/plugins/utils/tone.py b/src/plugins/utils/tone.py
index 9c26809..631bbb9 100644
--- a/src/plugins/utils/tone.py
+++ b/src/plugins/utils/tone.py
@@ -133,4 +133,67 @@
KibbleBit.pprint("Possible rate limiting in place, stopping for now.")
return False
return moods
+
+def picoTone(KibbleBit, bodies):
+ """ Sentiment analysis using picoAPI Text Analysis """
+ if 'picoapi' in KibbleBit.config:
+ headers = {
+ 'Content-Type': 'application/json',
+ 'PicoAPI-Key': KibbleBit.config['picoapi']['key']
+ }
+
+
+ js = {
+ "texts": []
+ }
+
+ # For each body...
+ a = 0
+ moods = []
+ for body in bodies:
+ # Crop out quotes
+ lines = body.split("\n")
+ body = "\n".join([x for x in lines if not x.startswith(">")])
+ doc = {
+ "id": str(a),
+ "body": body
+ }
+ js['texts'].append(doc)
+ moods.append({}) # placeholder for each doc, to be replaced
+ a += 1
+ try:
+ rv = requests.post(
+ "https://v1.picoapi.com/api/text/sentiment",
+ headers = headers,
+ data = json.dumps(js)
+ )
+ jsout = rv.json()
+ except:
+ jsout = {} # borked sentiment analysis?
+
+ if 'results' in jsout and len(jsout['results']) > 0:
+ for doc in jsout['results']:
+ mood = {}
+ # This is more parred than Watson, so we'll split it into three groups: positive, neutral and negative.
+ # Divide into four segments, 0->40%, 25->75% and 60->100%.
+ # 0-40 promotes negative, 60-100 promotes positive, and 25-75% promotes neutral.
+ # As we don't want to over-represent negative/positive where the results are
+ # muddy, the neutral zone is larger than the positive/negative zones by 10%.
+ val = (1 + doc['sentiment']) / 2 # This ranges from -1 to +1, so we'll just harmonize that to 0->1 and use the azure calcs
+
+ mood['negative'] = max(0, ((0.4 - val) * 2.5)) # For 40% and below, use 2½ distance
+ mood['positive'] = max(0, ((val-0.6) * 2.5)) # For 60% and above, use 2½ distance
+ mood['neutral'] = max(0, 1 - (abs(val - 0.5) * 2)) # Between 25% and 75% use double the distance to middle.
+ moods[int(doc['id'])] = mood # Replace moods[X] with the actual mood
+
+ else:
+ KibbleBit.pprint("Failed to analyze email body.")
+ print(jsout)
+ # 403 returned on invalid key, 429 on rate exceeded.
+ # If we see a code return, let's just stop for now.
+ # Later scans can pick up the slack.
+ if 'code' in jsout:
+ KibbleBit.pprint("Possible rate limiting in place, stopping for now.")
+ return False
+ return moods
\ No newline at end of file