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

Container Improvements, OVOS Compatibility, Optimization, Bugfixes #51

Merged
merged 27 commits into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b8149f0
Improved Container Support (#49)
NeonDaniel Jan 25, 2022
549e270
Increment Version
NeonDaniel Jan 25, 2022
5f67def
Add one-time config initialization (#52)
NeonDaniel Feb 1, 2022
13faf70
Increment Version
NeonDaniel Feb 1, 2022
ed12b5a
Refactor Signal Handling for SignalManager (#42)
NeonDaniel Feb 7, 2022
6854c19
Increment Version
NeonDaniel Feb 7, 2022
1a459c0
Remove mimic fallbackTTS deprecated in ovos-core 0.0.2 (#50)
NeonDaniel Feb 7, 2022
6956da8
Increment Version
NeonDaniel Feb 7, 2022
e7661b8
Loosen ovos-plugin-manager dependency spec (#53)
NeonDaniel Feb 19, 2022
ad4d71c
Increment Version
NeonDaniel Feb 19, 2022
091150b
Troubleshoot ovos package compatible versions (#55)
NeonDaniel Feb 23, 2022
7c48c38
Increment Version
NeonDaniel Feb 23, 2022
f1a4f49
Update Docker dependency specs (#56)
NeonDaniel Feb 23, 2022
f3ecb82
Increment Version
NeonDaniel Feb 23, 2022
7cfd7d0
Minor bugfixes and klat.response changes (#58)
NeonDaniel Mar 18, 2022
f423f6d
Increment Version
NeonDaniel Mar 18, 2022
ccc5983
OPM Refactor (#59)
NeonDaniel Apr 1, 2022
7b2f5e3
Increment Version
NeonDaniel Apr 1, 2022
5f9a71b
add license tests and workflow (#61)
NeonDaniel Apr 8, 2022
0ab6f2a
Increment Version
NeonDaniel Apr 8, 2022
bfa2360
Install Plugin on Launch (#60)
NeonDaniel Apr 8, 2022
16fc420
Increment Version
NeonDaniel Apr 8, 2022
26d633b
Logging, Caching, Dependency Update (#62)
NeonDaniel Apr 29, 2022
9bc5993
Increment Version
NeonDaniel Apr 29, 2022
59a67cc
Move ovos-core dependency to base requirements and update version spe…
NeonDaniel May 9, 2022
691d260
Increment Version
NeonDaniel May 9, 2022
423fb9a
Increment version to 1.0.0 (#64)
NeonDaniel May 10, 2022
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
35 changes: 35 additions & 0 deletions .github/workflows/license_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Run License Tests
on:
push:
workflow_dispatch:

jobs:
license_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: ${{ github.head_ref }}
- name: Setup Python
uses: actions/setup-python@v1
with:
python-version: 3.8
- name: Install Build Tools
run: |
python -m pip install build wheel
- name: Install System Dependencies
run: |
sudo apt-get update
sudo apt install python3-dev swig libssl-dev
- name: Install core repo
run: |
pip install .
- name: Install licheck
run: |
pip install git+https://github.com/NeonJarbas/lichecker
- name: Install test dependencies
run: |
pip install pytest pytest-timeout pytest-cov
- name: Test Licenses
run: |
pytest tests/license_tests.py
28 changes: 25 additions & 3 deletions .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,30 @@ on:
workflow_dispatch:

jobs:
py_build_tests:
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install Build Tools
run: |
python -m pip install build wheel
- name: Build Distribution Packages
run: |
python setup.py bdist_wheel sdist
docker_build_tests:
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build image
run: docker build .
unit_tests:
timeout-minutes: 15
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
Expand All @@ -22,8 +45,7 @@ jobs:
sudo apt update
sudo apt install portaudio19-dev python3-pyaudio
python -m pip install --upgrade pip
pip install -r requirements/requirements.txt
pip install -r requirements/test_requirements.txt
pip install . -r requirements/test_requirements.txt

- name: Test Base Classes
run: |
Expand All @@ -40,7 +62,7 @@ jobs:
run: |
pytest tests/api_method_tests.py --doctest-modules --junitxml=tests/api-method-test-results.xml
env:
TTS_URL: ${{secrets.tts_url}}
TTS_URL: https://mtts.2022.us
- name: Upload API Method test results
uses: actions/upload-artifact@v2
with:
Expand Down
59 changes: 38 additions & 21 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,30 +1,47 @@
FROM python:3.8
FROM python:3.8-slim

LABEL vendor=neon.ai \
ai.neon.name="neon-audio"

ADD . /neon_audio
WORKDIR /neon_audio

ENV NEON_CONFIG_PATH /config

RUN apt-get update && \
apt-get install -y \
curl \
gpg

RUN curl https://forslund.github.io/mycroft-desktop-repo/mycroft-desktop.gpg.key | \
gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/mycroft-desktop.gpg --import - && \
chmod a+r /etc/apt/trusted.gpg.d/mycroft-desktop.gpg && \
echo "deb http://forslund.github.io/mycroft-desktop-repo bionic main" \
> /etc/apt/sources.list.d/mycroft-mimic.list

RUN apt-get update && \
apt-get install -y \
alsa-utils \
libasound2-plugins \
pulseaudio-utils \
sox \
vlc \
ffmpeg \
mimic \
gcc \
g++ \
libsndfile1 \
espeak-ng \
git # Added to handle installing plugins from git

# Install TTS for Coqui plugin here to reduce time and layer size
RUN pip install tts==0.6.2

RUN curl https://forslund.github.io/mycroft-desktop-repo/mycroft-desktop.gpg.key | \
apt-key add - 2>/dev/null && \
echo "deb http://forslund.github.io/mycroft-desktop-repo bionic main" \
> /etc/apt/sources.list.d/mycroft-mimic.list && \
apt-get update && \
apt-get install -y alsa-utils libasound2-plugins pulseaudio-utils mimic sox vlc && \
pip install wheel && \
pip install .[docker]

RUN useradd -ms /bin/bash neon
USER neon
ADD . /neon_audio
WORKDIR /neon_audio

COPY docker_overlay/asoundrc /home/neon/.asoundrc
COPY docker_overlay/mycroft.conf /home/neon/.mycroft/mycroft.conf
RUN pip install wheel && \
pip install .[docker]

RUN mkdir -p /home/neon/.config/pulse && \
mkdir -p /home/neon/.config/neon && \
mkdir -p /home/neon/.local/share/neon && \
rm -rf ~/.cache
COPY docker_overlay/ /
RUN chmod ugo+x /root/run.sh

CMD ["neon_audio_client"]
CMD ["/root/run.sh"]
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@ to start the container.
docker run -d \
--network=host \
--name=neon_audio \
-v ${NEON_DATA_DIR}:/home/neon/.local/share/neon:rw \
-v ${NEON_CONFIG_DIR}:/home/neon/.config/neon:rw \
-v ~/.config/pulse/cookie:/home/neon/.config/pulse/cookie:ro \
-v ~/.config/pulse/cookie:/root/.config/pulse/cookie:ro \
-v ${XDG_RUNTIME_DIR}/pulse:${XDG_RUNTIME_DIR}/pulse:ro \
-v ${NEON_CONFIG_DIR}:/config \
--device=/dev/snd:/dev/snd \
-e PULSE_SERVER=unix:${XDG_RUNTIME_DIR}/pulse/native \
-e PULSE_COOKIE=/home/neon/.config/pulse/cookie \
-e PULSE_COOKIE=/root/.config/pulse/cookie \
neon_audio
```

>*Note:* The above example assumes Docker data is stored in the standard user locations `~/.local/share` and `~/.config`.
> You may want to change these values to some other path to separate container and host system data.
>*Note:* The above example assumes `NEON_CONFIG_DIR` contains valid configuration
File renamed without changes.
15 changes: 15 additions & 0 deletions docker_overlay/root/.config/OpenVoiceOS/ovos.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"module_overrides": {
"neon_core": {
"xdg": true,
"base_folder": "neon",
"config_filename": "neon.conf",
"default_config_path": "/lib/python3.8/site-packages/mycroft/configuration/mycroft.conf"
}
},
"submodule_mappings": {
"neon_speech": "neon_core",
"neon_audio": "neon_core",
"neon_enclosure": "neon_core"
}
}
File renamed without changes.
32 changes: 32 additions & 0 deletions docker_overlay/root/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash
# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework
# All trademark and other rights reserved by their respective owners
# Copyright 2008-2022 Neongecko.com Inc.
# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds,
# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo
# BSD-3 License
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Plugin installation must occur in a separate thread, before module load, for the entry point to be loaded.
neon-audio install-plugin -f
neon-audio run
45 changes: 1 addition & 44 deletions neon_audio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,4 @@
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import time
from ovos_utils.signal import check_for_signal, create_signal
from neon_utils.configuration_utils import get_neon_local_config


IPC_PATH = get_neon_local_config().get("dirVars", {}).get("ipcDir", "/tmp/neon/ipc")
CONFIG = {"ipc_path": IPC_PATH}


def is_speaking():
"""Determine if Text to Speech is occurring

Returns:
bool: True while still speaking
"""
return check_for_signal("isSpeaking", -1, CONFIG)


def wait_while_speaking():
"""Pause as long as Text to Speech is still happening

Pause while Text to Speech is still happening. This always pauses
briefly to ensure that any preceeding request to speak has time to
begin.
"""
# TODO: Better method using messages or signals here DM
time.sleep(0.3) # Wait briefly in for any queued speech to begin
while is_speaking():
time.sleep(0.1)


def stop_speaking():
# TODO: Less hacky approach to this once Audio Manager is implemented
# Skills should only be able to stop speech they've initiated
from mycroft_bus_client.send_func import send
create_signal('stoppingTTS')
send('mycroft.audio.speech.stop')

# Block until stopped
while check_for_signal("isSpeaking", -1, CONFIG):
time.sleep(0.25)

# This consumes the signal
check_for_signal('stoppingTTS', CONFIG)
from mycroft.audio.utils import wait_while_speaking, is_speaking, stop_speaking
51 changes: 39 additions & 12 deletions neon_audio/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from neon_utils.configuration_utils import get_neon_device_type
from neon_utils.messagebus_utils import get_messagebus
from neon_utils.configuration_utils import get_neon_device_type, \
init_config_dir
from neon_utils.logger import LOG

from ovos_utils.process_utils import ProcessStatus, StatusCallbackMap

from neon_audio import speech
from neon_audio.audioservice import AudioService
from neon_audio.audioservice import NeonAudioService

from mycroft.util.process_utils import ProcessStatus, StatusCallbackMap, start_message_bus_client
from mycroft.util import reset_sigint_handler, wait_for_exit_signal, check_for_signal
from mycroft.util import reset_sigint_handler, wait_for_exit_signal


def on_ready():
Expand All @@ -41,35 +44,59 @@ def on_stopping():
LOG.info('Audio service is shutting down...')


def main(ready_hook=on_ready, error_hook=on_error, stopping_hook=on_stopping, config: dict = None):
def on_alive():
pass


def on_started():
pass


def main(ready_hook=on_ready, error_hook=on_error, stopping_hook=on_stopping,
alive_hook=on_alive, started_hook=on_started, config: dict = None):
"""
Main function. Run when file is invoked.
:param ready_hook: Optional function to call when service is ready
:param error_hook: Optional function to call when service encounters an error
:param stopping_hook: Optional function to call when service is stopping
:param alive_hook: Optional function to call when service is alive
:param started_hook: Optional function to call when service is started
:param config: dict configuration containing keys: ['tts', 'Audio', 'language']
"""
init_config_dir()
reset_sigint_handler()
check_for_signal("isSpeaking")
whitelist = ['mycroft.audio.service']
bus = start_message_bus_client("AUDIO", whitelist=whitelist)

bus = get_messagebus()
callbacks = StatusCallbackMap(on_ready=ready_hook, on_error=error_hook,
on_stopping=stopping_hook)
on_stopping=stopping_hook,
on_alive=alive_hook, on_started=started_hook)
status = ProcessStatus('audio', bus, callbacks)
try:
speech.init(bus, config)

from neon_utils.signal_utils import init_signal_bus,\
init_signal_handlers, check_for_signal
init_signal_bus(bus)
init_signal_handlers()

check_for_signal("isSpeaking")

# Connect audio service instance to message bus
if get_neon_device_type() == 'server':
audio = None
else:
audio = AudioService(bus, config) # Connect audio service instance to message bus

audio = NeonAudioService(bus, config) # Connect audio service instance to message bus
status.set_started()
except Exception as e:
LOG.error(e)
status.set_error(e)
else:
if not audio or audio.wait_for_load() and len(audio.service) > 0:
if not audio or len(audio.service) == 0:
LOG.warning("No audio services loaded")
status.set_ready()
wait_for_exit_signal()
status.set_stopping()
if audio.wait_for_load():
# If at least one service exists, report ready
status.set_ready()
wait_for_exit_signal()
Expand Down
Loading