Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:pipeline plugin factory #14

Merged
merged 9 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 24 additions & 28 deletions ocp_pipeline/opm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@
from dataclasses import dataclass
from os.path import join, dirname
from threading import RLock
from typing import List, Tuple, Optional, Union
from typing import Tuple, Optional, Dict, List, Union

from langcodes import closest_match
from ovos_bus_client.apis.ocp import ClassicAudioServiceInterface
from ovos_bus_client.apis.ocp import OCPInterface, OCPQuery
from ovos_bus_client.client import MessageBusClient
from ovos_bus_client.message import Message, dig_for_message
from ovos_bus_client.session import SessionManager
from ovos_plugin_manager.ocp import available_extractors
from ovos_plugin_manager.templates.pipeline import IntentMatch, PipelinePlugin
from ovos_plugin_manager.templates.pipeline import IntentMatch, ConfidenceMatcherPipeline
from ovos_utils.lang import standardize_lang_tag, get_language_dir
from ovos_utils.log import LOG
from ovos_utils.messagebus import FakeBus
from ovos_utils.ocp import MediaType, PlaybackType, PlaybackMode, PlayerState, OCP_ID, \
MediaEntry, Playlist, MediaState, TrackState, dict2entry, PluginStream
from ovos_workshop.app import OVOSAbstractApplication
from padacioso import IntentContainer
from langcodes import closest_match

from ocp_pipeline.feats import OCPFeaturizer
from ocp_pipeline.legacy import LegacyCommonPlay

Expand All @@ -35,15 +37,16 @@ class OCPPlayerProxy:
media_type: MediaType = MediaType.GENERIC


class OCPPipelineMatcher(PipelinePlugin, OVOSAbstractApplication):
class OCPPipelineMatcher(ConfidenceMatcherPipeline, OVOSAbstractApplication):
intents = ["play.intent", "open.intent", "media_stop.intent",
"next.intent", "prev.intent", "pause.intent", "play_favorites.intent",
"resume.intent", "like_song.intent"]

def __init__(self, bus=None, config=None):
def __init__(self, bus: Optional[Union[MessageBusClient, FakeBus]] = None,
config: Optional[Dict] = None):
OVOSAbstractApplication.__init__(
self, bus=bus or FakeBus(), skill_id=OCP_ID, resources_dir=f"{dirname(__file__)}")
PipelinePlugin.__init__(self, config)
ConfidenceMatcherPipeline.__init__(self, bus, config)
JarbasAl marked this conversation as resolved.
Show resolved Hide resolved

self.ocp_api = OCPInterface(self.bus)
self.legacy_api = ClassicAudioServiceInterface(self.bus)
Expand Down Expand Up @@ -323,9 +326,8 @@ def match_high(self, utterances: List[str], lang: str, message: Message = None)
else:
return None

