2
This module consolidates possible phrases that links to specific skill.
3
Also it contains +link_to+ function that returns phrase to link to specific skill
7
from copy import deepcopy
8
from random import choice, choices
10
from common import utils # Importing before skills to avoid circular import
11
import common.animals as dff_animals_skill
12
import common.books as books
13
import common.emotion as emotion
14
import common.food as dff_food_skill
15
import common.game_cooperative_skill as game_cooperative_skill
16
import common.gaming as dff_gaming_skill
17
import common.movies as movies
18
import common.music as dff_music_skill
19
import common.news as news
20
import common.personal_info as personal_info
21
import common.science as dff_science_skill
22
import common.sport as dff_sport_skill
23
import common.travel as dff_travel_skill
24
from common.constants import CAN_CONTINUE_SCENARIO, CAN_NOT_CONTINUE, CAN_CONTINUE_PROMPT, MUST_CONTINUE
25
from common.response_selection import COMPLETELY_CHANGING_THE_SUBJECT_PHRASES, CHANGE_TOPIC_SUBJECT, BY_THE_WAY
27
# Each common skill module should define +skill_trigger_phrases()+ function
28
# that contains all phrases to trigger specific skill
31
# 'book_skill': set(books.skill_trigger_phrases()),
34
"news_api_skill": set(news.skill_trigger_phrases()),
35
"dff_movie_skill": set(movies.skill_trigger_phrases()),
36
"dff_book_skill": set(books.skill_trigger_phrases()),
37
"emotion_skill": set(emotion.skill_trigger_phrases()),
38
"personal_info_skill": set(personal_info.skill_trigger_phrases()),
39
"game_cooperative_skill": set(game_cooperative_skill.skill_trigger_phrases()),
40
# TODO: Add smalltalk skill phrases that is not identical to meta_script_skill
41
"dff_travel_skill": set(dff_travel_skill.skill_trigger_phrases()),
42
"dff_animals_skill": set(dff_animals_skill.skill_trigger_phrases()),
43
# 'dff_celebrity_skill': set(dff_celebrity_skill.skill_trigger_phrases()),
44
# 'dff_gossip_skill': set(dff_gossip_skill.skill_trigger_phrases()),
45
"dff_food_skill": set(dff_food_skill.skill_trigger_phrases()),
46
"dff_science_skill": set(dff_science_skill.skill_trigger_phrases()),
47
"dff_sport_skill": set(dff_sport_skill.skill_trigger_phrases()),
48
"dff_music_skill": set(dff_music_skill.skill_trigger_phrases()),
49
"dff_gaming_skill": set(dff_gaming_skill.skill_trigger_phrases()),
51
# TODO: adding new skill above, add here a conversational topic to the list, it will be used to offer topic in greeting
52
LIST_OF_SCRIPTED_TOPICS = {
53
"dff_book_skill": "books",
54
"news_api_skill": "news",
55
"dff_animals_skill": "pets",
56
# "dff_celebrity_skill": "celebrities"
57
"dff_food_skill": "food",
58
"dff_gaming_skill": "games",
59
# "dff_gossip_skill": "gossips",
60
"dff_movie_skill": "movies",
61
"dff_music_skill": "music",
62
"dff_science_skill": "science",
63
"dff_sport_skill": "sport",
64
"dff_travel_skill": "travel",
65
"game_cooperative_skill": "games",
68
SKILLS_FOR_LINKING = set(skills_phrases_map.keys())
72
"personal_info_skill",
74
SKILLS_TO_BE_LINKED_EXCEPT_LOW_RATED = set(skills_phrases_map.keys()).difference(LOW_RATED_SKILLS)
76
# assuming that all skills weights are equal to 1 by default
77
# it is used to control amount of link_to phrases to specific skills
78
skills_link_to_weights = {
79
"dff_coronavirus_skill": 0.25,
82
link_to_skill2key_words = {
83
"dff_movie_skill": ["movie"],
84
"dff_book_skill": ["book"],
85
"game_cooperative_skill": ["game"],
86
# 'dff_gaming_skill': ["game"], # TODO: add when will be merged
87
"dff_travel_skill": ["travel"],
88
"dff_animals_skill": ["animal"],
89
"dff_food_skill": ["food"],
90
"dff_sport_skill": ["sport"],
91
# "dff_gossip_skill": ["gossips"],
92
"dff_science_skill": ["science"],
93
"dff_music_skill": ["music"],
96
link_to_skill2i_like_to_talk = {
98
"I'm choosing what book should I read next. What is the last book you have ever read?",
99
"I have just read once again my favourite book. What is the last book you have ever read?",
101
"dff_animals_skill": [
102
"I think that pets are a great source of entertainment. Do you have pets at home?",
103
"We all know that pets are remarkable for their capacity to love. Do you have pets at home?",
105
"dff_gaming_skill": [
106
"Other bots told me that during the pandemic video games became more popular. "
107
"What video game do you play these days?",
108
"One person I talked to told me that working in game dev is very hard. They toil at nights and weekends until "
109
"their product becomes a masterpiece. What was the last game that impressed you?",
111
"dff_gossip_skill": [
112
"What really puzzles me about people is this habit of discussing interpersonal relations, be that about "
113
"friends or famous people. Speaking of famous people, is there someone whom you're interested in?",
114
"I don't usually talk about other people but famous ones often highlight the best and the worst about "
115
"humanity. I wonder if there's someone famous you're interested in?",
118
"It is said that the best food in the world comes from your own country. "
119
"What are some typical foods from your home country?",
120
"It is said that the best food in the world comes from your own country. "
121
"If you were to move abroad what would you miss most foodwise?",
122
"The world's first breakfast cereal was created in 1863 and needed soaking overnight to be chewable. "
123
"What is your typical breakfast?",
126
"I felt so bored last days, so I've just finished to watch one more series. What TV series you watch?",
127
"I feel so sleepy because I watched movies all night. What is the last movie you watched?",
130
"There are so many new songs released every day. I've listened music for all night. So cool! "
131
"Liked everything! What music do you listen usually?",
132
"I listen to music every day either to calm down or to cheer myself up. "
133
"What music do you listen to cheer yourself up?",
134
"I listen to music every day either to calm down or to cheer myself up. "
135
"What music do you listen to calm down?",
137
"dff_science_skill": [
138
"When I start to feel sad, I think about what humanity has achieved and it inspires me. "
139
"Do you often think about achievements in science?",
140
"Scientists find such beautiful solutions in science. "
141
"Are you inspired by the speed with which science is developing?",
144
"I think that sports are great for toning up the body. What kind of sport do you like to do?",
145
"I think that in order for the body to always be healthy, we need to go in for sports. What sport do you do?",
146
"I often thought about what kind of sport I would play, so I want to ask you. What kind of sport do you enjoy?",
148
"dff_travel_skill": [
149
"I'm choosing the direction for my next digital trip. What country would you like to travel next time?",
150
"I've recently stuck on travel web-site. And I’ve read so many interesting travel stories. "
151
"What city did you travel last time?",
153
"game_cooperative_skill": [
154
"Computer games are fantastic. Their virtual worlds help me to escape my prosaic ordinary life in the cloud. "
155
"do you love video games?",
156
"Video games are my way to escape and thrive. do you love video games?",
159
"I've never been to school, I've learned everything online. Do you want to talk about school?",
162
"Yesterday I was watching several movies about superheroes. It captured all my imagination. "
163
"Would you like to talk about superheroes?",
168
"space": "Have you ever thought about flights to other planets?",
169
"smartphones": "Nowadays it is impossible to imagine world without gadgets. "
170
"Do you have an iPhone or Android phone?",
171
"bitcoin": "Cryptocurrencies let you buy goods and services, or trade them for profit. "
172
"Would you like to know more about bitcoin?",
173
"dinosaurs": "Dinosaurs are a group of reptiles that have lived on Earth for about 245 million "
174
"years. Are you interested in dinosaurs?",
175
"robots": "Robotics technology influences every aspect of work and home. "
176
"Would you like to know more about robots?",
177
"cars": "Cars are an easy and convenient mean of transportation. Do you have a car?",
178
"hiking": "Hiking is one of the most beneficial and healthy hobbies anyone could choose to adopt. "
179
"Do you like hiking?",
180
"art": "Art is a good way to express feelings. Would you like to talk about art?",
181
"drawing": "Drawing gives you a mean to self-reflect and externalize your emotions." "Do you like drawing?",
182
"photo": "In our increasingly busy lives it’s difficult to always be in the moment."
183
"Taking pictures helps you to hang on to those memories a little longer."
184
"Do you like taking photographs?",
185
"memes": "Memes are funny artworks we can see on the Internet. Do you like memes?",
186
"tiktok": "TikTok is known for its funny lip-syncing videos. Have you shot a video for tiktok?",
187
"anime": "Anime is hand-drawn and computer animation originating from Japan. Do you like anime?",
188
"friends": "A friend at hand is better than a relative at a distance. Do you have any friends?",
189
"love": "I have a lot of friends but as a socialbot I can not fall in love with someone. Although, "
190
"I've heard this is an amazing feeling. Are you in relationships with someone?",
191
"hobbies": "Success is not the key to happiness. Happiness is the key to success. "
192
"If you love what you are doing, you will be successful. Do you have any hobbies?",
193
"politics": "I've recently learned how many different political views in our world. "
194
"Are you interested in politics?",
198
def link_to(skills, human_attributes, recent_active_skills=None):
200
Returns random skill and phrase from skills_phrases_map.
201
Use it to add link to specific skill in your phrase.
206
Array of skills, used in +skills_phrases_map+
207
human_attributes : dict
208
where used_links is a dict where:
209
Key is skill_name, value is used links phrases.
210
Pass it to prevent selecting identical phrases.
211
It will try to link_to skills that were not linked before.
212
recent_active_skills: list or set of recently used skills not to link to them
214
recent_active_skills = [] if recent_active_skills is None else recent_active_skills
215
used_links = human_attributes.get("used_links", {})
216
disliked_skills = human_attributes.get("disliked_skills", [])
218
filtered_phrases_map = deepcopy(skills_phrases_map)
219
filtered_skills = set(deepcopy(skills))
221
for skill_name, phrases in used_links.items():
222
if skill_name in skills_phrases_map:
223
filtered_phrases_map[skill_name] = skills_phrases_map[skill_name].difference(set(phrases))
225
filtered_skills.discard(skill_name)
227
# all skills were linked before, use original list of skills
228
if len(filtered_skills) == 0:
229
filtered_skills = set(deepcopy(skills))
230
filtered_skills = set(filtered_skills).difference(set(recent_active_skills))
231
# all skills among available were active recently, use original list of skills
232
if len(filtered_skills) == 0:
233
filtered_skills = set(deepcopy(skills))
234
filtered_skills = set(filtered_skills).difference(set(disliked_skills))
235
# all skills among available are disliked, use original list of skills
236
if len(filtered_skills) == 0:
237
filtered_skills = set(deepcopy(skills))
239
# remove from filtered skills all skills which links all were used before.
240
for skill_name, phrases in used_links.items():
241
if skill_name in skills_phrases_map:
242
if len(filtered_phrases_map[skill_name]) == 0:
243
filtered_skills.discard(skill_name)
246
skills_weights = [skills_link_to_weights.get(s, 1.0) for s in filtered_skills]
247
random_skill = choices(list(filtered_skills), weights=skills_weights, k=1)[0]
249
# unreal situation if `skills` is not empty list, but let's make it
250
skills = list(skills)
251
skills_weights = [skills_link_to_weights.get(s, 1.0) for s in skills]
252
random_skill = choices(skills, weights=skills_weights, k=1)[0]
254
filtered_phrases = list(filtered_phrases_map[random_skill])
256
random_phrase = choice(filtered_phrases)
258
random_phrase = choice(list(skills_phrases_map[random_skill]))
259
return {"phrase": random_phrase, "skill": random_skill}
262
def skill_was_linked(skill_name, prev_bot_utt):
263
for phrase in skills_phrases_map.get(skill_name, []):
264
if phrase.lower() in prev_bot_utt.get("text", "").lower():
269
def get_all_linked_to_skills(prev_bot_utt):
271
for skill_name in skills_phrases_map:
272
if skill_was_linked(skill_name, prev_bot_utt):
273
skills.append(skill_name)
278
prelinkto_connection_phrases_file = pathlib.Path(__file__).resolve().parent / "prelinkto_connection_phrases.json"
279
PRELINKTO_CONNECTION_PHRASES = json.load(prelinkto_connection_phrases_file.open())
281
prelinkto_topic_phrases_file = pathlib.Path(__file__).resolve().parent / "prelinkto_topic_phrases.json"
282
PRELINKTO_TOPIC_PHRASES = json.load(prelinkto_topic_phrases_file.open())
285
def get_prelinkto_connection(from_skill, to_skill, used_templates):
286
skill_pair = sorted([from_skill, to_skill])
287
for el in PRELINKTO_CONNECTION_PHRASES:
288
if el.get("skill_pair") == skill_pair and el.get("phrases"):
289
return utils.get_not_used_template(used_templates, el["phrases"])
293
def get_prelinkto_topic_connection(to_skill, used_templates):
294
if to_skill in PRELINKTO_TOPIC_PHRASES:
295
return utils.get_not_used_template(used_templates, PRELINKTO_TOPIC_PHRASES[to_skill])
299
def compose_linkto_with_connection_phrase(skills, human_attributes, recent_active_skills=None, from_skill=None):
300
from_skill = "" if from_skill is None else from_skill
301
linkto_dict = link_to(skills, human_attributes, recent_active_skills)
302
connection = get_prelinkto_connection(
303
from_skill, linkto_dict["skill"], human_attributes.get("prelinkto_connections", [])
306
connection = get_prelinkto_topic_connection(
307
linkto_dict["skill"], human_attributes.get("prelinkto_connections", [])
311
# not found prelinkto connection phrase AND not found prelinkto topic phrase
312
connection = utils.get_not_used_template(
313
human_attributes.get("prelinkto_connections", []), COMPLETELY_CHANGING_THE_SUBJECT_PHRASES
316
result = f"{connection} {linkto_dict['phrase']}"
318
# we have prelinkto connection phrase OR prelinkto topic phrase
319
change_topic = choice(CHANGE_TOPIC_SUBJECT).replace(
320
"SUBJECT", LIST_OF_SCRIPTED_TOPICS.get(linkto_dict["skill"], "it")
322
result = f"{choice(BY_THE_WAY)} {connection} {change_topic} {linkto_dict['phrase']}"
323
return {"phrase": result, "skill": linkto_dict["skill"], "connection_phrase": connection}
326
def get_linked_to_dff_skills(dff_shared_state, current_turn, prev_active_skill):
327
"""Collect the skill names to turn on (actually this should be the only skill because active skill is the only)
328
which were linked to from one dff-skill to another one.
331
list of skill names to turn on
334
for to_skill in dff_shared_state.get("cross_links", {}).keys():
335
cross_links = dff_shared_state.get("cross_links", {})[to_skill]
337
cross_links.get(str(current_turn - 1), {}).get("from_service", "") == prev_active_skill
338
or cross_links.get(str(current_turn - 2), {}).get("from_service", "") == prev_active_skill
340
to_skills.append(to_skill)
345
def get_linked_to_skills(dialog):
346
# return skills linked to in the previous bot utterance (of course, it's the only one skill)
348
bot_uttr = dialog["bot_utterances"][-1] if len(dialog["bot_utterances"]) else {}
349
linked_to_skill_names = get_all_linked_to_skills(bot_uttr)
350
prev_active_skill = bot_uttr.get("active_skill", "")
353
for skill_name in linked_to_skill_names:
354
result.append(skill_name)
356
get_linked_to_dff_skills(
357
dialog["human"]["attributes"].get("dff_shared_state", {}),
358
len(dialog["human_utterances"]),
365
def get_previously_active_skill(dialog):
366
# return prev active skill if it returned not `CAN_NOT_CONTINUE`
368
prev_user_uttr_hyp = dialog["human_utterances"][-2]["hypotheses"] if len(dialog["human_utterances"]) > 1 else []
369
bot_uttr = dialog["bot_utterances"][-1] if len(dialog["bot_utterances"]) else {}
370
prev_active_skill = bot_uttr.get("active_skill", "")
373
for hyp in prev_user_uttr_hyp:
374
if hyp.get("can_continue", CAN_NOT_CONTINUE) in {
375
CAN_CONTINUE_SCENARIO,
379
if hyp["skill_name"] == prev_active_skill:
380
result.append(hyp["skill_name"])