3
from common.greeting import HOW_ARE_YOU_RESPONSES
4
from common.utils import get_emotions, get_comet_conceptnet_annotations
5
from common.universal_templates import if_chat_about_particular_topic
8
POSITIVE_EMOTIONS = set(
49
NEGATIVE_EMOTIONS = set(
90
POSITIVE_EMOTION = "positive_emotion"
91
NEGATIVE_EMOTION = "negative_emotion"
93
HOW_DO_YOU_FEEL = "How do you feel?"
97
r"\b(pain|backache|heart attack|earache|headache|" r"stomachache|toothache|diseased|ailing|damaged|sick|sore)\b"
100
r"\b(sad|horrible|depressed|terrible|tired|awful|dire|upset|trash|"
101
r"pity|poor|ill|low|exhausted|inferior|crying|miserable|cry|naughty|nasty|foul|ugly|grisly|harmful|"
102
r"spoiled|depraved|tained|awry|so so|badly|sadly|wretched|bad|unhappy)\b"
105
r"\b(happy|good|okay|great|yeah|cool|awesome|perfect|nice|well|ok|fine|"
106
r"neat|swell|fabulous|peachy|excellent|exciting|excited|splendid|all right"
107
r"|super|classy|tops|famous|superb|incredible|tremendous|class|crackajack|crackerjack)\b"
109
ALONE_PATTERN = r"(i am alone|lonely|loneliness|do you love me)"
110
NOT_PATTERN = r"((\bnot|n't\bno)( too| that| really| so| feel| going)?)"
111
JOKE_PATTERN = r"(((tell me|tell|hear)( [a-z]+){0,3} jokes?)|^joke)"
112
POOR_ASR_PATTERN = r"^say$"
114
POSITIVE_TEMPLATE = re.compile(POSITIVE_PATTERN, re.IGNORECASE)
115
NOT_POSITIVE_TEMPLATE = re.compile(rf"{NOT_PATTERN} {POSITIVE_PATTERN}", re.IGNORECASE)
116
PAIN_TEMPLATE = re.compile(PAIN_PATTERN, re.IGNORECASE)
117
NOT_PAIN_TEMPLATE = re.compile(rf"{NOT_PATTERN} {PAIN_PATTERN}", re.IGNORECASE)
118
LONELINESS_TEMPLATE = re.compile(rf"{ALONE_PATTERN}", re.IGNORECASE)
119
NOT_LONELINESS_TEMPLATE = re.compile(rf"{NOT_PATTERN} {ALONE_PATTERN}", re.IGNORECASE)
120
SAD_TEMPLATE = re.compile(rf"({SAD_PATTERN}|{POOR_ASR_PATTERN})", re.IGNORECASE)
121
NOT_SAD_TEMPLATE = re.compile(rf"{NOT_PATTERN} {SAD_PATTERN}", re.IGNORECASE)
122
BORING_TEMPLATE = re.compile(r"(boring|bored)", re.IGNORECASE)
123
NOT_BORING_TEMPLATE = re.compile(rf"{NOT_PATTERN} (boring|bored)", re.IGNORECASE)
124
JOKE_REQUEST_TEMPLATE = re.compile(rf"{JOKE_PATTERN}", re.IGNORECASE)
125
NOT_JOKE_REQUEST_TEMPLATE = re.compile(rf"{NOT_PATTERN} {JOKE_PATTERN}", re.IGNORECASE)
127
r"((((can|could) you )?(give|suggest|tell) (me )?(a |an |some )?advice)|" r"(advice me (something|anything)))"
129
ADVICE_REQUEST_TEMPLATE = re.compile(ADVICE_PATTERN, re.IGNORECASE)
131
TALK_ABOUT_EMO_TEMPLATE = re.compile(r"\b(emotion|feeling|i feel\b|depress)", re.IGNORECASE)
134
def talk_about_emotion(user_utt, bot_uttr):
135
return if_chat_about_particular_topic(user_utt, bot_uttr, compiled_pattern=TALK_ABOUT_EMO_TEMPLATE)
138
def is_sad(annotated_uttr):
139
uttr_text = annotated_uttr["text"]
140
is_sad = re.search(SAD_TEMPLATE, uttr_text) and not re.search(NOT_SAD_TEMPLATE, uttr_text)
141
not_positive = re.search(NOT_POSITIVE_TEMPLATE, uttr_text)
142
return is_sad or not_positive
145
def is_boring(annotated_uttr):
146
uttr_text = annotated_uttr["text"]
147
return re.search(BORING_TEMPLATE, uttr_text) and not re.search(NOT_BORING_TEMPLATE, uttr_text)
150
def is_pain(annotated_uttr):
151
uttr_text = annotated_uttr["text"]
153
for elem, triplets in get_comet_conceptnet_annotations(annotated_uttr).items():
154
if "SymbolOf" in triplets and "pain" in triplets["SymbolOf"]:
156
return re.search(PAIN_TEMPLATE, uttr_text) and not re.search(NOT_PAIN_TEMPLATE, uttr_text)
159
def is_alone(annotated_uttr):
160
uttr_text = annotated_uttr["text"]
161
return re.search(LONELINESS_TEMPLATE, uttr_text) and not re.search(NOT_LONELINESS_TEMPLATE, uttr_text)
164
def is_joke_requested(annotated_uttr):
165
uttr_text = annotated_uttr["text"]
166
return re.search(JOKE_REQUEST_TEMPLATE, uttr_text) and not re.search(NOT_JOKE_REQUEST_TEMPLATE, uttr_text)
169
def is_negative_regexp_based(annotated_uttr):
170
return any([negative_function(annotated_uttr) for negative_function in [is_sad, is_boring, is_alone, is_pain]])
173
def is_positive_regexp_based(annotated_uttr):
174
uttr_text = annotated_uttr["text"]
175
positive = re.search(POSITIVE_TEMPLATE, uttr_text) and not re.search(NOT_POSITIVE_TEMPLATE, uttr_text)
176
not_sad = re.search(NOT_SAD_TEMPLATE, uttr_text)
177
return positive or not_sad
180
def emo_advice_requested(uttr):
181
return bool(re.search(ADVICE_REQUEST_TEMPLATE, uttr))
184
def skill_trigger_phrases():
185
return [HOW_DO_YOU_FEEL] + sum([HOW_ARE_YOU_RESPONSES[lang] for lang in ["RU", "EN"]], [])
188
def emotion_from_feel_answer(prev_bot_uttr, user_uttr):
189
if HOW_DO_YOU_FEEL.lower() in prev_bot_uttr.lower():
190
for w in user_uttr.split(" "):
191
w = re.sub(r"\W", " ", w.lower()).strip()
192
if w in POSITIVE_EMOTIONS:
193
return POSITIVE_EMOTION
194
elif w in NEGATIVE_EMOTIONS:
195
return NEGATIVE_EMOTION
199
def if_turn_on_emotion(user_utt, bot_uttr):
200
emotions = get_emotions(user_utt, probs=True)
201
emo_prob_threshold = 0.8
202
found_emotion, found_prob = "neutral", 1
203
for emotion, prob in emotions.items():
204
if prob == max(emotions.values()):
205
found_emotion, found_prob = emotion, prob
206
emo_found_emotion = found_emotion != "neutral" and found_prob > emo_prob_threshold
207
good_emotion_prob = max([emotions.get("joy", 0), emotions.get("love", 0)])
208
bad_emotion_prob = max([emotions.get("anger", 0), emotions.get("fear", 0), emotions.get("sadness", 0)])
209
not_strange_emotion_prob = not (good_emotion_prob > 0.6 and bad_emotion_prob > 0.5)
212
how_are_you_response.lower() in bot_uttr.get("text", "").lower()
213
for how_are_you_response in sum([HOW_ARE_YOU_RESPONSES[lang] for lang in ["RU", "EN"]], [])
216
joke_request_detected = is_joke_requested(user_utt)
217
talk_about_regexp = talk_about_emotion(user_utt, bot_uttr)
218
pain_detected_by_regexp = is_pain(user_utt)
219
sadness_detected_by_regexp = is_sad(user_utt)
220
loneliness_detected_by_regexp = is_alone(user_utt)
221
advice_request_detected_by_regexp = emo_advice_requested(user_utt.get("text", ""))
222
detected_from_feel_answer = emotion_from_feel_answer(bot_uttr.get("text", ""), user_utt.get("text", ""))
223
should_run_emotion = (
227
joke_request_detected,
228
sadness_detected_by_regexp,
229
loneliness_detected_by_regexp,
230
pain_detected_by_regexp,
231
advice_request_detected_by_regexp,
233
detected_from_feel_answer,
237
and not_strange_emotion_prob
239
return should_run_emotion