return IntentMatch(intent_service="OCP_intents",
intent_type=f'ocp:{match["name"]}',
intent_data=match,
return IntentMatch(match_type=f'ocp:{match["name"]}',
match_data=match,
skill_id=OCP_ID,
utterance=utterance)

Expand Down Expand Up @@ -353,17 +355,16 @@ def match_medium(self, utterances: List[str], lang: str, message: Message = None
# extract the query string
query = self.remove_voc(utterance, "Play", lang).strip()

return IntentMatch(intent_service="OCP_media",
intent_type="ocp:play",
intent_data={"media_type": media_type,
return IntentMatch(match_type="ocp:play",
match_data={"media_type": media_type,
"entities": ents,
"query": query,
"is_ocp_conf": bconf,
"conf": confidence},
skill_id=OCP_ID,
utterance=utterance)

def match_fallback(self, utterances: List[str], lang: str, message: Message = None) -> Optional[IntentMatch]:
def match_low(self, utterances: List[str], lang: str, message: Message = None) -> Optional[IntentMatch]:
""" match an utterance via presence of known OCP keywords,
recommended before fallback_low pipeline stage"""
utterance = utterances[0].lower()
Expand All @@ -386,9 +387,8 @@ def match_fallback(self, utterances: List[str], lang: str, message: Message = No
# extract the query string
query = self.remove_voc(utterance, "Play", lang).strip()

return IntentMatch(intent_service="OCP_fallback",
intent_type="ocp:play",
intent_data={"media_type": media_type,
return IntentMatch(match_type="ocp:play",
match_data={"media_type": media_type,
"entities": ents,
"query": query,
"conf": float(confidence)},
Expand All @@ -403,9 +403,8 @@ def _process_play_query(self, utterance: str, lang: str, match: dict = None,
# if media is currently paused, empty string means "resume playback"
if player.player_state == PlayerState.PAUSED and \
self._should_resume(utterance, lang, message=message):
return IntentMatch(intent_service="OCP_intents",
intent_type="ocp:resume",
intent_data=match,
return IntentMatch(match_type="ocp:resume",
match_data=match,
skill_id=OCP_ID,
utterance=utterance)

Expand All @@ -414,9 +413,8 @@ def _process_play_query(self, utterance: str, lang: str, match: dict = None,
phrase = self.get_response("play.what", num_retries=2)
if not phrase:
# let the error intent handler take action
return IntentMatch(intent_service="OCP_intents",
intent_type="ocp:search_error",
intent_data=match,
return IntentMatch(match_type="ocp:search_error",
match_data=match,
skill_id=OCP_ID,
utterance=utterance)

Expand All @@ -441,9 +439,8 @@ def _process_play_query(self, utterance: str, lang: str, match: dict = None,
else:
ents = OCPFeaturizer.extract_entities(utterance)

return IntentMatch(intent_service="OCP_intents",
intent_type="ocp:play",
intent_data={"media_type": media_type,
return IntentMatch(match_type="ocp:play",
match_data={"media_type": media_type,
"query": query,
"entities": ents,
"skills": valid_skills,
Expand Down Expand Up @@ -1058,9 +1055,8 @@ def match_legacy(self, utterances: List[str], lang: str, message: Message = None
if match["name"] == "play":
LOG.info(f"Legacy Mycroft CommonPlay match: {match}")
utterance = match["entities"].pop("query")
return IntentMatch(intent_service="OCP_media",
intent_type="ocp:legacy_cps",
intent_data={"query": utterance,
return IntentMatch(match_type="ocp:legacy_cps",
match_data={"query": utterance,
"conf": 0.7},
skill_id=OCP_ID,
utterance=utterance)
Expand Down
8 changes: 4 additions & 4 deletions tests/test_ocp.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@ def test_match_medium_with_invalid_input(self):
self.assertIsNone(result)

def test_match_fallback(self):
result = self.ocp.match_fallback(["i want music"], "en-us")
result = self.ocp.match_low(["i want music"], "en-us")
self.assertIsNotNone(result)
self.assertEqual(result.intent_service, 'OCP_fallback')
self.assertEqual(result.intent_type, 'ocp:play')

def test_match_fallback_with_invalid_input(self):
result = self.ocp.match_fallback(["do the thing"], "en-us")
result = self.ocp.match_low(["do the thing"], "en-us")
self.assertIsNone(result)

def test_predict(self):
Expand Down Expand Up @@ -139,14 +139,14 @@ def test_match_medium_with_invalid_input(self):
self.assertIsNone(result)

def test_match_fallback(self):
result = self.ocp.match_fallback(["i wanna hear metallica"], "en-us")
result = self.ocp.match_low(["i wanna hear metallica"], "en-us")
print(result)
self.assertIsNotNone(result)
self.assertEqual(result.intent_service, 'OCP_fallback')
self.assertEqual(result.intent_type, 'ocp:play')

def test_match_fallback_with_invalid_input(self):
result = self.ocp.match_fallback(["do the thing"], "en-us")
result = self.ocp.match_low(["do the thing"], "en-us")
self.assertIsNone(result)

def test_predict(self):
Expand Down
Loading