Tweak CommonPlay scoring

The scoring for CommonPlay would favor skills that responded with overly long
matches.  E.g. "Huey Lewis and the News" would be considered a better fit than
just "News" for the request "Play the News"
pull/2026/head
Steve Penrod 2019-02-28 03:54:53 -06:00 committed by Åke Forslund
parent d65555c327
commit d25d91e034
1 changed files with 23 additions and 6 deletions

View File

@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import re
from enum import Enum from enum import Enum
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from mycroft import MycroftSkill from mycroft import MycroftSkill
@ -34,6 +35,13 @@ class CommonPlaySkill(MycroftSkill, ABC):
self.audioservice = None self.audioservice = None
self.play_service_string = None self.play_service_string = None
# "MusicServiceSkill" -> "Music Service"
spoken = name or self.__class__.__name__
self.spoken_name = re.sub(r"([a-z])([A-Z])", r"\g<1> \g<2>",
spoken.replace("Skill", ""))
# NOTE: Derived skills will likely want to override self.spoken_name
# with a translatable name in their initialize() method.
def bind(self, bus): def bind(self, bus):
if bus: if bus:
super().bind(bus) super().bind(bus)
@ -61,6 +69,7 @@ class CommonPlaySkill(MycroftSkill, ABC):
self.bus.emit(message.response({"phrase": search_phrase, self.bus.emit(message.response({"phrase": search_phrase,
"skill_id": self.skill_id, "skill_id": self.skill_id,
"callback_data": callback, "callback_data": callback,
"service_name": self.spoken_name,
"conf": confidence})) "conf": confidence}))
else: else:
# Signal we are done (can't handle it) # Signal we are done (can't handle it)
@ -69,23 +78,31 @@ class CommonPlaySkill(MycroftSkill, ABC):
"searching": False})) "searching": False}))
def __calc_confidence(self, match, phrase, level): def __calc_confidence(self, match, phrase, level):
# "play pandora"
# "play pandora is my girlfriend"
# "play tom waits on pandora"
# Assume the more of the words that get consumed, the better the match # Assume the more of the words that get consumed, the better the match
consumed_pct = len(match.split()) / len(phrase.split()) consumed_pct = len(match.split()) / len(phrase.split())
if consumed_pct > 1.0: if consumed_pct > 1.0:
consumed_pct = 1.0 consumed_pct = 1.0 / consumed_pct # deal with over/under-matching
# We'll use this to modify the level, but don't want it to allow a
# match to jump to the next match level. So bonus is 0 - 0.05 (1/20)
bonus = consumed_pct / 20.0
if level == CPSMatchLevel.EXACT: if level == CPSMatchLevel.EXACT:
return 1.0 return 1.0
elif level == CPSMatchLevel.MULTI_KEY: elif level == CPSMatchLevel.MULTI_KEY:
return 0.9 + (consumed_pct / 10) return 0.9 + bonus
elif level == CPSMatchLevel.TITLE: elif level == CPSMatchLevel.TITLE:
return 0.8 + (consumed_pct / 10) return 0.8 + bonus
elif level == CPSMatchLevel.ARTIST: elif level == CPSMatchLevel.ARTIST:
return 0.7 + (consumed_pct / 10) return 0.7 + bonus
elif level == CPSMatchLevel.CATEGORY: elif level == CPSMatchLevel.CATEGORY:
return 0.6 + (consumed_pct / 10) return 0.6 + bonus
elif level == CPSMatchLevel.GENERIC: elif level == CPSMatchLevel.GENERIC:
return 0.5 + (consumed_pct / 10) return 0.5 + bonus
else: else:
return 0.0 # should never happen return 0.0 # should never happen