Skip to content

Commit

Permalink
feat: save/load game intent (#44)
Browse files Browse the repository at this point in the history
* feat: save/load game intent

improve intent matching when games are the active media

* update locale

* update locale

* update locale

* Apply suggestions from code review

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • Loading branch information
JarbasAl and coderabbitai[bot] authored Dec 18, 2024
1 parent e6a2298 commit 7d0a89f
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 15 deletions.
3 changes: 3 additions & 0 deletions ocp_pipeline/locale/en-us/load_game.intent
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
load
load [the] game
load [the] (last|previous) [saved] game
3 changes: 2 additions & 1 deletion ocp_pipeline/locale/en-us/next.intent
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
(play|go to) next (music|song|track|video|media)
next
next (song|track|music|movie|video|tune)
play next
play next
(play|go to) [the] next (song|track|music|movie|video|tune)
2 changes: 1 addition & 1 deletion ocp_pipeline/locale/en-us/open.intent
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
open (OCP|O C P|common|ovos|open voice os) (player|media player)
open (OCP|O C P|ovos common play|common play|ovos media player|open voice os player) (home screen|home page|homescreen|homepage|menu)
open (OCP|O C P|ovos common play|open voice os common play|common play)
open (media|music|gui|video) (player|catalog|skills|menu|playback)
open [the] (media|music|gui|video) (player|catalog|skills|menu|playback)
2 changes: 1 addition & 1 deletion ocp_pipeline/locale/en-us/pause.intent
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pause
pause (music|song|track|video|media|playback)
pause [the] (music|song|track|video|media|playback|game)
3 changes: 2 additions & 1 deletion ocp_pipeline/locale/en-us/prev.intent
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
(play previous|previous) (music|song|track|video|media)
(play previous|previous|go back)
previous
previous (song|track|music|movie|video|tune)
previous (song|track|music|movie|video|tune)
(play|go to) [the] previous (song|track|music|movie|video|tune)
2 changes: 1 addition & 1 deletion ocp_pipeline/locale/en-us/read.intent
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
read (book|audiobook|audio book) {query}
read [the] (book|audiobook|audio book) {query}
read {query}
read {query} (book|audiobook|audio book)
2 changes: 1 addition & 1 deletion ocp_pipeline/locale/en-us/resume.intent
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
(unpause|resume)
(unpause|resume|continue|restart) (music|song|track|video|media|playback)
(unpause|resume|continue|restart) [the] (music|song|track|video|media|playback|game)
play
2 changes: 2 additions & 0 deletions ocp_pipeline/locale/en-us/save_game.intent
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
save
save [the] game
48 changes: 47 additions & 1 deletion ocp_pipeline/opm.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class OCPPlayerProxy:
player_state: PlayerState = PlayerState.STOPPED
media_state: MediaState = MediaState.UNKNOWN
media_type: MediaType = MediaType.GENERIC
skill_id: Optional[str] = None


# for easier typing
Expand All @@ -47,7 +48,7 @@ class OCPPlayerProxy:
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"]
"resume.intent", "like_song.intent", "save_game.intent", "load_game.intent"]
intent_matchers = {}
intent_cache = f"{xdg_data_home()}/{get_xdg_base()}/intent_cache"

Expand Down Expand Up @@ -187,6 +188,8 @@ def register_ocp_intents(self):
self.add_event("ocp:media_stop", self.handle_stop_intent, is_intent=True)
self.add_event("ocp:search_error", self.handle_search_error_intent, is_intent=True)
self.add_event("ocp:like_song", self.handle_like_intent, is_intent=True)
self.add_event("ocp:save_game", self.handle_save_intent, is_intent=True)
self.add_event("ocp:load_game", self.handle_load_intent, is_intent=True)

def update_player_proxy(self, player: OCPPlayerProxy):
"""remember OCP session state"""
Expand Down Expand Up @@ -289,6 +292,7 @@ def handle_track_state_update(self, message: Message):
TrackState.PLAYING_MPRIS]:
player = self.get_player(message)
player.player_state = PlayerState.PLAYING
player = self._update_player_skill_id(player, message)
LOG.info(f"Session: {player.session_id} OCP PlayerState: PlayerState.PLAYING")
self.update_player_proxy(player)

