14 Commits

Author SHA1 Message Date
nunks 87920bb2c0 dockerfile buscando da branch modificada 2026-05-31 18:23:43 -03:00
nunks bf73f99907 Tentando conciliar as novidades com as minhas alteracoes 2026-05-31 17:46:32 -03:00
nunks 496ff9bb52 Adicionando skills para tocar mais musicas do artista/album que esta sendo tocado no momento
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-15 18:24:35 -03:00
nunks b27b77c572 Adicionando skills para tocar mais musicas do artista/album que esta sendo tocado no momento
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-15 18:08:49 -03:00
nunks e0b8cb71e4 Adicionando skills para tocar mais musicas do artista/album que esta sendo tocado no momento
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-15 17:56:11 -03:00
nunks a702b1befd Adicionando skills para tocar mais musicas do artista/album que esta sendo tocado no momento
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-15 17:50:11 -03:00
nunks d748ee2602 Adicionando skills para tocar mais musicas do artista/album que esta sendo tocado no momento
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-15 17:38:56 -03:00
nunks 609109dd17 Adicionando skills para tocar mais musicas do artista/album que esta sendo tocado no momento
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-15 17:15:49 -03:00
nunks c44b22d486 melhorando as falas da alexa
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-08 21:39:53 -03:00
nunks 4a36f0561b dockerfile mais enxuto
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-08 20:57:13 -03:00
nunks 4e9d03e774 testando alterar dockerfile
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-08 20:44:27 -03:00
nunks 46e9203677 testando alterar dockerfile
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-08 20:39:17 -03:00
nunks aa4d19aafd testando alterar dockerfile
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-08 13:03:04 -03:00
nunks 2ee1abd813 customizadas em portugues: interaction model e respostas da skill
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2025-11-08 12:50:08 -03:00
3 changed files with 194 additions and 92 deletions
+8 -19
View File
@@ -1,34 +1,23 @@
FROM alpine:3.22.1 AS build
LABEL maintainer="Ross Stewart <rosskouk@gmail.com>"
LABEL org.opencontainers.image.source=https://github.com/rosskouk/asknavidrome
RUN apk add python3 py3-pip git build-base python3-dev libffi-dev openssl-dev
WORKDIR /opt
RUN pwd
RUN python3 -m venv env
RUN git clone https://github.com/rosskouk/asknavidrome.git
WORKDIR /opt/asknavidrome
RUN ls -la
RUN git clone -b nunks https://g.nunks.org/nunks/asknavidrome-cafofo.git
RUN ls -la asknavidrome-cafofo
WORKDIR /opt/asknavidrome-cafofo
RUN pwd
RUN ls -la
RUN source ../env/bin/activate && pip --no-cache-dir install wheel && pip --no-cache-dir install -r skill/requirements-docker.txt
FROM alpine:3.22.1
LABEL maintainer="Ross Stewart <rosskouk@gmail.com>"
LABEL org.opencontainers.image.source=https://github.com/rosskouk/asknavidrome
RUN apk add python3
COPY --from=build /opt/env /opt/env
COPY --from=build /opt/asknavidrome/skill /opt/asknavidrome/
COPY --from=build /opt/asknavidrome-cafofo/skill /opt/asknavidrome/
WORKDIR /opt/asknavidrome
# Activate Python Virtual Environment
ENV PATH="/opt/env/bin:$PATH"
EXPOSE 5000
ENTRYPOINT ["python3", "app.py"]
+57 -49
View File
@@ -1,7 +1,7 @@
{
"interactionModel": {
"languageModel": {
"invocationName": "navisonic",
"invocationName": "cafofo music",
"intents": [
{
"name": "AMAZON.CancelIntent",
@@ -40,8 +40,8 @@
}
],
"samples": [
"play songs by {artist}",
"play music by {artist}"
"tocar músicas da {artist}",
"tocar músicas do {artist}"
]
},
{
@@ -65,8 +65,20 @@
}
],
"samples": [
"Play the album {album}",
"Play the album {album} by {artist}"
"Tocar o album {album}",
"Tocar o album {album} do {artist}",
"Tocar o album {album} da {artist}",
"Tocar o disco {album}",
"Tocar o disco {album} do {artist}",
"Tocar o disco {album} da {artist}"
]
},
{
"name": "NaviSonicPlayMusicByCurrentAlbum",
"slots": [],
"samples": [
"Tocar mais músicas desse album",
"Tocar mais músicas desse disco"
]
},
{
@@ -78,49 +90,42 @@
}
],
"samples": [
"Play the {playlist} playlist",
"Start the {playlist} playlist"
"Tocar a playlist {playlist}"
]
},
{
"name": "NaviSonicSongDetails",
"slots": [],
"samples": [
"What is playing",
"Who is singing",
"Who's singing",
"What album is this song on",
"What album is this on",
"Which album",
"Which album is this song from",
"Which artist is this",
"What band is this",
"Who sings this song",
"Who sings this",
"What song is this",
"What's playing"
"O que está tocando",
"Quem está tocando",
"Quem está cantando",
"Qual o album dessa música",
"Que banda é essa",
"Que musica é essa",
"Que banda é essa"
]
},
{
"name": "NaviSonicStarSong",
"slots": [],
"samples": [
"Add this song to my favourites",
"Favourite this song",
"Like this song",
"Add this song to my liked songs",
"Star this song"
"Adicionar música aos favoritos",
"Adicionar aos favoritos",
"Favoritar essa musica",
"Lembrar dessa música",
"Eu gosto dessa música"
]
},
{
"name": "NaviSonicUnstarSong",
"slots": [],
"samples": [
"Remove this song from favourites",
"I don't like this song",
"Remove the star from this song",
"Delete this song from my favourites",
"Unstar this song"
"Tirar a música dos favoritos",
"Tirar dos favoritos",
"Desfavoritar a música",
"Esquecer essa música",
"Eu não gosto dessa música"
]
},
{
@@ -136,21 +141,27 @@
}
],
"samples": [
"Play the song {song} by the band {artist}",
"Play {song} by the band {artist}",
"Play {song} by {artist}",
"Play the song {song} by the artist {artist}"
"Tocar a música {song} da banda {artist}",
"Tocar {song} da banda {artist}",
"Tocar {song} da {artist}"
]
},
{
"name": "NaviSonicPlayMusicByCurrentArtist",
"slots": [],
"samples": [
"Tocar mais músicas desse artista",
"Tocar mais músicas desse grupo",
"Tocar mais músicas dessa banda"
]
},
{
"name": "NaviSonicPlayFavouriteSongs",
"slots": [],
"samples": [
"Play my starred tracks",
"Play starred tracks",
"Play starred songs",
"Play my starred songs",
"Play my favourite songs"
"Tocar favoritos",
"Tocar meus favoritos",
"Tocar minhas músicas favoritas"
]
},
{
@@ -162,29 +173,26 @@
}
],
"samples": [
"Play {genre} songs",
"Play {genre} music"
"Tocar {genre}"
]
},
{
"name": "NaviSonicPlayMusicRandom",
"slots": [],
"samples": [
"Play a selection of music",
"Play a mix of tracks",
"Play a mix of songs",
"Play random music",
"Play random songs"
"Tocar seleção aleatória",
"Tocar qualquer coisa",
"Tocar mix",
"Tocar músicas aleatórias"
]
},
{
"name": "NaviSonicRandomiseQueue",
"slots": [],
"samples": [
"randomise the queue",
"randomise",
"shuffle",
"shuffle the queue"
"shuffle na lista",
"mistura tudo"
]
}
],
+127 -22
View File
@@ -222,7 +222,7 @@ class LaunchRequestHandler(AbstractRequestHandler):
logger.debug('In LaunchRequestHandler')
connection.ping()
speech = sanitise_speech_output('Ready!')
speech = sanitise_speech_output('Simbora!')
handler_input.response_builder.speak(speech).ask(speech)
return handler_input.response_builder.response
@@ -311,7 +311,8 @@ class NaviSonicPlayMusicByArtist(AbstractRequestHandler):
artist_lookup = connection.search_artist(artist.value)
if artist_lookup is None:
text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
#text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
text = sanitise_speech_output(f"Não achei o artista {artist.value} na nossa coleção.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -328,7 +329,8 @@ class NaviSonicPlayMusicByArtist(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output(f'Playing music by: {artist.value}')
#speech = sanitise_speech_output(f'Playing music by: {artist.value}')
speech = sanitise_speech_output(f'Tocando músicas de: {artist.value}')
logger.info(speech)
card = {'title': 'AskNavidrome',
@@ -339,6 +341,97 @@ class NaviSonicPlayMusicByArtist(AbstractRequestHandler):
track_details = play_queue.get_next_track()
return controller.start_playback('play', speech, card, track_details, handler_input)
def get_current_song_details():
current_track = play_queue.get_current_track()
logger.debug(current_track)
return {
"title": current_track.title,
"artist": current_track.artist,
"album": current_track.album,
"_sanitized": {
"title": sanitise_speech_output(current_track.title),
"artist": sanitise_speech_output(current_track.artist),
"album": sanitise_speech_output(current_track.album)
}
}
class NaviSonicPlayMusicByCurrentArtist(AbstractRequestHandler):
"""Handle NaviSonicPlayMusicByCurrentArtist Intent
Plays more music of the current playing Artist
"""
def can_handle(self, handler_input: HandlerInput) -> bool:
return is_intent_name('NaviSonicPlayMusicByCurrentArtist')(handler_input)
def handle(self, handler_input: HandlerInput) -> Response:
global backgroundProcess
logger.debug('In NaviSonicPlayMusicByCurrentArtist Handler (custom)')
if backgroundProcess is not None:
backgroundProcess.terminate()
backgroundProcess.join()
t = get_current_song_details() #current "T"rack
artist_lookup = connection.search_artist(t["artist"])
artist_album_lookup = connection.albums_by_artist(artist_lookup[0].get('id'))
song_id_list = connection.build_song_list_from_albums(artist_album_lookup, min_song_count)
play_queue.clear()
controller.enqueue_songs(connection, play_queue, [song_id_list[0], song_id_list[1]]) # When generating the playlist return the first two tracks.
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output(f'Tocando mais músicas de {t["artist"]}')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
}
play_queue.shuffle()
track_details = play_queue.get_next_track()
return controller.start_playback('play', speech, card, track_details, handler_input)
class NaviSonicPlayMusicByCurrentAlbum(AbstractRequestHandler):
"""Handle NaviSonicPlayMusicByCurrentAlbum Intent
Plays more music of the current playing Album
"""
def can_handle(self, handler_input: HandlerInput) -> bool:
return is_intent_name('NaviSonicPlayMusicByCurrentAlbum')(handler_input)
def handle(self, handler_input: HandlerInput) -> Response:
global backgroundProcess
logger.debug('In NaviSonicPlayMusicByCurrentAlbum Handler (custom)')
if backgroundProcess is not None:
backgroundProcess.terminate()
backgroundProcess.join()
t = get_current_song_details() #current "T"rack
artist_lookup = connection.search_artist(t["artist"])
artist_album_lookup = connection.albums_by_artist(artist_lookup[0].get('id'))
result = [album_result for album_result in artist_album_lookup if album_result.get('name').lower() == t["album"].lower()]
song_id_list = connection.build_song_list_from_albums(result, -1)
play_queue.clear()
controller.enqueue_songs(connection, play_queue, [song_id_list[0], song_id_list[1]]) # When generating the playlist return the first two tracks.
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output(f'Tocando mais músicas do album {t["album"]}, de {t["artist"]}')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
}
play_queue.shuffle()
track_details = play_queue.get_next_track()
return controller.start_playback('play', speech, card, track_details, handler_input)
class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
"""Handle NaviSonicPlayAlbumByArtist
@@ -371,7 +464,8 @@ class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
artist_lookup = connection.search_artist(artist.value)
if artist_lookup is None:
text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
#text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
text = sanitise_speech_output(f"Não achei o artista {artist.value} na nossa coleção.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -384,7 +478,8 @@ class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
result = [album_result for album_result in artist_album_lookup if album_result.get('name').lower() == album.value.lower()]
if not result:
text = sanitise_speech_output(f"I couldn't find an album called {album.value} by {artist.value} in the collection.")
#text = sanitise_speech_output(f"I couldn't find an album called {album.value} by {artist.value} in the collection.")
text = sanitise_speech_output(f"Não achei na nossa coleção um disco chamado {album.value} de {artist.value}.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -398,7 +493,8 @@ class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output(f'Playing {album.value} by: {artist.value}')
#speech = sanitise_speech_output(f'Playing {album.value} by: {artist.value}')
speech = sanitise_speech_output(f'Tocando o álbum {album.value} de: {artist.value}')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -414,7 +510,8 @@ class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
result = connection.search_album(album.value)
if result is None:
text = sanitise_speech_output(f"I couldn't find the album {album.value} in the collection.")
#text = sanitise_speech_output(f"I couldn't find the album {album.value} in the collection.")
text = sanitise_speech_output(f"Não achei o disco {album.value} na nossa coleção.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -428,7 +525,7 @@ class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output(f'Playing {album.value}')
speech = sanitise_speech_output(f'Tocando o disco {album.value}')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -461,7 +558,8 @@ class NaviSonicPlaySongByArtist(AbstractRequestHandler):
artist_lookup = connection.search_artist(artist.value)
if artist_lookup is None:
text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
#text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
text = sanitise_speech_output(f"Não achei o artista {artist.value} na nossa coleção.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -476,7 +574,8 @@ class NaviSonicPlaySongByArtist(AbstractRequestHandler):
song_dets = [item.get('id') for item in song_list if item.get('artistId') == artist_id]
if not song_dets:
text = sanitise_speech_output(f"I couldn't find a song called {song.value} by {artist.value} in the collection.")
#text = sanitise_speech_output(f"I couldn't find a song called {song.value} by {artist.value} in the collection.")
text = sanitise_speech_output(f"Não achei uma música chamada {song.value} de {artist.value} na nossa coleção.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -484,7 +583,7 @@ class NaviSonicPlaySongByArtist(AbstractRequestHandler):
play_queue.clear()
controller.enqueue_songs(connection, play_queue, song_dets)
speech = sanitise_speech_output(f'Playing {song.value} by {artist.value}')
speech = sanitise_speech_output(f'Tocando {song.value} de {artist.value}')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -520,7 +619,7 @@ class NaviSonicPlayPlaylist(AbstractRequestHandler):
playlist_id = connection.search_playlist(playlist.value)
if playlist_id is None:
text = sanitise_speech_output("I couldn't find the playlist " + str(playlist.value) + ' in the collection.')
text = sanitise_speech_output("Não achei a playlist " + str(playlist.value) + ' na nossa coleção.')
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -534,7 +633,7 @@ class NaviSonicPlayPlaylist(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output('Playing playlist ' + str(playlist.value))
speech = sanitise_speech_output('Tocando a playlist ' + str(playlist.value))
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -569,7 +668,7 @@ class NaviSonicPlayMusicByGenre(AbstractRequestHandler):
song_id_list = connection.build_song_list_from_genre(genre.value, min_song_count)
if song_id_list is None:
text = sanitise_speech_output(f"I couldn't find any {genre.value} songs in the collection.")
text = sanitise_speech_output(f"Não achei nada do estilo {genre.value} na nossa coleção.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -583,7 +682,7 @@ class NaviSonicPlayMusicByGenre(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output(f'Playing {genre.value} music')
speech = sanitise_speech_output(f'Tocando músicas do estilo {genre.value}')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -615,7 +714,8 @@ class NaviSonicPlayMusicRandom(AbstractRequestHandler):
song_id_list = connection.build_random_song_list(min_song_count)
if song_id_list is None:
text = sanitise_speech_output("I couldn't find any songs in the collection.")
#text = sanitise_speech_output("I couldn't find any songs in the collection.")
text = sanitise_speech_output("Não achei nenhuma música na nossa coleção. Estranho.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -629,7 +729,7 @@ class NaviSonicPlayMusicRandom(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output('Playing random music')
speech = sanitise_speech_output('Tocando qualquer coisa aleatória')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -661,7 +761,7 @@ class NaviSonicPlayFavouriteSongs(AbstractRequestHandler):
song_id_list = connection.build_song_list_from_favourites()
if song_id_list is None:
text = sanitise_speech_output("You don't have any favourite songs in the collection.")
text = sanitise_speech_output("Não tenho nada nos favoritos.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -675,7 +775,7 @@ class NaviSonicPlayFavouriteSongs(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output('Playing your favourite tracks.')
speech = sanitise_speech_output('Tocando suas músicas favoritas.')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -721,7 +821,8 @@ class NaviSonicSongDetails(AbstractRequestHandler):
artist = sanitise_speech_output(current_track.artist)
album = sanitise_speech_output(current_track.album)
text = f'This is {title} by {artist}, from the album {album}'
# text = f'This is {title} by {artist}, from the album {album}'
text = f'Essa é {title} de {artist}, do album {album}'
handler_input.response_builder.speak(text)
return handler_input.response_builder.response
@@ -989,7 +1090,8 @@ class SystemExceptionHandler(AbstractExceptionHandler):
if get_request_type(handler_input) == 'IntentRequest':
logger.error(f'Intent Name Was: {get_intent_name(handler_input)}')
speech = sanitise_speech_output("Sorry, I didn't get that. Can you please say it again!!")
#speech = sanitise_speech_output("Sorry, I didn't get that. Can you please say it again!!")
speech = sanitise_speech_output("Foi mal, não entendi.")
handler_input.response_builder.speak(speech).ask(speech)
return handler_input.response_builder.response
@@ -1015,7 +1117,8 @@ class GeneralExceptionHandler(AbstractExceptionHandler):
if get_request_type(handler_input) == 'IntentRequest':
logger.error(f'Intent Name Was: {get_intent_name(handler_input)}')
speech = sanitise_speech_output("Sorry, I didn't get that. Can you please say it again!!")
#speech = sanitise_speech_output("Sorry, I didn't get that. Can you please say it again!!")
speech = sanitise_speech_output("Foi mal, não entendi. Pode repetir!!")
handler_input.response_builder.speak(speech).ask(speech)
return handler_input.response_builder.response
@@ -1114,6 +1217,8 @@ sb.add_request_handler(NaviSonicPlayPlaylist())
sb.add_request_handler(NaviSonicPlayFavouriteSongs())
sb.add_request_handler(NaviSonicPlayMusicByGenre())
sb.add_request_handler(NaviSonicPlayMusicRandom())
sb.add_request_handler(NaviSonicPlayMusicByCurrentArtist())
sb.add_request_handler(NaviSonicPlayMusicByCurrentAlbum())
sb.add_request_handler(NaviSonicRandomiseQueue())
sb.add_request_handler(NaviSonicSongDetails())
sb.add_request_handler(NaviSonicStarSong())