-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwatson.py
757 lines (671 loc) · 32.4 KB
/
watson.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
#!/usr/bin/env python
#
# Name: watson.py
# Author: Striek
# Date: December 2016
# Summary: krokbot natural language processing module
#
import config
from sopel import module, tools
import json
from watson_developer_cloud import AlchemyLanguageV1, WatsonException
from pprint import pprint
from datetime import datetime
import sqlalchemy
from sqlalchemy import (create_engine, Table, Column, Text, Integer,
String, MetaData, ForeignKey, exc)
from sqlalchemy.sql import (select, exists, update, insert)
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import OperationalError
import traceback
engine = create_engine(config.sql_connection_string, pool_recycle = 14400)
metadata = MetaData()
watson_apikeys = Table('watson_apikeys', metadata, autoload=True, autoload_with=engine)
watson_krok = Table('watson_krok', metadata, autoload=True, autoload_with=engine)
watson_kroksubjects = Table('watson_kroksubjects', metadata, autoload=True, autoload_with=engine)
watson_krokemotions = Table('watson_krokemotions', metadata, autoload=True, autoload_with=engine)
coolkids = Table('coolkids', metadata, autoload=True, autoload_with=engine)
Session = sessionmaker(bind=engine)
global debug
debug = False
class APIKeyClass:
'''A class to contain a list of all API keys in use, and cycle through them when we
reach a specified number of API calls'''
def __init__(self):
self.currentAPIKey = 0
self.api_keys = []
self.queryCount = 1000
#self.api_keys.append("1c9d6cd926fc7bff7488f0a4d6597f98ab8ca2de") # Striek API key #1 - CC# attached
# Load API keys from the database
query = select([watson_apikeys.c.key, watson_apikeys.c.queries, watson_apikeys.c.owner])
conn = engine.connect()
keys = conn.execute(query)
for key in keys:
self.api_keys.append(key.key)
self.name = self.api_keys[self.currentAPIKey]
# Get the current query count for this key
self.queryCount = self.getQueryCount()
class exc:
'''A subclass which holds any exceptions raised by this class. Currently, just
used for NoMoreKeysException.'''
class NoMoreKeysException(Exception):
pass
def next(self):
'''Cycles to the next API key in the list. Return False if we've exhausted the
available keys. Returns the key we've switched to.'''
self.currentAPIKey += 1
if self.currentAPIKey > len(self.api_keys)-1:
raise APIKey.exc.NoMoreKeysException("No more API keys available!")
return False
else:
self.name = self.api_keys[self.currentAPIKey]
self.queryCount = self.getQueryCount()
return self.name
def first(self):
'''Resets us back to the first key in the list. Generally called from
!nlp_enable.'''
self.currentAPIKey = 0
self.name = self.api_keys[self.currentAPIKey]
self.getQueryCount()
def updateQueryCount(self):
'''Updates the in-memory record of the current query count, and writes that value
to the DB'''
self.queryCount = self.getQueryCount()
self.queryCount += 1
query = update(watson_apikeys).where(watson_apikeys.c.key == self.name)\
.values(queries = self.queryCount)
conn = engine.connect()
conn.execute(query)
return self.queryCount
def getQueryCount(self):
'''Returns the number of queries that the currently in use API key has performed'''
query = select([watson_apikeys.c.queries]).where(watson_apikeys.c.key == self.name)
conn = engine.connect()
result = conn.execute(query)
self.queryCount = result.fetchone()
self.queryCount = self.queryCount[0]
return self.queryCount
def getCurrentKey(self):
'''Returns a dict containing information on the currently in use API key'''
query = select([watson_apikeys.c.key, watson_apikeys.c.queries,
watson_apikeys.c.owner]).where(watson_apikeys.c.key == self.name)
conn = engine.connect()
result = conn.execute(query)
keyInfo = result.fetchone()
return keyInfo
APIKey = APIKeyClass()
class TextAnalyzer:
''' A class to analyze text messages from an IRC channel and make cutesy-tutesy
comments about what we think the state of the commenter is.'''
master_nlp_enabled = False
emotionList = ["joy", "anger", "sadness", "fear", "disgust"]
alchemy_language = AlchemyLanguageV1(api_key = APIKey.name)
def __init__(self, name):
'''Opens a dialogue with Watson and sets up sane defaults. Also sets up our API
keys by calling instantiating am APIKey object'''
self.threshold = {}
for emotion in TextAnalyzer.emotionList:
self.threshold[emotion] = config.watson_emotion_detection_threshold
self.emotionDetected = False
def analyzeEmotion(self, bot, trigger):
'''Runs IRC messages through Watson's Alchemy API, attempting to identify
emotional context.'''
if debug: print "Entering analyzeEmotion()"
if not krok_handler.nlp_master_enabled or not krok_handler.nlp_emotion_enabled:
print "Early return from analyzeEmotion()!"
return
self.emotionDetected = False
emotions = {}
try:
channel = trigger.sender
except AttributeError:
# We likely called this from the interpreter if we wind up here
pass
channel = "#test1"
print trigger
if APIKey.queryCount >= 990:
if bot is not None:
bot.msg(channel, "Cycling to next API key!")
else:
print "Cycling to next API key!"
# If there's no more API keys we can use, disable the NLP subsystem and exit.
# Otherwise, move to the next key.
try:
TextAnalyzer.alchemy_language = AlchemyLanguageV1(api_key = APIKey.next())
emotions = self.analyzeEmotion(bot, trigger) # Start over w/new key.
return emotions
except APIKey.exc.NoMoreKeysException:
TextAnalyzer.master_nlp_enabled = False
raise APIKey.exc.NoMoreKeysException("This class is entirelely "
+" uncontaminated with API keys! "
+" (https://www.youtube.com/watch?v=B3KBuQHHKx0). Disabling NLP subsystem.")
try:
# This is the block that actually sends messages off to Alchemy for processing.
if debug: print "In analyzeEmotion(): Analyzing emotion with " + APIKey.name
json_dump = TextAnalyzer.alchemy_language.combined(
text=trigger,
extract='doc-emotion',
max_items=1,
language='english')
result = json.dumps(json_dump)
pprint(result)
# Make sure we keep track of how many API queries we've used
APIKey.updateQueryCount()
print result
except WatsonException, message:
# This really shouldn't happen if we set the max query count correctly.
# This means this block is untestable :(
if "daily-transaction-limit-exceeded" in str(message) \
or "invalid-api-key" in str(message):
if bot is not None:
bot.msg(channel, "API daily transaction limit exceeded. "
+"Switching to next key :D (" + str(message))
else:
print "API daily transaction limit exceeded. Switching to next key."
TextAnalyzer.alchemy_language = AlchemyLanguageV1(api_key = APIKey.next())
print "API Key is now: " + APIKey.name
emotions = self.analyzeEmotion(bot, trigger) # Start over w/new key
return emotions
else:
if bot is not None:
bot.msg(channel, "Unhandled Watson Exception: " + str(message))
return
else:
print "Unhandled Watson Exception: " + str(message)
except Exception, message:
print "Unhandled exception! " + str(message)
if result:
json_data = json.loads(result)
for emotion in TextAnalyzer.emotionList:
if float(json_data['docEmotions'][emotion]) > self.threshold[emotion]:
emotions[emotion] = float(json_data['docEmotions'][emotion])
self.emotionDetected = True
if self.emotionDetected == True:
if debug: pprint("About to return... " + str(emotions))
return emotions
else:
return False
def analyzeSubject(self, bot, trigger):
'''Runs messages through Watson's Alchemy API, attempting to identify
topical context. Can also be used from the interpreter, if bot=None.'''
if not krok_handler.nlp_master_enabled or not krok_handler.nlp_subject_enabled:
if debug: print "TextAnalyzer.analyzeSubject(): early return!"
return
subjects = []
try:
channel = trigger.sender
except AttributeError:
# We likely called this from the interpreter if we wind up here
pass
channel = "#test1"
print trigger
if APIKey.queryCount >= 990:
bot.msg(channel, "Cycling to next API key!")
# If there's no more API keys we can use, disable the NLP subsystem and exit.
# Otherwise, move to the next key.
try:
TextAnalyzer.alchemy_language = AlchemyLanguageV1(api_key = APIKey.next())
concepts = self.analyzeSubject(bot, trigger) # Start over with new key.
return concepts
except APIKey.exc.NoMoreKeysException:
TextAnalyzer.master_nlp_enabled = False
raise APIKey.exc.NoMoreKeysException("This class is entirelely"
+" uncontaminated with API keys! "
+" (https://www.youtube.com/watch?v=B3KBuQHHKx0). Disabling NLP subsystem.")
try:
# This is the block that actually sends messages off to Alchemy for processing.
result = json.dumps(
TextAnalyzer.alchemy_language.concepts(text=trigger,
show_source_text = 1,
linked_data = 0,
language='english')
)
# Make sure we keep track of how many API queries we've used
APIKey.updateQueryCount()
except WatsonException, message:
# This really shouldn't happen if we set the max query count correctly.
# This means this block is untestable :(
if "daily-transaction-limit-exceeded" in str(message) \
or "invalid-api-key" in str(message):
if bot is not None:
bot.msg(channel, "API daily transaction limit exceeded. \
Switching to next key :D (" + str(message))
else:
print "API daily transaction limit exceeded. Switching to next key."
print "API key was: " + APIKey.name
TextAnalyzer.alchemy_language = AlchemyLanguageV1(api_key = APIKey.next())
print "API Key is now: " + APIKey.name
subjects = self.analyzeSubject(bot, trigger) # Start over w/new key
return subjects
return
else:
bot.msg(channel, "Unhandled Watson Exception: " + str(message))
json_data = json.loads(result)
concepts = json_data['concepts']
if json_data['concepts']:
return concepts
else:
return False
class DataHandler:
'''A class to handle messages and identified context'''
master_nlp_enabled = False
def __init__(self, name):
self.name = name
self.nlp_enabled = False
def recordSubjects(self, trigger, concepts):
'''Tags krok already present in the database with associated subjects'''
# Pull the key ID for the krok we just inserted.
# (Can a ResultProxy object give us this info?)
conn = engine.connect()
query = select([watson_krok.c.krokid]).where(watson_krok.c.text == trigger)
result = conn.execute(query)
if result.rowcount != 0:
krokID = result.first()[0]
# Now, update kroksubjects with a list of every subject identified for
# that krok, and its relevance.
for datum in concepts:
subject = datum['text']
query = watson_kroksubjects.insert().values(krokid = krokID,
subject = subject,
relevance = datum['relevance'])
try:
result = conn.execute(query)
except Exception, message:
print "Exception in recordSubjects() writing " + subject \
+ " to database for krok " + trigger + ": " + str(message)
return False
return True
else:
return False
def recordEmotions(self, trigger, emotions):
'''Tags krok already present in the database with associated subjects'''
# Pull the key ID for the krok we just inserted.
# (Can a ResultProxy object give us this info?)
conn = engine.connect()
query = select([watson_krok.c.krokid]).where(watson_krok.c.text == trigger)
result = conn.execute(query)
if result.rowcount != 0:
krokID = result.first()[0]
# Now, update kroksubjects with a list of every subject identified for
# that krok, and its relevance.
for emotion in emotions:
confidence = emotions[emotion]
query = watson_krokemotions.insert().values(krokid = krokID,
emotion = emotion,
confidence = confidence)
result = conn.execute(query)
return True
else:
return False
class KrokHandler:
'''Handles the processing, analysis, and db insertion of krok.'''
global debug
emotionList = TextAnalyzer.emotionList # Expose the list of emotions through this class
def __init__(self, name):
concepts = []
emotions = []
self.nlp_master_enabled = True
self.nlp_emotion_enabled = True
self.nlp_subject_enabled = True
self.emotionAnalyzer = TextAnalyzer('emotionAnalyzer')
self.emotionHandler = DataHandler('emotionHandler')
self.subjectAnalyzer = TextAnalyzer('subjectAnalyzer')
self.subjectHandler = DataHandler('subjectHandler')
class exc:
class UnknownEmotionError(Exception):
pass
def record_krok(self, bot, trigger, force=False, record_date=True):
'''Inserts krok in the database, first checking that it's unique'''
# If force is true, this function will insert the krok regardless of whether
# or not any context was identified. Otherwise, one of the subclasses
# must return some context before the krok will be inserted.
if not self.nlp_master_enabled:
if debug: print "In record_krok(): early return, nlp_master_enabled is False"
return
try:
conn = engine.connect()
query = select([watson_krok.c.text]).where(watson_krok.c.text == trigger)
result = conn.execute(query)
# Is this krok already present in the database? If so, exit now.
if result.rowcount != 0:
if debug: print "Found " + str(result.rowcount) + " matching entries."
return
if self.nlp_subject_enabled:
if debug: print "About to analyze subjects"
subjects = self.subjectAnalyzer.analyzeSubject(bot, trigger)
if debug: print "Analyzed subjects"; print subjects
if self.nlp_emotion_enabled:
if debug: print "About to analyze emotions"
emotions = self.emotionAnalyzer.analyzeEmotion(bot, trigger)
if debug: print "Analyzed emotions"; print emotions
# Record the krok, if there's any context identified, or we forced it
if subjects or emotions or force:
if record_date:
query = watson_krok.insert().values(text = trigger,
date = datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
nick = trigger.nick,
emotions=bool(emotions), subjects=bool(subjects))
else:
query = watson_krok.insert().values(text = trigger,
emotions=bool(emotions), subjects=bool(subjects))
result = conn.execute(query)
else:
if debug: print "In record_krok(): early return - no context identified."
return False
# Now, if we identified any context, enter that into the DB as well
try:
if emotions:
self.emotionHandler.recordEmotions(trigger,emotions)
if subjects:
self.subjectHandler.recordSubjects(trigger, subjects)
except APIKey.exc.NoMoreKeysException:
print "NoMoreKeysException: " + str(message)
except OperationalError, message:
if "has gone away" in message:
print "MariaDB server has gone away: " + str(message)
else:
print "Unhandled OperationalError in recordKrok() writing to database: "\
+ str(message)
# Disable the NLP subsystem if we catch any other exception, to prevent flooding
except Exception, message:
self.nlp_master_enabled = False
traceback.print_exc()
raise
def get_random_krok(self, bot = None, emotion = None, subject = None, text = None):
''' Returns a random krok quote from the database. Can optionally return only a specific emotion or subject,
and can optionally search for specific text (aka deeplove)'''
session = Session()
conn = engine.connect()
if emotion is not None:
items = session.query(watson_krok).join(watson_krokemotions)\
.filter(watson_krokemotions.c.emotion == emotion)\
.order_by('RAND()')\
.limit(1)
elif subject is not None:
items = session.query(watson_krok).join(watson_kroksubjects)\
.filter(watson_kroksubjects.c.subject == subject)\
.order_by('RAND()')\
.limit(1)
elif text is not None:
items = session.query(watson_krok)\
.filter(watson_krok.c.text.like('%'+text+'%'))\
.order_by('RAND()')\
.limit(1)
else:
items = session.query(watson_krok)\
.order_by('RAND()')\
.limit(1)
row = items.first()
if row is not None:
return row.text
else:
return None
def get_emotion(self, bot, krok="", krokID=0):
'''Returns emotional context for a message. Returns a dict with the krok, the
krokID, and every emotion found tagged to it, if any.'''
if not self.nlp_master_enabled or not self.nlp_emotion_enabled:
if debug: print "Early return from get_emotion: master or subsystem disabled"
return False
emotions = {}
session = Session()
try:
conn = engine.connect()
# If a specific krok id was requested, jump right to that
if krokID > 0:
query = select([watson_krok.c.text]).where(watson_krok.c.krokid==str(krokID))
result = conn.execute(query)
rowcount = session.query(sqlalchemy.func.count(watson_krok).filter(watson_krok.c.krokid==krokID))
if rowcount > 0:
result = session.query(watson_krok).filter(watson_krok.c.krokid==krokID)
row = result.first()
krokID = row.krokid
krok = row.text
query = select([watson_krokemotions.c.emotion,\
watson_krokemotions.c.confidence])\
.where(watson_krokemotions.c.krokid==krokID)
results = conn.execute(query)
if results.rowcount > 0:
emotions[krokID] = {}
emotions[krokID]['krok'] = krok
emotions[krokID]['emotions'] = {}
for result in results:
emotions[krokID]['emotions'][result['emotion']] = result['confidence']
pprint(emotions)
else:
if debug: print "No krok found for id " + krokID
# First, check if this krok is already in the local database.
elif len(krok):
rowcount = session.query(sqlalchemy.func.count(watson_krok).filter(watson_krok.c.text.op('regexp')(krok)))
result = session.query(watson_krok).filter(watson_krok.c.text.op('regexp')(krok))
if rowcount > 0:
for row in result:
krokID = row.krokid
krok = row.text
query = select([watson_krokemotions.c.emotion,\
watson_krokemotions.c.confidence])\
.where(watson_krokemotions.c.krokid==krokID)
results = conn.execute(query)
if results.rowcount > 0:
emotions[krokID] = {}
emotions[krokID]['krok'] = row.text
emotions[krokID]['emotions'] = {}
for result in results:
if debug: print result['emotion'] + ": " + str(result['confidence'])
emotions[krokID]['emotions'][result['emotion']] = result['confidence']
else:
if debug: print "No emotions tagged to " + krok
else:
print krok + ": not in db"
else:
if debug: print "No matching krok in the database!"
# And return an empty dict.
if debug: pprint(emotions)
return emotions
except Exception, message:
print "Exception in get_emotion: " + str(message)
traceback.print_exc()
raise
def set_emotion_threshold(self, threshold=None, emotion=None):
'''Sets a new threshold for the detection of emotion'''
if not self.nlp_master_enabled or not self.nlp_emotion_enabled:
if debug: print "Early return from set_emotion_threshold(): master or subsystem disabled."
return False
elif threshold is None:
if debug: print "Early return from set_emotion_threshold(): no threshold given."
return False
if emotion is not None:
if emotion not in TextAnalyzer.emotionList:
if debug: print "Unknown emotion specified for set_emotion_threshold."
raise KrokHandler.exc.UnknownEmotionError
return
if debug: print "Setting " + emotion + " threshold to " + str(threshold)
self.emotionAnalyzer.threshold[emotion] = float(threshold)
else:
for emotion in TextAnalyzer.emotionList:
if debug: print "Setting " + emotion + " threshold to " + str(threshold)
self.emotionAnalyzer.threshold[emotion] = float(threshold)
krok_handler = KrokHandler('krokHandler')
# Match a line not starting with ".", "!", "krokbot", "krokpot", "kdev", or "krokwhore"
@module.unblockable
@module.rule('^(?!krokbot|krokwhore|krokpot|kdev)^[^\.!].*')
def analyzeText(bot, trigger):
'''Passes messages to the TextAnalyzer class for analysis by the Big Blue'''
global debug
channel = trigger.sender
collect_krok = False
conn = engine.connect()
query = select([coolkids.c.hostmasks, coolkids.c.collectkrok])
results = conn.execute(query)
if not results.rowcount == 0:
for row in results:
if row.hostmasks is not None:
hostmasklist = row.hostmasks
hostmasks = hostmasklist.split(',')
for hostmask in hostmasks:
if hostmask.strip() in trigger.hostmask:
if row.collectkrok == 1:
collect_krok = True
print "collecting krok"
else:
print "not colelcting krok"
if collect_krok: break
# Ignore this rule if it's not rockho
if not debug and not collect_krok:
return
try:
krok_handler.record_krok(bot, trigger)
except Exception, message:
bot.msg(channel, "Unhandled exception in record_krok(): " + str(message) \
+"; NLP subsystem disabled.")
@module.commands('nlp_emotion_threshold')
def setEmotionThreshold(bot, trigger):
'''Sets a new threshold for emotion detection, or shows current threshold if no
argument is given. Defaults to 0.6. Must be 0 <= threshold <= 1 Usage: !nlp_emotion_threshold [0 <= <new value> <= 1]'''
if krok_handler.nlp_master_enabled:
channel = trigger.sender
if trigger.group(2):
args = trigger.group(2).split()
if len(args) > 0:
newThreshold = float(args[0])
if not 0 <= newThreshold <= 1:
bot.msg(channel, "The new value must be between 0 and 1 "\
+"inclusive. RTFM, mothafucka!")
return
if len(args) > 1:
emotion = args[1]
else:
emotion = None
try:
krok_handler.set_emotion_threshold(newThreshold, emotion)
bot.msg(channel, trigger.nick
+ ", new emotion detection threshold is "
+ str(krok_handler.emotionAnalyzer.threshold))
except KrokHandler.exc.UnknownEmotionError:
bot.msg(channel, "Don't be a chomo. I don't recognize that emotion.")
bot.msg(channel, "Valid emotions are: " + ", ".join(TextAnalyzer.emotionList))
else:
bot.msg(channel, trigger.nick
+ ", current emotion detection threshold is "
+ str(krok_handler.emotionAnalyzer.threshold))
else:
bot.msg(channel, "Enable the NLP subsystem first, fuckwad.")
@module.require_admin
@module.commands('nlp_enable')
def enableNlp(bot, trigger):
'''Enables the natural language processing subsystems. Requires admin access.'''
channel = trigger.sender
if trigger.group(2) == "emotion":
if krok_handler.nlp_emotion_enabled:
bot.msg(channel, "Emotional analysis is already enabled, fucktard.")
else:
krok_handler.nlp_emotion_enabled = True
bot.msg(channel, "Emotional analysis enabled")
return
elif trigger.group(2) == "subject":
if krok_handler.nlp_subject_enabled:
bot.msg(channel, "Subject analysis is already enabled, fucktard.")
else:
krok_handler.nlp_subject_enabled = True
bot.msg(channel, "Subject analysis enabled.")
return
else:
if krok_handler.nlp_master_enabled:
bot.msg(trigger.sender, "Natural language processing is already enabled, fucktard.")
else:
krok_handler.nlp_master_enabled = True
APIKey.first()
bot.msg(trigger.sender, "Natural language processing susbsystems enabled.")
@module.require_admin
@module.commands('nlp_disable')
def disbleNlp(bot, trigger):
'''Disables the natural language processing subsystems. Requires admin access.'''
channel = trigger.sender
if trigger.group(2) == "emotion":
if not krok_handler.nlp_emotion_enabled:
bot.msg(channel, "Emotional analysis is already disabled, fucktard.")
else:
krok_handler.nlp_emotion_enabled = False
bot.msg(channel, "Emotional analysis disabled")
return
elif trigger.group(2) == "subject":
if not krok_handler.nlp_subject_enabled:
bot.msg(channel, "Subject analysis is already disabled, fucktard.")
else:
krok_handler.nlp_subject_enabled = False
bot.msg(channel, "Subject analysis disabled.")
return
else:
if not krok_handler.nlp_master_enabled:
bot.msg(trigger.sender, "Natural language processing is already disabled, fucktard.")
else:
krok_handler.nlp_master_enabled = False
bot.msg(trigger.sender, "Natural language processing susbsystems disabled.")
@module.commands('nlp_status')
def getNlpStatus(bot, trigger):
'''Displays the current status of the NLP subsystem.'''
channel = trigger.sender
if krok_handler.nlp_master_enabled: bot.msg(channel, "NLP subsystem is active!")
else: bot.msg(channel, "Sorry, NLP subsystem is offline.")
if krok_handler.nlp_emotion_enabled: bot.msg(channel, "Emotional analysis: Online")
else: bot.msg(channel, "Emotional analysis: Offline")
if krok_handler.nlp_subject_enabled: bot.msg(channel, "Subject analysis: Online")
else: bot.msg(channel, "Subject analysis: Offline")
@module.require_admin
@module.commands('nlp_current_key')
def showKeyInfo(bot, trigger):
'''Shows the key currently in use via PRIVMSG to the requester. Requires admin access.'''
if krok_handler.nlp_master_enabled:
keyInfo = APIKey.getCurrentKey()
bot.msg(trigger.nick, "Current API key: " + keyInfo['key'])
bot.msg(trigger.nick, "Current query count: " + str(keyInfo['queries']))
bot.msg(trigger.nick, "Key owner: " + keyInfo['owner'])
bot.msg(trigger.nick, "Thank you, " + trigger.nick + ", and have an awesome day!")
else:
bot.msg(trigger.sender, "Enable the NLP subsystem first, fuckwad.")
@module.require_admin
@module.commands('nlp_debug')
def nlp_debug(bot, trigger):
'''Toggles the state of the debug global.'''
global debug
if debug:
debug = False
bot.msg(trigger.sender, trigger.nick + ", debug flag is now off. Thanks!")
else:
debug = True
bot.msg(trigger.sender, trigger.nick + ", debug flag is now on. Go fuck a pig.")
@module.commands('nlp_get_emotion')
def nlp_get_emotion(bot, trigger):
'''Returns emotional context from the database for a given message, by krok ID or by message'''
channel = trigger.sender
krokID = 0
message = ""
emotions = {}
try:
krokID = int(trigger.group(2))
except ValueError:
krok = str(trigger.group(2))
if krokID:
if debug: print "Trigger argument is (int) " + str(krokID)
emotions = krok_handler.get_emotion(bot, krokID=krokID)
elif len(krok):
if debug: print "Trigger argument is (str) " + str(krok)
emotions = krok_handler.get_emotion(bot, krok=krok)
# Send this via PM if the reply would flood the channel
print "Length of emotions: " + str(len(emotions))
if len(emotions) > 3:
recipient = trigger.nick
else:
recipient = channel
if len(emotions): # This dict will be empty if we found no krok
for krokID, result in emotions.items():
pprint(result)
if len(result['emotions']): # This dict will be empty if no emotions were tagged
bot.msg(recipient, "Emotions tagged for \"" + result['krok'] + "\" (" + str(krokID) + "):")
for emotion, confidence in result['emotions'].items():
print emotion + ": " + str(confidence)
bot.msg(recipient, emotion + ": " + str(confidence))
else:
bot.msg(channel, "No emotions tagged for \"" + krok + "\"")
else:
# this krok is not in the db
bot.msg(channel, "Sorry, \"" + trigger.group(2) + "\" does not appear in my database")