Expand All @@ -310,6 +314,7 @@ def handle_player_state_update(self, message: Message):
if mtype is not None:
player.media_type = MediaType(pstate)
LOG.debug(f"Session: {player.session_id} MediaType: {player.media_type}")
player = self._update_player_skill_id(player, message)
self.update_player_proxy(player)

# pipeline
Expand Down Expand Up @@ -347,6 +352,21 @@ def match_high(self, utterances: List[str], lang: str, message: Message = None)

player = self.get_player(message)

if player.media_type == MediaType.GAME:
# if the user is currently playing a game
# disable: next/prev/shuffle/... intents
# enable: load/save intents
game_blacklist = ["next", "prev", "open", "like_song", "play_favorites"]
if match["name"] in game_blacklist:
LOG.info(f'Ignoring OCP intent match {match["name"]}, playing MediaType.GAME')
return None
else:
# if no game is being played, disable game specific intents
game_only = ["save_game"]
if match["name"] in game_only:
LOG.info(f'Ignoring OCP intent match {match["name"]}, not playing MediaType.GAME')
return None

if match["name"] == "play":
utterance = match["entities"].pop("query")
return self._process_play_query(utterance, lang, match)
Expand Down Expand Up @@ -535,6 +555,14 @@ def _normalize_media_enum(m: Union[int, MediaType]):
return e
raise ValueError(f"{m} is not a valid media type")

def handle_save_intent(self, message: Message):
skill_id = self.get_player(message).skill_id
self.bus.emit(message.forward(f"ovos.common_play.{skill_id}.save"))

def handle_load_intent(self, message: Message):
skill_id = self.get_player(message).skill_id
self.bus.emit(message.forward(f"ovos.common_play.{skill_id}.load"))

def handle_play_intent(self, message: Message):

if not len(self.skill_aliases): # skill_id registered when skills load
Expand Down Expand Up @@ -574,6 +602,8 @@ def handle_play_intent(self, message: Message):

# ovos-PHAL-plugin-mk1 will display music icon in response to play message
player = self.get_player(message)
player.skill_id = best.skill_id
self.update_player_proxy(player)
if not player.ocp_available:
self.legacy_play(results, query, message=message)
else:
Expand Down Expand Up @@ -603,6 +633,7 @@ def handle_stop_intent(self, message: Message):
self.ocp_api.stop(source_message=message)
player = self.get_player(message)
player.player_state = PlayerState.STOPPED
player.skill_id = None
self.update_player_proxy(player)

def handle_next_intent(self, message: Message):
Expand Down Expand Up @@ -633,6 +664,7 @@ def handle_pause_intent(self, message: Message):
self.ocp_api.pause(source_message=message)
player = self.get_player(message)
player.player_state = PlayerState.PAUSED
player = self._update_player_skill_id(player, message)
self.update_player_proxy(player)

def handle_resume_intent(self, message: Message):
Expand All @@ -645,6 +677,7 @@ def handle_resume_intent(self, message: Message):
self.ocp_api.resume(source_message=message)
player = self.get_player(message)
player.player_state = PlayerState.PLAYING
player = self._update_player_skill_id(player, message)
self.update_player_proxy(player)

def handle_search_error_intent(self, message: Message):
Expand Down Expand Up @@ -833,6 +866,13 @@ def get_player(self, message: Optional[Message] = None, timeout=1) -> OCPPlayerP
player = self._player_sync(player, message, timeout)
return player

@staticmethod
def _update_player_skill_id(player, message):
skill_id = message.data.get("skill_id") or message.context.get("skill_id")
if skill_id and skill_id != OCP_ID:
player.skill_id = skill_id
return player

@staticmethod
def normalize_results(results: RawResultsList) -> NormalizedResultsList:
# support Playlist and MediaEntry objects in tracks
Expand Down Expand Up @@ -1055,6 +1095,7 @@ def legacy_play(self, results: NormalizedResultsList, phrase="",
playing = True
self.legacy_api.play(real_uri, utterance=phrase, source_message=message)
player.player_state = PlayerState.PLAYING
player.skill_id = r.skill_id
self.update_player_proxy(player)
else:
self.legacy_api.queue(real_uri, source_message=message)
Expand All @@ -1064,34 +1105,39 @@ def _handle_legacy_audio_stop(self, message: Message):
if not player.ocp_available:
player.player_state = PlayerState.STOPPED
player.media_state = MediaState.NO_MEDIA
player.skill_id = None
self.update_player_proxy(player)

def _handle_legacy_audio_pause(self, message: Message):
player = self.get_player(message)
if not player.ocp_available and player.player_state == PlayerState.PLAYING:
player.player_state = PlayerState.PAUSED
player.media_state = MediaState.LOADED_MEDIA
player = self._update_player_skill_id(player, message)
self.update_player_proxy(player)

def _handle_legacy_audio_resume(self, message: Message):
player = self.get_player(message)
if not player.ocp_available and player.player_state == PlayerState.PAUSED:
player.player_state = PlayerState.PLAYING
player.media_state = MediaState.LOADED_MEDIA
player = self._update_player_skill_id(player, message)
self.update_player_proxy(player)

def _handle_legacy_audio_start(self, message: Message):
player = self.get_player(message)
if not player.ocp_available:
player.player_state = PlayerState.PLAYING
player.media_state = MediaState.LOADED_MEDIA
player = self._update_player_skill_id(player, message)
self.update_player_proxy(player)

def _handle_legacy_audio_end(self, message: Message):
player = self.get_player(message)
if not player.ocp_available:
player.player_state = PlayerState.STOPPED
player.media_state = MediaState.END_OF_MEDIA
player.skill_id = None
self.update_player_proxy(player)

@classmethod
Expand Down
5 changes: 2 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
ovos-workshop>=0.1.7,<4.0.0
ovos-classifiers
ovos-utils>=0.3.5,<1.0.0
ovos-plugin-manager>=0.5.0,<1.0.0
langcodes
ovos-utils[extras]>=0.3.5,<1.0.0
ovos-plugin-manager>=0.5.0,<1.0.0
21 changes: 16 additions & 5 deletions translations/en-us/intents.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,36 @@
"(play|go to) next (music|song|track|video|media)",
"play next",
"next",
"next (song|track|music|movie|video|tune)"
"next (song|track|music|movie|video|tune)",
"(play|go to) [the] next (song|track|music|movie|video|tune)"
],
"resume.intent": [
"(unpause|resume)",
"(unpause|resume|continue|restart) (music|song|track|video|media|playback)",
"(unpause|resume|continue|restart) [the] (music|song|track|video|media|playback|game)",
"play"
],
"read.intent": [
"read (book|audiobook|audio book) {query}",
"read [the] (book|audiobook|audio book) {query}",
"read {query}",
"read {query} (book|audiobook|audio book)"
],
"prev.intent": [
"(play previous|go back one) (music|song|track|video|media)",
"(play previous|previous) (music|song|track|video|media)",
"(play previous|previous|go back)",
"(play|go to) [the] previous (song|track|music|movie|video|tune)",
"previous",
"previous (song|track|music|movie|video|tune)"
],
"pause.intent": [
"pause",
"pause (music|song|track|video|media|playback)"
"pause [the] (music|song|track|video|media|playback|game)"
],
"open.intent": [
"open (OCP|O C P|common|ovos|open voice os) (player|media player)",
"open (OCP|O C P|ovos common play|common play|ovos media player|open voice os player) (home screen|home page|homescreen|homepage|menu)",
"open (OCP|O C P|ovos common play|open voice os common play|common play)",
"open (media|music|gui|video) (player|catalog|skills|menu|playback)"
"open [the] (media|music|gui|video) (player|catalog|skills|menu|playback)"
],
"featured.intent": [
"(open|show|display) (featured|) {media} (catalog|collection|playlist)",
Expand All @@ -59,5 +61,14 @@
"stop",
"stop (playback|media|media playback|music|movie|movies|noise)",
"stop everything"
],
"save_game.intent": [
"save",
"save [the] game"
],
"load_game.intent": [
"load",
"load [the] game",
"load [the] (last|previous) [saved] game"
]
}

0 comments on commit 7d0a89f

Please sign in to comment.