60 Commits

Author SHA1 Message Date
Michael Hansen 0c37c88e61 Update README.md 2020-06-08 09:33:28 -04:00
Michael Hansen 50f05506a2 Some extra README info 2020-06-08 09:32:00 -04:00
Michael Hansen b62068da69 Can't use classes in divs in the README, I guess 2020-06-08 09:29:55 -04:00
Michael Hansen f69d7484ba Update README to point to 2.5 repo 2020-06-08 09:27:56 -04:00
Michael Hansen e478765b4e Merge branch 'master' of https://github.com/synesthesiam/rhasspy 2020-06-02 09:44:51 -04:00
Michael Hansen 8bf673c412 Merge pull request #236 from Mic92/intent-docs
Intent docs
2020-06-02 09:44:39 -04:00
Michael Hansen 8854f26dc1 Merge branch 'master' of https://github.com/synesthesiam/rhasspy 2020-06-02 09:40:21 -04:00
Michael Hansen cf8f2319b8 Merge pull request #234 from devkid/patch-1
Enable speech response for Home Assistant intent handler
2020-06-02 09:40:06 -04:00
Michael Hansen 782721fab3 Merge branch 'master' of https://github.com/synesthesiam/rhasspy 2020-06-02 09:39:10 -04:00
Michael Hansen 43dc7a07c9 Add mosquitto tools to Docker runtime image 2020-06-02 09:38:49 -04:00
Jörg Thalheim be42447620 docs: note that mycroft adapt does not convert integers back yet. 2020-06-01 23:45:32 +01:00
Alfred Krohmer 3a884888c4 Enable speech response for Home Assistant intent handler 2020-06-01 21:37:34 +02:00
Michael Hansen 3133666390 Merge pull request #230 from Romkabouter/master
Fix Google Wavenet TTS
2020-05-29 16:16:13 -04:00
Paul Romkes ff0aea4177 Fix Google Wavenet TTS 2020-05-29 20:49:31 +02:00
Michael Hansen fa418d3129 Ensure setuptools is in Docker runtime image 2020-05-26 13:39:59 -04:00
Michael Hansen d4314a85d9 Force pip in runtime Docker image 2020-05-26 13:38:19 -04:00
Michael Hansen 3d42551bfc Merge pull request #227 from kroka/patch-2
force download if deletion is enabled
2020-05-26 13:33:44 -04:00
kroka 6411924cf2 force download if deletion is enabled
ignore that file might exist already,
change motivated by #213
2020-05-22 14:33:24 +02:00
Michael Hansen 77d2196f00 Add /ssl prefix for Hass.IO SSL settings 2020-04-23 16:59:29 -04:00
Michael Hansen 3c53cd0236 Fix ssl_context 2020-04-20 08:54:33 -04:00
Michael Hansen 46a75ec83e Use ssl context in aiohttp 2020-04-19 15:03:50 -04:00
Michael Hansen 3e9c4bef68 Clean up docker file and docker run.sh 2020-04-19 11:39:46 -04:00
Michael Hansen 465d1e61e0 Add asoundrc to Hass.io config path in docker run 2020-04-19 09:19:30 -04:00
Michael Hansen 563fcfcd49 Merge pull request #207 from pheelee/master
fixes startup on hass.io
2020-04-19 09:10:25 -04:00
pheelee 0ff965a965 fixes startup on hass.io 2020-04-19 12:35:56 +02:00
Michael Hansen 998eff8708 Merge branch 'master' of pumpkin.lan:Mike/Projects/rhasspy 2020-04-15 16:48:35 -04:00
Michael Hansen 1dcf984669 Fix Docker tag 2020-04-15 16:48:18 -04:00
Michael Hansen 21c2b2ef9d Only use system Python pre-venv create 2020-04-15 16:47:37 -04:00
Michael Hansen 958c12cfb4 Merge branch 'master' of pumpkin.lan:Mike/Projects/rhasspy 2020-04-15 16:03:39 -04:00
Michael Hansen 04efe9f151 Update CHANGELOG 2020-04-10 16:53:38 -04:00
Michael Hansen 6dbc8dc35e Fix arm64 arch 2020-04-10 13:45:07 -04:00
Michael Hansen 2cac48292a Fix raw_value in MQTT messages 2020-04-10 13:25:26 -04:00
Michael Hansen a4528d40fb Porting Docker build to buildx for multi-platform 2020-04-10 13:17:15 -04:00
Michael Hansen 4cd8b307c7 Merge branch 'master' of https://github.com/synesthesiam/rhasspy 2020-04-10 13:08:26 -04:00
Michael Hansen de0824e49a Merge pull request #201 from ofekd/mqtt-tls-support
Support MQTT over TLS
2020-04-10 11:38:18 -04:00
Michael Hansen 74ba8c1c4a Bump version 2020-04-10 11:07:38 -04:00
Michael Hansen 9428abdd40 Softer error for porcupine missing files 2020-04-10 11:05:35 -04:00
Michael Hansen a6c425d65f Properly accept websocket connections 2020-04-10 11:05:27 -04:00
Michael Hansen 015c37fa5d Refactor Dockerfile 2020-04-10 11:05:18 -04:00
Michael Hansen 32f7e37657 Fix typo 2020-04-10 09:39:31 -04:00
Ofek 54063feb03 Support MQTT over TLS 2020-04-09 23:31:48 +03:00
Michael Hansen 3bc36f2fb1 Correct HA intent docs 2020-03-26 16:32:37 -04:00
Michael Hansen e0401d4c18 Move Google imports inside STT class 2020-03-12 17:19:09 -04:00
Michael Hansen 73124075ae Don't try to download Kaldi for armv6l 2020-03-12 17:18:56 -04:00
Michael Hansen c410f4eea7 Fix typo 2020-03-12 17:17:25 -04:00
Michael Hansen 3f0545ed0f Bump version 2020-03-04 11:52:18 -05:00
Michael Hansen 331138f300 Updated CHANGELOG 2020-03-04 11:52:03 -05:00
Michael Hansen 33b847b828 Merge branch 'master' of https://github.com/synesthesiam/rhasspy 2020-03-04 11:48:53 -05:00
Michael Hansen d770679373 Fix first entity bug in Rasa NLU training 2020-03-04 11:48:02 -05:00
Michael Hansen 86e695a7a4 Merge pull request #184 from daniele-athome/rasa-min-confidence
Rasa: min confidence parameter
2020-03-03 20:55:00 -05:00
Daniele Ricci 07d1cc4e43 Rasa: min confidence parameter
Signed-off-by: Daniele Ricci <daniele@casaricci.it>
2020-02-25 20:03:23 +01:00
Michael Hansen b68e5caf01 Merge pull request #182 from Tooa/follow_up_178
Prevent porcupine incompatibilities
2020-02-24 16:59:28 -05:00
Uli da4d994e75 Use tagged porcupine models
* This prevents incompatibilities with the Python wrapper
  in future.
2020-02-22 11:45:05 +01:00
Michael Hansen 627e6e8b3d Merge pull request #179 from daniele-athome/google-stt
Support for Google Cloud STT
2020-02-20 22:13:33 -05:00
Daniele Ricci f0ec0486f7 Google Cloud TTS documentation
Signed-off-by: Daniele Ricci <daniele@casaricci.it>
2020-02-18 20:04:03 +01:00
Daniele Ricci 1febc3d1d8 Support for Google Cloud STT
Signed-off-by: Daniele Ricci <daniele@casaricci.it>
2020-02-18 19:48:26 +01:00
Michael Hansen 2879802f2f Merge pull request #180 from Tooa/fix_178
Fixes Porcupine wrapper incompatibilities with models
2020-02-18 09:27:23 -05:00
Uli 21a2a8f9b4 Bump Porcupine Python wrapper 2020-02-16 18:51:01 +01:00
Michael Hansen a96f80237e Fix remote intent handler 2020-02-15 17:04:33 -05:00
Michael Hansen fc68d04f29 Fix siteId is null 2020-02-09 13:58:38 -05:00
63 changed files with 709 additions and 1137 deletions
+4 -5
View File
@@ -1,14 +1,13 @@
*
!etc/qemu-*
!download/rhasspy-tools*
!download/pocketsphinx-python.tar.gz
!download/snowboy*
!download/kaldi*
!download/
!requirements.txt
!dist/
!etc/wav
!etc/shflags
!create-venv.sh
!download-dependencies.sh
!docker/run.sh
!docker/rhasspy
+27
View File
@@ -1,3 +1,30 @@
## [2.4.20] - 2020 Apr 10
### Added
- libasound2-plugins to Docker image (for Hass.IO)
- MQTT TLS support (thanks https://github.com/ofekd)
- Mycroft Precise 0.3.0 added to Docker image
### Changed
- Properly accept websocket connections
- Don't error out on missing porcupine files
- Fix rawValue in MQTT messages
## [2.4.19] - 2020 Mar 04
### Added
- Support for Google Cloud speech to text
- Rasa NLU minimum confidence parameter
### Changed
- Using tagged version of porcupine wake models to avoid incompatibilities
- Fix Rasa NLU first entity only bug
- Fix siteId null bug
## [2.4.18] - 2020 Feb 07
### Added
+80
View File
@@ -0,0 +1,80 @@
FROM ubuntu:eoan as build
ARG TARGETPLATFORM
ARG TARGETARCH
ARG TARGETVARIANT
ENV LANG C.UTF-8
ENV RHASSPY_APP /usr/share/rhasspy
ENV RHASSPY_VENV ${RHASSPY_APP}/.venv
WORKDIR /
RUN apt-get update && \
apt-get install --no-install-recommends --yes \
python3 python3-dev python3-setuptools python3-pip python3-venv \
build-essential swig portaudio19-dev libatlas-base-dev
COPY etc/shflags ${RHASSPY_APP}/etc/
COPY download/rhasspy-tools_*.tar.gz \
download/kaldi_*.tar.gz \
download/pocketsphinx-python.tar.gz \
download/snowboy-1.3.0.tar.gz \
download/precise-engine_0.3.0_*.tar.gz \
${RHASSPY_APP}/download/
COPY create-venv.sh download-dependencies.sh requirements.txt ${RHASSPY_APP}/
RUN cd ${RHASSPY_APP} && ./create-venv.sh --nosystem --noweb
# -----------------------------------------------------------------------------
FROM ubuntu:eoan
ARG TARGETPLATFORM
ARG TARGETARCH
ARG TARGETVARIANT
ENV LANG C.UTF-8
ENV RHASSPY_APP /usr/share/rhasspy
ENV RHASSPY_VENV ${RHASSPY_APP}/.venv
WORKDIR /
COPY --from=build ${RHASSPY_VENV} ${RHASSPY_VENV}
COPY --from=build ${RHASSPY_APP}/opt/kaldi/ ${RHASSPY_APP}/opt/kaldi/
RUN apt-get update && \
apt-get install --no-install-recommends --yes \
python3 python3-dev python3-setuptools python3-pip python3-venv \
bash jq unzip curl perl \
libportaudio2 libatlas3-base \
libgfortran4 ca-certificates \
sox espeak flite libttspico-utils alsa-utils lame \
libasound2-plugins \
libfreetype6-dev libpng-dev pkg-config libffi-dev libssl-dev \
gstreamer1.0-tools gstreamer1.0-plugins-good \
mosquitto-clients
# Web interface
ADD download/rhasspy-web-dist.tar.gz ${RHASSPY_APP}/
RUN ldconfig
# Copy script to run
COPY docker/run.sh /run.sh
RUN chmod +x /run.sh
COPY profiles/ ${RHASSPY_APP}/profiles/
COPY profiles/defaults.json ${RHASSPY_APP}/profiles/
COPY docker/rhasspy ${RHASSPY_APP}/bin/
COPY dist/ ${RHASSPY_APP}/dist/
COPY etc/wav/* ${RHASSPY_APP}/etc/wav/
COPY rhasspy/profile_schema.json ${RHASSPY_APP}/rhasspy/
COPY rhasspy/train/jsgf2fst/*.py ${RHASSPY_APP}/rhasspy/train/jsgf2fst/
COPY rhasspy/train/*.py ${RHASSPY_APP}/rhasspy/train/
COPY *.py ${RHASSPY_APP}/
COPY rhasspy/*.py ${RHASSPY_APP}/rhasspy/
COPY VERSION ${RHASSPY_APP}/
ENV CONFIG_PATH /data/options.json
ENV KALDI_PREFIX ${RHASSPY_APP}/opt
ENTRYPOINT ["/run.sh"]
+9 -39
View File
@@ -1,49 +1,19 @@
.PHONY: web-dist docker manifest docs-uml g2p check
SHELL := bash
DOCKER_PLATFORMS = linux/amd64,linux/arm64,linux/arm/v7
all: docker
# -----------------------------------------------------------------------------
# Docker
# -----------------------------------------------------------------------------
docker: web-dist docker-amd64 docker-armhf docker-aarch64
docker-deploy: docker-push manifest
docker-amd64:
docker build . -f docker/templates/dockerfiles/Dockerfile.prebuilt.alsa.all \
--build-arg BUILD_ARCH=amd64 \
--build-arg CPU_ARCH=x86_64 \
--build-arg BUILD_FROM=ubuntu:bionic \
-t synesthesiam/rhasspy-server:amd64
docker-armhf:
docker build . -f docker/templates/dockerfiles/Dockerfile.prebuilt.alsa.all \
--build-arg BUILD_ARCH=armhf \
--build-arg CPU_ARCH=armv7l \
--build-arg BUILD_FROM=arm32v7/ubuntu:bionic \
-t synesthesiam/rhasspy-server:armhf
docker-aarch64:
docker build . -f docker/templates/dockerfiles/Dockerfile.prebuilt.alsa.all \
--build-arg BUILD_ARCH=aarch64 \
--build-arg CPU_ARCH=arm64v8 \
--build-arg BUILD_FROM=arm64v8/ubuntu:bionic \
-t synesthesiam/rhasspy-server:aarch64
docker-push:
docker push synesthesiam/rhasspy-server:amd64
docker push synesthesiam/rhasspy-server:armhf
docker push synesthesiam/rhasspy-server:aarch64
manifest:
docker manifest push --purge synesthesiam/rhasspy-server:latest
docker manifest create --amend synesthesiam/rhasspy-server:latest \
synesthesiam/rhasspy-server:amd64 \
synesthesiam/rhasspy-server:armhf \
synesthesiam/rhasspy-server:aarch64
docker manifest annotate synesthesiam/rhasspy-server:latest synesthesiam/rhasspy-server:armhf --os linux --arch arm
docker manifest annotate synesthesiam/rhasspy-server:latest synesthesiam/rhasspy-server:aarch64 --os linux --arch arm64
docker manifest push synesthesiam/rhasspy-server:latest
docker: web-dist
docker buildx build . \
--platform $(DOCKER_PLATFORMS) \
--tag synesthesiam/rhasspy-server:latest \
--push
# -----------------------------------------------------------------------------
# Yarn (Vue)
+9 -3
View File
@@ -1,8 +1,14 @@
![Rhasspy logo](docs/img/rhasspy.svg)
# Rhasspy has [moved and improved!](https://github.com/rhasspy/rhasspy)
Rhasspy (pronounced RAH-SPEE) is an offline voice assistant toolkit inspired by [Jasper](https://jasperproject.github.io/) [supports many languages](#supported-languages). It works well with [Home Assistant](https://www.home-assistant.io/), [Hass.io](https://www.home-assistant.io/hassio/), and [Node-RED](https://nodered.org).
This repository contains code for an older version of Rhasspy (2.4).
* [Documentation](https://rhasspy.readthedocs.io/)
---
Rhasspy (pronounced RAH-SPEE) is an offline voice assistant toolkit inspired by [Jasper](https://jasperproject.github.io/) that [supports many languages](#supported-languages). It works well with [Home Assistant](https://www.home-assistant.io/), [Hass.io](https://www.home-assistant.io/hassio/), and [Node-RED](https://nodered.org).
**A newer version of Rhasspy (2.5) is available at [https://github.com/rhasspy/rhasspy](https://github.com/rhasspy/rhasspy)**
* [Documentation](https://rhasspy.readthedocs.io/en/v2.4.20/)
* [Discussion](https://community.rhasspy.org)
* [Video Introduction](https://www.youtube.com/watch?v=ijKTR_GqWwA)
* [Hass.IO Add-On Repository](https://github.com/synesthesiam/hassio-addons)
+1 -1
View File
@@ -1 +1 @@
2.4.18
2.4.20
+8
View File
@@ -1243,6 +1243,8 @@ def api_websocket(func):
async def api_events_intent(queue) -> None:
"""Websocket endpoint to receive intents as JSON."""
# Add new queue for websocket
await websocket.accept()
while True:
message_type, text = await queue.get()
if message_type == "intent":
@@ -1253,6 +1255,8 @@ async def api_events_intent(queue) -> None:
@api_websocket
async def api_events_text(queue) -> None:
"""Websocket endpoint for transcriptions."""
await websocket.accept()
while True:
message_type, text = await queue.get()
if message_type == "transcription":
@@ -1263,6 +1267,8 @@ async def api_events_text(queue) -> None:
@api_websocket
async def api_events_wake(queue) -> None:
"""Websocket endpoint to report wake up."""
await websocket.accept()
while True:
message_type, text = await queue.get()
if message_type == "wake":
@@ -1272,6 +1278,8 @@ async def api_events_wake(queue) -> None:
@app.websocket("/api/events/log")
async def api_events_log() -> None:
"""Websocket endpoint to receive logging messages as text."""
await websocket.accept()
# Add new queue for websocket
q: asyncio.Queue = asyncio.Queue()
logging_queues.add(q)
+43 -21
View File
@@ -11,10 +11,12 @@ DEFINE_string 'venv' "${this_dir}/.venv" 'Path to create virtual environment'
DEFINE_string 'download-dir' "${this_dir}/download" 'Directory to cache downloaded files'
DEFINE_boolean 'system' true 'Install system dependencies'
DEFINE_boolean 'flair' false 'Install flair'
DEFINE_boolean 'precise' false 'Install Mycroft Precise'
DEFINE_boolean 'precise' true 'Install Mycroft Precise'
DEFINE_boolean 'adapt' true 'Install Mycroft Adapt'
DEFINE_boolean 'google' false 'Install Google Text to Speech'
DEFINE_boolean 'google' true 'Install Google Text to Speech'
DEFINE_boolean 'kaldi' true 'Install Kaldi'
DEFINE_boolean 'tools' true 'Install Rhasspy tools'
DEFINE_boolean 'web' true 'Install web UI'
DEFINE_boolean 'offline' false "Don't download anything"
DEFINE_integer 'make-threads' 4 'Number of threads to use with make' 'j'
DEFINE_string 'python' '' 'Path to Python executable'
@@ -60,6 +62,14 @@ if [[ "${FLAGS_offline}" -eq "${FLAGS_TRUE}" ]]; then
offline='true'
fi
if [[ "${FLAGS_tools}" -eq "${FLAGS_FALSE}" ]]; then
no_tools='true'
fi
if [[ "${FLAGS_web}" -eq "${FLAGS_FALSE}" ]]; then
no_web='true'
fi
make_threads="${FLAGS_make_threads}"
# -----------------------------------------------------------------------------
@@ -160,7 +170,7 @@ case "${CPU_ARCH}" in
FRIENDLY_ARCH=armhf
;;
arm64v8)
aarch64|arm64v8)
FRIENDLY_ARCH=aarch64
;;
@@ -183,6 +193,14 @@ if [[ -n "${no_kaldi}" ]]; then
download_args+=('--nokaldi')
fi
if [[ -n "${no_tools}" ]]; then
download_args+=('--notools')
fi
if [[ -n "${no_web}" ]]; then
download_args+=('--noweb')
fi
bash download-dependencies.sh "${download_args[@]}"
# -----------------------------------------------------------------------------
@@ -202,10 +220,12 @@ echo "Creating new virtual environment"
mkdir -p "${venv}"
"${PYTHON}" -m venv "${venv}"
# Extract Rhasspy tools
rhasspy_tools_file="${download_dir}/rhasspy-tools_${FRIENDLY_ARCH}.tar.gz"
echo "Extracting tools (${rhasspy_tools_file})"
tar -C "${venv}" -xf "${rhasspy_tools_file}"
if [[ -z "${no_tools}" ]]; then
# Extract Rhasspy tools
rhasspy_tools_file="${download_dir}/rhasspy-tools_${FRIENDLY_ARCH}.tar.gz"
echo "Extracting tools (${rhasspy_tools_file})"
tar -C "${venv}" -xf "${rhasspy_tools_file}"
fi
# Force .venv/lib to be used
export LD_LIBRARY_PATH="${venv}/lib:${LD_LIBRARY_PATH}"
@@ -214,11 +234,11 @@ export LD_LIBRARY_PATH="${venv}/lib:${LD_LIBRARY_PATH}"
source "${venv}/bin/activate"
echo "Upgrading pip"
"${PYTHON}" -m pip install --upgrade pip
python3 -m pip install --upgrade pip
echo "Installing Python requirements"
"${PYTHON}" -m pip install wheel setuptools
"${PYTHON}" -m pip install requests
python3 -m pip install wheel setuptools
python3 -m pip install requests
# pytorch is not available on ARM
case "${CPU_ARCH}" in
@@ -255,18 +275,18 @@ sed -i '/^openfst/d' "${requirements_file}"
python3 -m pip install -r "${requirements_file}"
# Install Python openfst wrapper
"${PYTHON}" -m pip install \
--global-option=build_ext \
--global-option="-I${venv}/include" \
--global-option="-L${venv}/lib" \
-r <(grep '^openfst' "${this_dir}/requirements.txt")
python3 -m pip install \
--global-option=build_ext \
--global-option="-I${venv}/include" \
--global-option="-L${venv}/lib" \
-r <(grep '^openfst' "${this_dir}/requirements.txt")
# -----------------------------------------------------------------------------
# Pocketsphinx for Python
# -----------------------------------------------------------------------------
pocketsphinx_file="${download_dir}/pocketsphinx-python.tar.gz"
"${PYTHON}" -m pip install "${pocketsphinx_file}"
python3 -m pip install "${pocketsphinx_file}"
# -----------------------------------------------------------------------------
# Snowboy
@@ -275,7 +295,7 @@ pocketsphinx_file="${download_dir}/pocketsphinx-python.tar.gz"
case "${CPU_ARCH}" in
x86_64|armv7l)
snowboy_file="${download_dir}/snowboy-1.3.0.tar.gz"
"${PYTHON}" -m pip install "${snowboy_file}"
python3 -m pip install "${snowboy_file}"
;;
*)
@@ -288,7 +308,7 @@ esac
if [[ -z "${no_precise}" && -z "$(command -v precise-engine)" ]]; then
case "${CPU_ARCH}" in
x86_64|armv7l)
x86_64|armv7l|aarch64)
echo "Installing Mycroft Precise"
precise_file="${download_dir}/precise-engine_0.3.0_${CPU_ARCH}.tar.gz"
precise_install="${venv}/lib"
@@ -316,9 +336,11 @@ fi
# Web Interface
# -----------------------------------------------------------------------------
rhasspy_web_file="${download_dir}/rhasspy-web-dist.tar.gz"
echo "Extracting web interface (${rhasspy_web_file})"
tar -C "${this_dir}" -xf "${rhasspy_web_file}"
if [[ -z "${no_web}" ]]; then
rhasspy_web_file="${download_dir}/rhasspy-web-dist.tar.gz"
echo "Extracting web interface (${rhasspy_web_file})"
tar -C "${this_dir}" -xf "${rhasspy_web_file}"
fi
# -----------------------------------------------------------------------------
+26 -5
View File
@@ -1,5 +1,4 @@
#!/usr/bin/env bash
DIR="$( cd "$( dirname "$0" )" && pwd )"
# Try to detemine where Rhasspy is located
if [[ -z "${RHASSPY_APP}" ]]; then
@@ -16,13 +15,35 @@ if [[ -f "${CONFIG_PATH}" ]]; then
# Hass.IO configuration
profile_name="$(jq --raw-output '.profile_name' "${CONFIG_PATH}")"
profile_dir="$(jq --raw-output '.profile_dir' "${CONFIG_PATH}")"
RHASSPY_ARGS="--profile \"${profile_name}\" --user-profiles \"${profile_dir}\""
RHASSPY_ARGS=('--profile' "${profile_name}" '--user-profiles' "${profile_dir}")
# Copy user-defined asoundrc to root
asoundrc="$(jq --raw-output '.asoundrc' "${CONFIG_PATH}")"
if [[ ! -z "${asoundrc}" ]]; then
echo "${asoundrc}" > /root/.asoundrc
fi
# Add SSL settings
ssl="$(jq --raw-output '.ssl' "${CONFIG_PATH}")"
if [[ "${ssl}" == 'true' ]]; then
certfile="$(jq --raw-output '.certfile' "${CONFIG_PATH}")"
keyfile="$(jq --raw-output '.keyfile' "${CONFIG_PATH}")"
RHASSPY_ARGS+=('--ssl' "/ssl/${certfile}" "/ssl/${keyfile}")
fi
fi
cd "${RHASSPY_APP}"
RHASSPY_VENV="${RHASSPY_APP}/.venv"
if [[ -d "${RHASSPY_VENV}" ]]; then
source "${RHASSPY_VENV}/bin/activate"
if [[ -z "${RHASSPY_ARGS}" ]]; then
# Force .venv/lib to be used
export LD_LIBRARY_PATH="${RHASSPY_VENV}/lib:${LD_LIBRARY_PATH}"
fi
cd "${RHASSPY_APP}" || exit 1
if [[ -z "${RHASSPY_ARGS[*]}" ]]; then
python3 app.py "$@"
else
python3 app.py "${RHASSPY_ARGS}" "$@"
python3 app.py "${RHASSPY_ARGS[@]}" "$@"
fi
-52
View File
@@ -1,52 +0,0 @@
ARG BUILD_FROM
FROM $BUILD_FROM
LABEL maintainer="Michael Hansen <hansen.mike@gmail.com>"
ARG BUILD_ARCH
ARG CPU_ARCH
ENV LANG C.UTF-8
ARG MAKE_THREADS=4
WORKDIR /
QEMU
SYSTEM_DEPENDENCIES
RHASSPY_TOOLS
PYTHON_REQUIREMENTS
PYTHON_POCKETSPHINX
SNOWBOY
TTS
KALDI
RUN ldconfig
# Copy bw and mllr_solve to /usr/bin
RUN find / -name bw -exec cp '{}' /usr/bin/ \;
RUN find / -name mllr_solve -exec cp '{}' /usr/bin/ \;
GSTREAMER
PULSEAUDIO
# Copy script to run
COPY docker/run.sh /run.sh
RUN chmod +x /run.sh
RHASSPY_USER
PROFILES
RHASSPY_CODE
ENV CONFIG_PATH /data/options.json
ENV KALDI_PREFIX /opt
ENTRYPOINT ["/run.sh"]
@@ -1 +0,0 @@
COPY profiles/ ${RHASSPY_APP}/profiles/
-1
View File
@@ -1 +0,0 @@
ENV RHASSPY_APP /usr/share/rhasspy
@@ -1,207 +0,0 @@
ARG BUILD_FROM
FROM $BUILD_FROM
LABEL maintainer="Michael Hansen <hansen.mike@gmail.com>"
ARG BUILD_ARCH
ARG CPU_ARCH
ENV LANG C.UTF-8
ARG MAKE_THREADS=4
WORKDIR /
COPY etc/qemu-arm-static /usr/bin/
COPY etc/qemu-aarch64-static /usr/bin/
RUN apt-get update && \
apt-get install --no-install-recommends --yes \
bash jq unzip \
python3 python3-pip python3-dev \
build-essential portaudio19-dev swig \
libatlas-base-dev \
sox espeak flite alsa-utils \
git curl \
autoconf libtool automake bison \
sphinxbase-utils sphinxtrain
COPY download/openfst-1.6.2-1_${BUILD_ARCH}.deb /
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then \
apt-get install --no-install-recommends --yes libfst-dev libfst-tools; \
else \
dpkg -i /openfst-1.6.2-1_${BUILD_ARCH}.deb; \
rm /openfst*.deb; \
fi
RHASSPY_TOOLS
# Install Python dependencies
RUN python3 -m pip install --no-cache-dir setuptools wheel
RUN apt-get install -y libfreetype6-dev libpng-dev pkg-config libffi-dev libssl-dev
COPY requirements.txt /requirements.txt
RUN if [ "$BUILD_ARCH" != "amd64" ]; then \
grep -v flair /requirements.txt > /requirements-noflair.txt; \
mv /requirements-noflair.txt /requirements.txt; \
fi
RUN python3 -m pip install --no-cache-dir -r /requirements.txt
# Install Pocketsphinx Python module with no sound
COPY download/pocketsphinx-python.tar.gz /
RUN python3 -m pip install --no-cache-dir /pocketsphinx-python.tar.gz && \
rm -rf /pocketsphinx-python*
# Install snowboy
COPY download/snowboy-1.3.0.tar.gz /
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then pip3 install --no-cache-dir /snowboy-1.3.0.tar.gz; fi
RUN apt-get install --no-install-recommends --yes flite libttspico-utils
COPY download/kaldi_${BUILD_ARCH}.tar.gz /kaldi.tar.gz
RUN mkdir -p /opt && \
tar -C /opt -xzf /kaldi.tar.gz && \
rm /kaldi.tar.gz
RUN ldconfig
# Copy bw and mllr_solve to /usr/bin
RUN find / -name bw -exec cp '{}' /usr/bin/ \;
RUN find / -name mllr_solve -exec cp '{}' /usr/bin/ \;
# Install gstreamer and plugins
RUN apt-get install --no-install-recommends --yes gstreamer1.0-tools gstreamer1.0-plugins-good
ENV RHASSPY_APP /usr/share/rhasspy
# Copy script to run
COPY docker/run.sh /run.sh
RUN chmod +x /run.sh
COPY profiles/zh/profile.json \
profiles/zh/custom_words.txt \
profiles/zh/espeak_phonemes.txt \
profiles/zh/phoneme_examples.txt \
profiles/zh/frequent_words.txt \
profiles/zh/sentences.ini \
profiles/zh/stop_words.txt ${RHASSPY_APP}/profiles/zh/
COPY profiles/hi/ \
profiles/hi/profile.json \
profiles/hi/custom_words.txt \
profiles/hi/espeak_phonemes.txt \
profiles/hi/phoneme_examples.txt \
profiles/hi/frequent_words.txt \
profiles/hi/sentences.ini \
profiles/hi/stop_words.txt ${RHASSPY_APP}/profiles/hi/
COPY profiles/el/profile.json \
profiles/el/custom_words.txt \
profiles/el/espeak_phonemes.txt \
profiles/el/phoneme_examples.txt \
profiles/el/frequent_words.txt \
profiles/el/sentences.ini \
profiles/el/stop_words.txt ${RHASSPY_APP}/profiles/el/
COPY profiles/de/profile.json \
profiles/de/custom_words.txt \
profiles/de/espeak_phonemes.txt \
profiles/de/phoneme_examples.txt \
profiles/de/frequent_words.txt \
profiles/de/sentences.ini \
profiles/de/stop_words.txt ${RHASSPY_APP}/profiles/de/
COPY profiles/it/profile.json \
profiles/it/custom_words.txt \
profiles/it/espeak_phonemes.txt \
profiles/it/phoneme_examples.txt \
profiles/it/frequent_words.txt \
profiles/it/sentences.ini \
profiles/it/stop_words.txt ${RHASSPY_APP}/profiles/it/
COPY profiles/es/profile.json \
profiles/es/custom_words.txt \
profiles/es/espeak_phonemes.txt \
profiles/es/phoneme_examples.txt \
profiles/es/frequent_words.txt \
profiles/es/sentences.ini \
profiles/es/stop_words.txt ${RHASSPY_APP}/profiles/es/
COPY profiles/fr/profile.json \
profiles/fr/custom_words.txt \
profiles/fr/espeak_phonemes.txt \
profiles/fr/phoneme_examples.txt \
profiles/fr/frequent_words.txt \
profiles/fr/sentences.ini \
profiles/fr/stop_words.txt ${RHASSPY_APP}/profiles/fr/
COPY profiles/ru/profile.json \
profiles/ru/custom_words.txt \
profiles/ru/espeak_phonemes.txt \
profiles/ru/phoneme_examples.txt \
profiles/ru/frequent_words.txt \
profiles/ru/sentences.ini \
profiles/ru/stop_words.txt ${RHASSPY_APP}/profiles/ru/
COPY profiles/nl/profile.json \
profiles/nl/custom_words.txt \
profiles/nl/espeak_phonemes.txt \
profiles/nl/phoneme_examples.txt \
profiles/nl/frequent_words.txt \
profiles/nl/sentences.ini \
profiles/nl/stop_words.txt ${RHASSPY_APP}/profiles/nl/
COPY profiles/vi/profile.json \
profiles/vi/custom_words.txt \
profiles/vi/espeak_phonemes.txt \
profiles/vi/phoneme_examples.txt \
profiles/vi/frequent_words.txt \
profiles/vi/sentences.ini \
profiles/vi/stop_words.txt ${RHASSPY_APP}/profiles/vi/
COPY profiles/pt/profile.json \
profiles/pt/custom_words.txt \
profiles/pt/espeak_phonemes.txt \
profiles/pt/phoneme_examples.txt \
profiles/pt/frequent_words.txt \
profiles/pt/sentences.ini \
profiles/pt/stop_words.txt ${RHASSPY_APP}/profiles/pt/
COPY profiles/sv/profile.json \
profiles/sv/custom_words.txt \
profiles/sv/espeak_phonemes.txt \
profiles/sv/phoneme_examples.txt \
profiles/sv/frequent_words.txt \
profiles/sv/sentences.ini \
profiles/sv/stop_words.txt ${RHASSPY_APP}/profiles/sv/
COPY profiles/ca/profile.json \
profiles/ca/custom_words.txt \
profiles/ca/espeak_phonemes.txt \
profiles/ca/phoneme_examples.txt \
profiles/ca/frequent_words.txt \
profiles/ca/sentences.ini \
profiles/ca/stop_words.txt ${RHASSPY_APP}/profiles/ca/
COPY profiles/en/profile.json \
profiles/en/custom_words.txt \
profiles/en/espeak_phonemes.txt \
profiles/en/phoneme_examples.txt \
profiles/en/frequent_words.txt \
profiles/en/sentences.ini \
profiles/en/stop_words.txt ${RHASSPY_APP}/profiles/en/
COPY profiles/defaults.json ${RHASSPY_APP}/profiles/
COPY docker/rhasspy ${RHASSPY_APP}/bin/
COPY dist/ ${RHASSPY_APP}/dist/
COPY etc/wav/* ${RHASSPY_APP}/etc/wav/
COPY rhasspy/profile_schema.json ${RHASSPY_APP}/rhasspy/
COPY rhasspy/train/jsgf2fst/*.py ${RHASSPY_APP}/rhasspy/train/jsgf2fst/
COPY rhasspy/train/*.py ${RHASSPY_APP}/rhasspy/train/
COPY *.py ${RHASSPY_APP}/
COPY rhasspy/*.py ${RHASSPY_APP}/rhasspy/
ENV CONFIG_PATH /data/options.json
ENV KALDI_PREFIX /opt
ENTRYPOINT ["/run.sh"]
@@ -1,96 +0,0 @@
ARG BUILD_FROM
FROM $BUILD_FROM
LABEL maintainer="Michael Hansen <hansen.mike@gmail.com>"
ARG BUILD_ARCH
ARG CPU_ARCH
ENV LANG C.UTF-8
ARG MAKE_THREADS=4
WORKDIR /
COPY etc/qemu-arm-static /usr/bin/
COPY etc/qemu-aarch64-static /usr/bin/
RUN apt-get update && \
apt-get install --no-install-recommends --yes \
bash jq unzip \
python3 python3-pip python3-dev \
build-essential portaudio19-dev swig \
libatlas-base-dev \
sox espeak flite alsa-utils \
git curl \
autoconf libtool automake bison \
sphinxbase-utils sphinxtrain
COPY download/openfst-1.6.2-1_${BUILD_ARCH}.deb /
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then \
apt-get install --no-install-recommends --yes libfst-dev libfst-tools; \
else \
dpkg -i /openfst-1.6.2-1_${BUILD_ARCH}.deb; \
rm /openfst*.deb; \
fi
RHASSPY_TOOLS
# Install Python dependencies
RUN python3 -m pip install --no-cache-dir setuptools wheel
RUN apt-get install -y libfreetype6-dev libpng-dev pkg-config libffi-dev libssl-dev
COPY requirements.txt /requirements.txt
RUN if [ "$BUILD_ARCH" != "amd64" ]; then \
grep -v flair /requirements.txt > /requirements-noflair.txt; \
mv /requirements-noflair.txt /requirements.txt; \
fi
RUN python3 -m pip install --no-cache-dir -r /requirements.txt
# Install Pocketsphinx Python module with no sound
COPY download/pocketsphinx-python.tar.gz /
RUN python3 -m pip install --no-cache-dir /pocketsphinx-python.tar.gz && \
rm -rf /pocketsphinx-python*
# Install snowboy
COPY download/snowboy-1.3.0.tar.gz /
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then pip3 install --no-cache-dir /snowboy-1.3.0.tar.gz; fi
RUN apt-get install --no-install-recommends --yes flite libttspico-utils
COPY download/kaldi_${BUILD_ARCH}.tar.gz /kaldi.tar.gz
RUN mkdir -p /opt && \
tar -C /opt -xzf /kaldi.tar.gz && \
rm /kaldi.tar.gz
RUN ldconfig
# Copy bw and mllr_solve to /usr/bin
RUN find / -name bw -exec cp '{}' /usr/bin/ \;
RUN find / -name mllr_solve -exec cp '{}' /usr/bin/ \;
# Install gstreamer and plugins
RUN apt-get install --no-install-recommends --yes gstreamer1.0-tools gstreamer1.0-plugins-good
ENV RHASSPY_APP /usr/share/rhasspy
# Copy script to run
COPY docker/run.sh /run.sh
RUN chmod +x /run.sh
COPY profiles/en/ ${RHASSPY_APP}/profiles/en/
COPY profiles/defaults.json ${RHASSPY_APP}/profiles/
COPY docker/rhasspy ${RHASSPY_APP}/bin/
COPY dist/ ${RHASSPY_APP}/dist/
COPY etc/wav/* ${RHASSPY_APP}/etc/wav/
COPY rhasspy/profile_schema.json ${RHASSPY_APP}/rhasspy/
COPY rhasspy/train/jsgf2fst/*.py ${RHASSPY_APP}/rhasspy/train/jsgf2fst/
COPY rhasspy/train/*.py ${RHASSPY_APP}/rhasspy/train/
COPY *.py ${RHASSPY_APP}/
COPY rhasspy/*.py ${RHASSPY_APP}/rhasspy/
ENV CONFIG_PATH /data/options.json
ENV KALDI_PREFIX /opt
ENTRYPOINT ["/run.sh"]
@@ -1,113 +0,0 @@
ARG BUILD_FROM
FROM $BUILD_FROM
LABEL maintainer="Michael Hansen <hansen.mike@gmail.com>"
ARG BUILD_ARCH
ARG CPU_ARCH
ENV LANG C.UTF-8
ARG MAKE_THREADS=4
WORKDIR /
COPY etc/qemu-arm-static /usr/bin/
COPY etc/qemu-aarch64-static /usr/bin/
RUN apt-get update && \
apt-get install --no-install-recommends --yes \
bash jq unzip \
python3 python3-pip python3-dev \
build-essential portaudio19-dev swig \
libatlas-base-dev \
sox espeak flite alsa-utils \
git curl \
autoconf libtool automake bison \
sphinxbase-utils sphinxtrain
COPY download/openfst-1.6.2-1_${BUILD_ARCH}.deb /
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then \
apt-get install --no-install-recommends --yes libfst-dev libfst-tools; \
else \
dpkg -i /openfst-1.6.2-1_${BUILD_ARCH}.deb; \
rm /openfst*.deb; \
fi
RHASSPY_TOOLS
# Install Python dependencies
RUN python3 -m pip install --no-cache-dir setuptools wheel
RUN apt-get install -y libfreetype6-dev libpng-dev pkg-config libffi-dev libssl-dev
COPY requirements.txt /requirements.txt
RUN if [ "$BUILD_ARCH" != "amd64" ]; then \
grep -v flair /requirements.txt > /requirements-noflair.txt; \
mv /requirements-noflair.txt /requirements.txt; \
fi
RUN python3 -m pip install --no-cache-dir -r /requirements.txt
# Install Pocketsphinx Python module with no sound
COPY download/pocketsphinx-python.tar.gz /
RUN python3 -m pip install --no-cache-dir /pocketsphinx-python.tar.gz && \
rm -rf /pocketsphinx-python*
# Install snowboy
COPY download/snowboy-1.3.0.tar.gz /
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then pip3 install --no-cache-dir /snowboy-1.3.0.tar.gz; fi
RUN apt-get install --no-install-recommends --yes flite libttspico-utils
COPY download/kaldi_${BUILD_ARCH}.tar.gz /kaldi.tar.gz
RUN mkdir -p /opt && \
tar -C /opt -xzf /kaldi.tar.gz && \
rm /kaldi.tar.gz
RUN ldconfig
# Copy bw and mllr_solve to /usr/bin
RUN find / -name bw -exec cp '{}' /usr/bin/ \;
RUN find / -name mllr_solve -exec cp '{}' /usr/bin/ \;
# Install gstreamer and plugins
RUN apt-get install --no-install-recommends --yes gstreamer1.0-tools gstreamer1.0-plugins-good
RUN apt-get install -y pulseaudio
COPY etc/pulseaudio.client.conf /etc/pulse/client.conf
# Create new user
ENV UNAME=rhasspy
RUN export UNAME=$UNAME UID=1000 GID=1000 && \
mkdir -p "/home/${UNAME}" && \
echo "${UNAME}:x:${UID}:${GID}:${UNAME} User,,,:/home/${UNAME}:/bin/bash" >> /etc/passwd && \
echo "${UNAME}:x:${UID}:" >> /etc/group && \
mkdir -p /etc/sudoers.d && \
echo "${UNAME} ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/${UNAME} && \
chmod 0440 /etc/sudoers.d/${UNAME} && \
chown ${UID}:${GID} -R /home/${UNAME} && \
gpasswd -a ${UNAME} audio
ENV RHASSPY_APP /home/${UNAME}
# Copy script to run
COPY docker/run.sh /run.sh
RUN chmod +x /run.sh
# Switch to new user
USER $UNAME
ENV HOME /home/${UNAME}
COPY profiles/en/ ${RHASSPY_APP}/profiles/en/
COPY profiles/defaults.json ${RHASSPY_APP}/profiles/
COPY docker/rhasspy ${RHASSPY_APP}/bin/
COPY dist/ ${RHASSPY_APP}/dist/
COPY etc/wav/* ${RHASSPY_APP}/etc/wav/
COPY rhasspy/profile_schema.json ${RHASSPY_APP}/rhasspy/
COPY rhasspy/train/jsgf2fst/*.py ${RHASSPY_APP}/rhasspy/train/jsgf2fst/
COPY rhasspy/train/*.py ${RHASSPY_APP}/rhasspy/train/
COPY *.py ${RHASSPY_APP}/
COPY rhasspy/*.py ${RHASSPY_APP}/rhasspy/
ENV CONFIG_PATH /data/options.json
ENV KALDI_PREFIX /opt
ENTRYPOINT ["/run.sh"]
@@ -1,91 +0,0 @@
ARG BUILD_FROM
FROM $BUILD_FROM
LABEL maintainer="Michael Hansen <hansen.mike@gmail.com>"
ARG BUILD_ARCH
ARG CPU_ARCH
ENV LANG C.UTF-8
ARG MAKE_THREADS=4
WORKDIR /
COPY etc/qemu-arm-static /usr/bin/
COPY etc/qemu-aarch64-static /usr/bin/
RUN apt-get update && \
apt-get install --no-install-recommends --yes \
bash jq unzip \
python3 python3-pip python3-dev \
build-essential portaudio19-dev swig \
libatlas-base-dev \
sox espeak flite alsa-utils \
git curl \
autoconf libtool automake bison \
sphinxbase-utils sphinxtrain
COPY download/rhasspy-tools_${BUILD_ARCH}.tar.gz /
RUN tar -C /usr -xvf /rhasspy-tools_${BUILD_ARCH}.tar.gz && \
rm -f /rhasspy-tools_${BUILD_ARCH}.tar.gz
# Install Python dependencies
RUN python3 -m pip install --no-cache-dir setuptools wheel
RUN apt-get install -y libfreetype6-dev libpng-dev pkg-config libffi-dev libssl-dev
COPY requirements.txt /requirements.txt
RUN if [ "$BUILD_ARCH" != "amd64" ]; then \
grep -v flair /requirements.txt > /requirements-noflair.txt; \
mv /requirements-noflair.txt /requirements.txt; \
fi
RUN python3 -m pip install --no-cache-dir -r /requirements.txt
# Install Pocketsphinx Python module with no sound
COPY download/pocketsphinx-python.tar.gz /
RUN python3 -m pip install --no-cache-dir /pocketsphinx-python.tar.gz && \
rm -rf /pocketsphinx-python*
# Install snowboy
COPY download/snowboy-1.3.0.tar.gz /
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then pip3 install --no-cache-dir /snowboy-1.3.0.tar.gz; fi
RUN apt-get install --no-install-recommends --yes flite libttspico-utils lame
COPY download/kaldi_${BUILD_ARCH}.tar.gz /kaldi.tar.gz
RUN mkdir -p /opt && \
tar -C /opt -xzf /kaldi.tar.gz && \
rm /kaldi.tar.gz
RUN ldconfig
# Copy bw and mllr_solve to /usr/bin
RUN find / -name bw -exec cp '{}' /usr/bin/ \;
RUN find / -name mllr_solve -exec cp '{}' /usr/bin/ \;
# Install gstreamer and plugins
RUN apt-get install --no-install-recommends --yes gstreamer1.0-tools gstreamer1.0-plugins-good
ENV RHASSPY_APP /usr/share/rhasspy
# Copy script to run
COPY docker/run.sh /run.sh
RUN chmod +x /run.sh
COPY profiles/ ${RHASSPY_APP}/profiles/
COPY profiles/defaults.json ${RHASSPY_APP}/profiles/
COPY docker/rhasspy ${RHASSPY_APP}/bin/
COPY dist/ ${RHASSPY_APP}/dist/
COPY etc/wav/* ${RHASSPY_APP}/etc/wav/
COPY rhasspy/profile_schema.json ${RHASSPY_APP}/rhasspy/
COPY rhasspy/train/jsgf2fst/*.py ${RHASSPY_APP}/rhasspy/train/jsgf2fst/
COPY rhasspy/train/*.py ${RHASSPY_APP}/rhasspy/train/
COPY *.py ${RHASSPY_APP}/
COPY rhasspy/*.py ${RHASSPY_APP}/rhasspy/
COPY VERSION ${RHASSPY_APP}/
ENV CONFIG_PATH /data/options.json
ENV KALDI_PREFIX /opt
ENTRYPOINT ["/run.sh"]
@@ -1,91 +0,0 @@
ARG BUILD_FROM
FROM $BUILD_FROM
LABEL maintainer="Michael Hansen <hansen.mike@gmail.com>"
ARG BUILD_ARCH
ARG CPU_ARCH
ENV LANG C.UTF-8
ARG MAKE_THREADS=4
WORKDIR /
COPY etc/qemu-arm-static /usr/bin/
COPY etc/qemu-aarch64-static /usr/bin/
RUN apt-get update && \
apt-get install --no-install-recommends --yes \
bash jq unzip \
python3 python3-pip python3-dev \
build-essential portaudio19-dev swig \
libfst-dev libfst-tools \
libatlas-base-dev \
sox espeak flite alsa-utils \
git curl \
autoconf libtool automake bison \
sphinxbase-utils sphinxtrain
COPY download/rhasspy-tools_${BUILD_ARCH}.tar.gz /
RUN tar -C /usr -xvf /rhasspy-tools_${BUILD_ARCH}.tar.gz && \
rm -f /rhasspy-tools_${BUILD_ARCH}.tar.gz
# Install Python dependencies
RUN python3 -m pip install --no-cache-dir setuptools wheel
RUN apt-get install -y libfreetype6-dev libpng-dev pkg-config libffi-dev libssl-dev
COPY requirements.txt /requirements.txt
RUN if [ "$BUILD_ARCH" != "amd64" ]; then \
grep -v flair /requirements.txt > /requirements-noflair.txt; \
mv /requirements-noflair.txt /requirements.txt; \
fi
RUN python3 -m pip install --no-cache-dir -r /requirements.txt
# Install Pocketsphinx Python module with no sound
COPY download/pocketsphinx-python.tar.gz /
RUN python3 -m pip install --no-cache-dir /pocketsphinx-python.tar.gz && \
rm -rf /pocketsphinx-python*
# Install snowboy
COPY download/snowboy-1.3.0.tar.gz /
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then pip3 install --no-cache-dir /snowboy-1.3.0.tar.gz; fi
RUN apt-get install --no-install-recommends --yes flite libttspico-utils
COPY download/kaldi_${BUILD_ARCH}.tar.gz /kaldi.tar.gz
RUN mkdir -p /opt && \
tar -C /opt -xzf /kaldi.tar.gz && \
rm /kaldi.tar.gz
RUN ldconfig
# Copy bw and mllr_solve to /usr/bin
RUN find / -name bw -exec cp '{}' /usr/bin/ \;
RUN find / -name mllr_solve -exec cp '{}' /usr/bin/ \;
# Install gstreamer and plugins
RUN apt-get install --no-install-recommends --yes gstreamer1.0-tools gstreamer1.0-plugins-good
ENV RHASSPY_APP /usr/share/rhasspy
# Copy script to run
COPY docker/run.sh /run.sh
RUN chmod +x /run.sh
COPY profiles/en/ ${RHASSPY_APP}/profiles/en/
COPY profiles/defaults.json ${RHASSPY_APP}/profiles/
COPY docker/rhasspy ${RHASSPY_APP}/bin/
COPY dist/ ${RHASSPY_APP}/dist/
COPY etc/wav/* ${RHASSPY_APP}/etc/wav/
COPY rhasspy/profile_schema.json ${RHASSPY_APP}/rhasspy/
COPY rhasspy/train/jsgf2fst/*.py ${RHASSPY_APP}/rhasspy/train/jsgf2fst/
COPY rhasspy/train/*.py ${RHASSPY_APP}/rhasspy/train/
COPY *.py ${RHASSPY_APP}/
COPY rhasspy/*.py ${RHASSPY_APP}/rhasspy/
ENV CONFIG_PATH /data/options.json
ENV KALDI_PREFIX /opt
ENTRYPOINT ["/run.sh"]
@@ -1,108 +0,0 @@
ARG BUILD_FROM
FROM $BUILD_FROM
LABEL maintainer="Michael Hansen <hansen.mike@gmail.com>"
ARG BUILD_ARCH
ARG CPU_ARCH
ENV LANG C.UTF-8
ARG MAKE_THREADS=4
WORKDIR /
COPY etc/qemu-arm-static /usr/bin/
COPY etc/qemu-aarch64-static /usr/bin/
RUN apt-get update && \
apt-get install --no-install-recommends --yes \
bash jq unzip \
python3 python3-pip python3-dev \
build-essential portaudio19-dev swig \
libfst-dev libfst-tools \
libatlas-base-dev \
sox espeak flite alsa-utils \
git curl \
autoconf libtool automake bison \
sphinxbase-utils sphinxtrain
COPY download/rhasspy-tools_${BUILD_ARCH}.tar.gz /
RUN tar -C /usr -xvf /rhasspy-tools_${BUILD_ARCH}.tar.gz && \
rm -f /rhasspy-tools_${BUILD_ARCH}.tar.gz
# Install Python dependencies
RUN python3 -m pip install --no-cache-dir setuptools wheel
RUN apt-get install -y libfreetype6-dev libpng-dev pkg-config libffi-dev libssl-dev
COPY requirements.txt /requirements.txt
RUN if [ "$BUILD_ARCH" != "amd64" ]; then \
grep -v flair /requirements.txt > /requirements-noflair.txt; \
mv /requirements-noflair.txt /requirements.txt; \
fi
RUN python3 -m pip install --no-cache-dir -r /requirements.txt
# Install Pocketsphinx Python module with no sound
COPY download/pocketsphinx-python.tar.gz /
RUN python3 -m pip install --no-cache-dir /pocketsphinx-python.tar.gz && \
rm -rf /pocketsphinx-python*
# Install snowboy
COPY download/snowboy-1.3.0.tar.gz /
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then pip3 install --no-cache-dir /snowboy-1.3.0.tar.gz; fi
RUN apt-get install --no-install-recommends --yes flite libttspico-utils
COPY download/kaldi_${BUILD_ARCH}.tar.gz /kaldi.tar.gz
RUN mkdir -p /opt && \
tar -C /opt -xzf /kaldi.tar.gz && \
rm /kaldi.tar.gz
RUN ldconfig
# Copy bw and mllr_solve to /usr/bin
RUN find / -name bw -exec cp '{}' /usr/bin/ \;
RUN find / -name mllr_solve -exec cp '{}' /usr/bin/ \;
# Install gstreamer and plugins
RUN apt-get install --no-install-recommends --yes gstreamer1.0-tools gstreamer1.0-plugins-good
RUN apt-get install -y pulseaudio
COPY etc/pulseaudio.client.conf /etc/pulse/client.conf
# Create new user
ENV UNAME=rhasspy
RUN export UNAME=$UNAME UID=1000 GID=1000 && \
mkdir -p "/home/${UNAME}" && \
echo "${UNAME}:x:${UID}:${GID}:${UNAME} User,,,:/home/${UNAME}:/bin/bash" >> /etc/passwd && \
echo "${UNAME}:x:${UID}:" >> /etc/group && \
mkdir -p /etc/sudoers.d && \
echo "${UNAME} ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/${UNAME} && \
chmod 0440 /etc/sudoers.d/${UNAME} && \
chown ${UID}:${GID} -R /home/${UNAME} && \
gpasswd -a ${UNAME} audio
ENV RHASSPY_APP /home/${UNAME}
# Copy script to run
COPY docker/run.sh /run.sh
RUN chmod +x /run.sh
# Switch to new user
USER $UNAME
ENV HOME /home/${UNAME}
COPY profiles/en/ ${RHASSPY_APP}/profiles/en/
COPY profiles/defaults.json ${RHASSPY_APP}/profiles/
COPY docker/rhasspy ${RHASSPY_APP}/bin/
COPY dist/ ${RHASSPY_APP}/dist/
COPY etc/wav/* ${RHASSPY_APP}/etc/wav/
COPY rhasspy/profile_schema.json ${RHASSPY_APP}/rhasspy/
COPY rhasspy/train/jsgf2fst/*.py ${RHASSPY_APP}/rhasspy/train/jsgf2fst/
COPY rhasspy/train/*.py ${RHASSPY_APP}/rhasspy/train/
COPY *.py ${RHASSPY_APP}/
COPY rhasspy/*.py ${RHASSPY_APP}/rhasspy/
ENV CONFIG_PATH /data/options.json
ENV KALDI_PREFIX /opt
ENTRYPOINT ["/run.sh"]
-1
View File
@@ -1 +0,0 @@
COPY profiles/en/ ${RHASSPY_APP}/profiles/en/
@@ -1,7 +0,0 @@
COPY download/phonetisaurus-2019.tar.gz /phonetisaurus.tar.gz
RUN cd / && tar -xf phonetisaurus.tar.gz
RUN cd /phonetisaurus && \
./configure && \
make -j $MAKE_THREADS && \
make install && \
rm -rf /phonetisaurus*
@@ -1,18 +0,0 @@
RUN apt-get update && \
apt-get install --no-install-recommends --yes \
bash jq unzip \
python3 python3-pip python3-dev \
build-essential portaudio19-dev swig \
libatlas-base-dev \
sox espeak flite alsa-utils \
git curl \
autoconf libtool automake bison \
sphinxbase-utils sphinxtrain
COPY download/openfst-1.6.2-1_${BUILD_ARCH}.deb /
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then \
apt-get install --no-install-recommends --yes libfst-dev libfst-tools; \
else \
dpkg -i /openfst-1.6.2-1_${BUILD_ARCH}.deb; \
rm /openfst*.deb; \
fi
-67
View File
@@ -1,67 +0,0 @@
#!/usr/bin/env bash
# Directory of *this* script
DIR="$( cd "$( dirname "$0" )" && pwd )"
template="$DIR/Dockerfile.template"
out="$DIR/dockerfiles"
mkdir -p "$out"
# -----------------------------------------------------------------------------
# Uppercases an input string
function upper {
tr '[[:lower:]]' '[[:upper:]]'
}
# Creates m4 "define" statements from text files in one or more directories.
# The contents of dir/file.txt will be the value of variable FILE.
function set_variables {
echo "divert(-1)"
while [[ ! -z "$1" ]]; do
if [[ -d "$1" ]]; then
for var_file in $(find "$1" -type f -name "*.txt"); do
var_name=$(basename "$var_file" .txt | upper)
echo "define(\`$var_name', \`$(cat $var_file)')"
done
elif [[ -f "$1" ]]; then
var_file="$1"
var_name=$(basename "$var_file" .txt | upper)
echo "define(\`$var_name', \`$(cat $var_file)')"
fi
shift
done
echo "divert(0)dnl"
}
# -----------------------------------------------------------------------------
#------------
# From source
#------------
# set_variables "$DIR/shared/" "$DIR/from-source/" \
# "$DIR/alsa/" "$DIR/en_profile/" \
# | cat - "$template" | m4 > "$out/Dockerfile.from-source.alsa.en"
# set_variables "$DIR/shared/" "$DIR/from-source/" \
# "$DIR/pulseaudio/" "$DIR/en_profile/" \
# | cat - "$template" | m4 > "$out/Dockerfile.from-source.pulseaudio.en"
# set_variables "$DIR/shared/" "$DIR/from-source/" \
# "$DIR/alsa/" "$DIR/all_profiles/" \
# | cat - "$template" | m4 > "$out/Dockerfile.from-source.alsa.all"
#-----------
# Pre-built
#-----------
# set_variables "$DIR/shared/" "$DIR/prebuilt/" \
# "$DIR/alsa/" "$DIR/en_profile/" \
# | cat - "$template" | m4 > "$out/Dockerfile.prebuilt.alsa.en"
# set_variables "$DIR/shared/" "$DIR/prebuilt/" \
# "$DIR/pulseaudio/" "$DIR/en_profile/" \
# | cat - "$template" | m4 > "$out/Dockerfile.prebuilt.pulseaudio.en"
set_variables "$DIR/shared/" "$DIR/prebuilt/" \
"$DIR/alsa/" "$DIR/all_profiles/" \
| cat - "$template" | m4 > "$out/Dockerfile.prebuilt.alsa.all"
@@ -1,3 +0,0 @@
COPY download/phonetisaurus-2019_${BUILD_ARCH}.deb /phonetisaurus.deb
RUN dpkg -i /phonetisaurus.deb && \
rm /phonetisaurus.deb
@@ -1,3 +0,0 @@
COPY download/rhasspy-tools_${BUILD_ARCH}.tar.gz /
RUN tar -C /usr -xvf /rhasspy-tools_${BUILD_ARCH}.tar.gz && \
rm -f /rhasspy-tools_${BUILD_ARCH}.tar.gz
@@ -1,10 +0,0 @@
RUN apt-get update && \
apt-get install --no-install-recommends --yes \
bash jq unzip \
python3 python3-pip python3-dev \
build-essential portaudio19-dev swig \
libatlas-base-dev \
sox espeak flite alsa-utils \
git curl \
autoconf libtool automake bison \
sphinxbase-utils sphinxtrain
@@ -1,16 +0,0 @@
RUN apt-get install -y pulseaudio
COPY etc/pulseaudio.client.conf /etc/pulse/client.conf
# Create new user
ENV UNAME=rhasspy
RUN export UNAME=$UNAME UID=1000 GID=1000 && \
mkdir -p "/home/${UNAME}" && \
echo "${UNAME}:x:${UID}:${GID}:${UNAME} User,,,:/home/${UNAME}:/bin/bash" >> /etc/passwd && \
echo "${UNAME}:x:${UID}:" >> /etc/group && \
mkdir -p /etc/sudoers.d && \
echo "${UNAME} ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/${UNAME} && \
chmod 0440 /etc/sudoers.d/${UNAME} && \
chown ${UID}:${GID} -R /home/${UNAME} && \
gpasswd -a ${UNAME} audio
ENV RHASSPY_APP /home/${UNAME}
@@ -1,3 +0,0 @@
# Switch to new user
USER $UNAME
ENV HOME /home/${UNAME}
-2
View File
@@ -1,2 +0,0 @@
# Install gstreamer and plugins
RUN apt-get install --no-install-recommends --yes gstreamer1.0-tools gstreamer1.0-plugins-good
-4
View File
@@ -1,4 +0,0 @@
COPY download/kaldi_${BUILD_ARCH}.tar.gz /kaldi.tar.gz
RUN mkdir -p /opt && \
tar -C /opt -xzf /kaldi.tar.gz && \
rm /kaldi.tar.gz
-9
View File
@@ -1,9 +0,0 @@
# Install mitlm
RUN apt-get install --no-install-recommends --yes gfortran
COPY download/mitlm-0.4.2.tar.xz /
RUN cd / && tar -xf mitlm-0.4.2.tar.xz && cd mitlm-0.4.2/ && \
./configure && \
make -j $MAKE_THREADS && \
make install && \
rm -rf /mitlm-0.4.2*
@@ -1,7 +0,0 @@
# Install Mycroft Precise
COPY download/precise-engine_0.3.0_${CPU_ARCH}.tar.gz /precise-engine.tar.gz
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then \
cd / && tar -xzf /precise-engine.tar.gz && \
ln -s /precise-engine/precise-engine /usr/bin/precise-engine && \
rm /precise-engine.tar.gz; \
fi
-9
View File
@@ -1,9 +0,0 @@
# Install Opengrm
COPY download/opengrm-ngram-1.3.3.tar.gz /
RUN cd / && tar -xf opengrm-ngram-1.3.3.tar.gz && \
cd opengrm-ngram-1.3.3 && \
./configure && \
make -j $MAKE_THREADS && \
make install && \
ldconfig && \
rm -rf /opengrm*
@@ -1,4 +0,0 @@
# Install Pocketsphinx Python module with no sound
COPY download/pocketsphinx-python.tar.gz /
RUN python3 -m pip install --no-cache-dir /pocketsphinx-python.tar.gz && \
rm -rf /pocketsphinx-python*
@@ -1,10 +0,0 @@
# Install Python dependencies
RUN python3 -m pip install --no-cache-dir setuptools wheel
RUN apt-get install -y libfreetype6-dev libpng-dev pkg-config libffi-dev libssl-dev
COPY requirements.txt /requirements.txt
RUN if [ "$BUILD_ARCH" != "amd64" ]; then \
grep -v flair /requirements.txt > /requirements-noflair.txt; \
mv /requirements-noflair.txt /requirements.txt; \
fi
RUN python3 -m pip install --no-cache-dir -r /requirements.txt
-2
View File
@@ -1,2 +0,0 @@
COPY etc/qemu-arm-static /usr/bin/
COPY etc/qemu-aarch64-static /usr/bin/
-10
View File
@@ -1,10 +0,0 @@
COPY profiles/defaults.json ${RHASSPY_APP}/profiles/
COPY docker/rhasspy ${RHASSPY_APP}/bin/
COPY dist/ ${RHASSPY_APP}/dist/
COPY etc/wav/* ${RHASSPY_APP}/etc/wav/
COPY rhasspy/profile_schema.json ${RHASSPY_APP}/rhasspy/
COPY rhasspy/train/jsgf2fst/*.py ${RHASSPY_APP}/rhasspy/train/jsgf2fst/
COPY rhasspy/train/*.py ${RHASSPY_APP}/rhasspy/train/
COPY *.py ${RHASSPY_APP}/
COPY rhasspy/*.py ${RHASSPY_APP}/rhasspy/
COPY VERSION ${RHASSPY_APP}/
-3
View File
@@ -1,3 +0,0 @@
# Install snowboy
COPY download/snowboy-1.3.0.tar.gz /
RUN if [ "$BUILD_ARCH" != "aarch64" ]; then pip3 install --no-cache-dir /snowboy-1.3.0.tar.gz; fi
-1
View File
@@ -1 +0,0 @@
RUN apt-get install --no-install-recommends --yes flite libttspico-utils lame
+9 -1
View File
@@ -69,7 +69,15 @@ Add to your [profile](profiles.md):
"username": "",
"port": 1883,
"password": "",
"site_id": "default"
"site_id": "default",
"tls": {
"enabled": false,
"ca_certs": "",
"cert_reqs": "CERT_REQUIRED",
"certfile": "",
"ciphers": "",
"keyfile": ""
}
}
```
+9 -1
View File
@@ -44,7 +44,15 @@ Add to your [profile](profiles.md):
"username": "",
"port": 1883,
"password": "",
"site_id": "default"
"site_id": "default",
"tls": {
"enabled": false,
"ca_certs": "",
"cert_reqs": "CERT_REQUIRED",
"certfile": "",
"ciphers": "",
"keyfile": ""
}
}
```
+9 -1
View File
@@ -86,7 +86,15 @@ Add to your [profile](profiles.md):
"username": "",
"port": 1883,
"password": "",
"site_id": "default"
"site_id": "default",
"tls": {
"enabled": false,
"ca_certs": "",
"cert_reqs": "CERT_REQUIRED",
"certfile": "",
"ciphers": "",
"keyfile": ""
}
}
```
+35 -8
View File
@@ -65,6 +65,25 @@ In order to do something with the `rhasspy_ChangeLightColor` event, create an au
See the documentation on [actions](https://www.home-assistant.io/docs/automation/action/) for the different things you can do with Home Assistant.
### Intents
More recent versions of Home Assistant can accept intents directly. Add the following to your `configuration.yaml` file:
```yaml
intent:
```
This will enable intents over the HTTP API. Next, write [intent scripts](https://www.home-assistant.io/integrations/intent_script) to handle each Rhasspy intent:
```yaml
intent_script:
ChangeLightColor:
action:
...
```
The possible [actions](https://www.home-assistant.io/docs/automation/action/) are the same as in automations.
### MQTT
In addition to events, Rhasspy can also publish intents through MQTT ([Hermes protocol](https://docs.snips.ai/reference/dialogue#intent)).
@@ -74,14 +93,22 @@ Add to your [profile](profiles.md):
```json
"mqtt": {
"enabled": true,
"host": "localhost",
"username": "",
"password": "",
"port": 1883,
"reconnect_sec": 5,
"site_id": "default",
"publish_intents": true
"enabled": true,
"host": "localhost",
"username": "",
"password": "",
"port": 1883,
"reconnect_sec": 5,
"site_id": "default",
"publish_intents": true,
"tls": {
"enabled": false,
"ca_certs": "",
"cert_reqs": "CERT_REQUIRED",
"certfile": "",
"ciphers": "",
"keyfile": ""
}
}
```
+1 -1
View File
@@ -55,7 +55,7 @@ See `rhasspy.intent.FuzzyWuzzyRecognizer` for details.
## Mycroft Adapt
Recognizes intents using [Mycroft Adapt](https://github.com/MycroftAI/adapt). Works best when you have a medium number of sentences (hundreds to thousands) and need to be able to recognize sentences not seen during training (no new words, though).
Recognizes intents using [Mycroft Adapt](https://github.com/MycroftAI/adapt). Works best when you have a medium number of sentences (hundreds to thousands) and need to be able to recognize sentences not seen during training (no new words, though). This recognizer does not support converters, i.e. numbers are not converted back to integers.
Add to your [profile](profiles.md):
+1 -1
View File
@@ -52,7 +52,7 @@ Application authors may want to use the [rhasspy-client](https://pypi.org/projec
* `?nohass=true` - stop Rhasspy from handling the intent
* `?timeout=<seconds>` - override default command timeout
* `?entity=<entity>&value=<value>` - set custom entity/value in recognized intent
* `/api/listen-for-wake-word`
* `/api/listen-for-wake`
* POST "on" to have Rhasspy listen for a wake word
* POST "off" to disable wake word
* `/api/lookup`
+24
View File
@@ -8,6 +8,7 @@ The following table summarizes language support for the various speech to text s
| ------ | ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- |
| [pocketsphinx](speech-to-text.md#pocketsphinx) | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | | &#x2713; | &#x2713; |
| [kaldi](speech-to-text.md#kaldi) | &#x2713; | &#x2713; | | &#x2713; | | &#x2713; | | | | | &#x2713; | | |
| [google](speech-to-text.md#google-cloud) | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; | &#x2713; |
## Pocketsphinx
@@ -77,6 +78,29 @@ Rhasspy expects a Kaldi-compatible profile to contain a `model` directory with a
If you just want to use Rhasspy for general speech to text, you can set `speech_to_text.kaldi.open_transcription` to `true` in your profile. This will use the included general language model (much slower) and ignore any custom voice commands you've specified.
## Google Cloud
Does speech recognition using [Google Cloud Speech-to-Text](https://cloud.google.com/speech-to-text) service.
You will need an active Google Cloud subscription and a JSON private key connected to a service account enabled to use
the speech-to-text API. The locale configured in your profile will be used for speech recognition.
```json
{
"locale": "en_US",
"speech_to_text": {
"system": "google",
"google": {
"credentials": "api-project-xxxxxxxx-abcdef.json",
"min_confidence": 0.7
}
}
}
```
Please note that this module sends the recorded audio after it's completed, so no streaming support.
See `rhasspy.stt.GoogleCloudDecoder` for details.
## Remote HTTP Server
Uses a remote HTTP server to transform speech (WAV) to text.
+9 -1
View File
@@ -181,7 +181,15 @@ Add to your [profile](profiles.md):
"username": "",
"port": 1883,
"password": "",
"site_id": "default"
"site_id": "default",
"tls": {
"enabled": false,
"ca_certs": "",
"cert_reqs": "CERT_REQUIRED",
"certfile": "",
"ciphers": "",
"keyfile": ""
}
}
```
+55 -6
View File
@@ -11,6 +11,7 @@ cpu_arch=$(uname --m)
DEFINE_string 'download-dir' "${this_dir}/download" 'Directory to cache downloaded files'
DEFINE_boolean 'precise' true 'Install Mycroft Precise'
DEFINE_boolean 'kaldi' true 'Install Kaldi'
DEFINE_boolean 'web' true "Install web UI"
DEFINE_boolean 'offline' false "Don't download anything"
DEFINE_boolean 'all-cpu' false 'Download dependencies for all CPU architectures'
DEFINE_string 'cpu-arch' "${cpu_arch}" 'CPU architecture (x86_64, armv7l, arm64v8, armv6l)'
@@ -44,6 +45,10 @@ if [[ "${FLAGS_kaldi}" -eq "${FLAGS_FALSE}" ]]; then
no_kaldi='true'
fi
if [[ "${FLAGS_web}" -eq "${FLAGS_FALSE}" ]]; then
no_web='true'
fi
# -----------------------------------------------------------------------------
function maybe_download {
@@ -65,8 +70,15 @@ declare -A CPU_TO_FRIENDLY
CPU_TO_FRIENDLY["x86_64"]="amd64"
CPU_TO_FRIENDLY["armv7l"]="armhf"
CPU_TO_FRIENDLY["arm64v8"]="aarch64"
CPU_TO_FRIENDLY["aarch64"]="aarch64"
CPU_TO_FRIENDLY["armv6l"]="armv6l"
declare -A FRIENDLY_TO_DOCKER
FRIENDLY_TO_DOCKER["amd64"]="amd64"
FRIENDLY_TO_DOCKER["armhf"]="armv7"
FRIENDLY_TO_DOCKER["aarch64"]="arm64"
FRIENDLY_TO_DOCKER["armv6l"]="armv6"
# CPU architecture
if [[ -n "${all_cpu}" ]]; then
CPU_ARCHS=("x86_64" "armv7l" "arm64v8")
@@ -81,12 +93,32 @@ fi
# -----------------------------------------------------------------------------
for FRIENDLY_ARCH in "${FRIENDLY_ARCHS[@]}"; do
rhasspy_files=("rhasspy-tools_${FRIENDLY_ARCH}.tar.gz" "rhasspy-web-dist.tar.gz")
rhasspy_files=()
if [[ -z "${no_tools}" ]]; then
# Install Rhasspy tools
rhasspy_files+=("rhasspy-tools_${FRIENDLY_ARCH}.tar.gz")
fi
if [[ -z "${no_web}" ]]; then
# Install web UI
rhasspy_files+=('rhasspy-web-dist.tar.gz')
fi
for rhasspy_file_name in "${rhasspy_files[@]}"; do
rhasspy_file="${download_dir}/${rhasspy_file_name}"
rhasspy_file_url="https://github.com/synesthesiam/rhasspy/releases/download/v2.0/${rhasspy_file_name}"
maybe_download "${rhasspy_file_url}" "${rhasspy_file}"
done
if [[ -z "${no_tools}" ]]; then
# Create link for docker buildx
DOCKER_ARCH="${FRIENDLY_TO_DOCKER[${FRIENDLY_ARCH}]}"
if [[ "${FRIENDLY_ARCH}" != "${DOCKER_ARCH}" ]]; then
ln -f "${download_dir}/rhasspy-tools_${FRIENDLY_ARCH}.tar.gz" \
"${download_dir}/rhasspy-tools_${DOCKER_ARCH}.tar.gz"
fi
fi
done
# -----------------------------------------------------------------------------
@@ -112,10 +144,18 @@ maybe_download "${snowboy_url}" "${snowboy_file}"
if [[ -z "${no_precise}" ]]; then
for CPU_ARCH in "${CPU_ARCHS[@]}"; do
case $CPU_ARCH in
x86_64|armv7l)
x86_64|armv7l|aarch64)
precise_file="${download_dir}/precise-engine_0.3.0_${CPU_ARCH}.tar.gz"
precise_url="https://github.com/MycroftAI/mycroft-precise/releases/download/v0.3.0/precise-engine_0.3.0_${CPU_ARCH}.tar.gz"
maybe_download "${precise_url}" "${precise_file}"
# Create link for docker buildx
FRIENDLY_ARCH="${CPU_TO_FRIENDLY[${CPU_ARCH}]}"
DOCKER_ARCH="${FRIENDLY_TO_DOCKER[${FRIENDLY_ARCH}]}"
if [[ "${CPU_ARCH}" != "${DOCKER_ARCH}" ]]; then
ln -f "${download_dir}/precise-engine_0.3.0_${CPU_ARCH}.tar.gz" \
"${download_dir}/precise-engine_0.3.0_${DOCKER_ARCH}.tar.gz"
fi
esac
done
fi
@@ -126,10 +166,19 @@ fi
if [[ -z "${no_kaldi}" ]]; then
for FRIENDLY_ARCH in "${FRIENDLY_ARCHS[@]}"; do
# Install pre-built package
kaldi_file="${download_dir}/kaldi_${FRIENDLY_ARCH}.tar.gz"
kaldi_url="https://github.com/synesthesiam/kaldi-docker/releases/download/v1.0/kaldi_${FRIENDLY_ARCH}.tar.gz"
maybe_download "${kaldi_url}" "${kaldi_file}"
if [[ "${FRIENDLY_ARCH}" != "armv6l" ]]; then
# Install pre-built package
kaldi_file="${download_dir}/kaldi_${FRIENDLY_ARCH}.tar.gz"
kaldi_url="https://github.com/synesthesiam/kaldi-docker/releases/download/v1.0/kaldi_${FRIENDLY_ARCH}.tar.gz"
maybe_download "${kaldi_url}" "${kaldi_file}"
# Create link for docker buildx
DOCKER_ARCH="${FRIENDLY_TO_DOCKER[${FRIENDLY_ARCH}]}"
if [[ "${FRIENDLY_ARCH}" != "${DOCKER_ARCH}" ]]; then
ln -f "${download_dir}/kaldi_${FRIENDLY_ARCH}.tar.gz" \
"${download_dir}/kaldi_${DOCKER_ARCH}.tar.gz"
fi
fi
done
fi
+61 -48
View File
@@ -1,17 +1,12 @@
#
# Copyright 2018 Picovoice Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
# file accompanying this source.
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
import os
@@ -20,7 +15,7 @@ from enum import Enum
class Porcupine(object):
"""Python binding for Picovoice's wake word detection (aka Porcupine) library."""
"""Python binding for Picovoice's wake word detection (Porcupine) engine."""
class PicovoiceStatuses(Enum):
"""Status codes corresponding to 'pv_status_t' defined in 'include/picovoice.h'"""
@@ -29,11 +24,17 @@ class Porcupine(object):
OUT_OF_MEMORY = 1
IO_ERROR = 2
INVALID_ARGUMENT = 3
STOP_ITERATION = 4
KEY_ERROR = 5
INVALID_STATE = 6
_PICOVOICE_STATUS_TO_EXCEPTION = {
PicovoiceStatuses.OUT_OF_MEMORY: MemoryError,
PicovoiceStatuses.IO_ERROR: IOError,
PicovoiceStatuses.INVALID_ARGUMENT: ValueError
PicovoiceStatuses.INVALID_ARGUMENT: ValueError,
PicovoiceStatuses.STOP_ITERATION: StopIteration,
PicovoiceStatuses.KEY_ERROR: KeyError,
PicovoiceStatuses.INVALID_STATE: ValueError,
}
class CPorcupine(Structure):
@@ -48,9 +49,9 @@ class Porcupine(object):
keyword_file_paths=None,
sensitivities=None):
"""
Loads Porcupine's shared library and creates an instance of wake word detection object.
Constructor.
:param library_path: Absolute path to Porcupine's shared library.
:param library_path: Absolute path to Porcupine's dynamic library.
:param model_file_path: Absolute path to file containing model parameters.
:param keyword_file_path: Absolute path to keyword file containing hyper-parameters. If not present then
'keyword_file_paths' will be used.
@@ -64,38 +65,38 @@ class Porcupine(object):
"""
if not os.path.exists(library_path):
raise IOError(f"Could not find Porcupine's library at '{library_path}'")
raise IOError("could'nt find Porcupine's library at '%s'" % library_path)
library = cdll.LoadLibrary(library_path)
if not os.path.exists(model_file_path):
raise IOError(f"Could not find model file at '{model_file_path}'")
raise IOError("could'nt find model file at '%s'" % model_file_path)
if sensitivity is not None and keyword_file_path is not None:
if not os.path.exists(keyword_file_path):
raise IOError(f"Could not find keyword file at '{keyword_file_path}'")
raise IOError("could'nt' find keyword file at '%s'" % keyword_file_path)
keyword_file_paths = [keyword_file_path]
if not (0 <= sensitivity <= 1):
raise ValueError('Sensitivity should be within [0, 1]')
raise ValueError('sensitivity should be within [0, 1]')
sensitivities = [sensitivity]
elif sensitivities is not None and keyword_file_paths is not None:
if len(keyword_file_paths) != len(sensitivities):
raise ValueError("Different number of sensitivity and keyword file path parameters are provided.")
raise ValueError("different number of sensitivity and keyword file path parameters are provided.")
for x in keyword_file_paths:
if not os.path.exists(os.path.expanduser(x)):
raise IOError(f"Could not find keyword file at '{x}'")
raise IOError("could not find keyword file at '%s'" % x)
for x in sensitivities:
if not (0 <= x <= 1):
raise ValueError('Sensitivity should be within [0, 1]')
raise ValueError('sensitivity should be within [0, 1]')
else:
raise ValueError("Sensitivity and/or keyword file path is missing")
raise ValueError("sensitivity and/or keyword file path is missing")
self._num_keywords = len(keyword_file_paths)
init_func = library.pv_porcupine_multiple_keywords_init
init_func = library.pv_porcupine_init
init_func.argtypes = [
c_char_p,
c_int,
@@ -107,44 +108,43 @@ class Porcupine(object):
self._handle = POINTER(self.CPorcupine)()
status = init_func(
model_file_path.encode(),
model_file_path.encode('utf-8'),
self._num_keywords,
(c_char_p * self._num_keywords)(*[os.path.expanduser(x).encode() for x in keyword_file_paths]),
(c_char_p * self._num_keywords)(*[os.path.expanduser(x).encode('utf-8') for x in keyword_file_paths]),
(c_float * self._num_keywords)(*sensitivities),
byref(self._handle))
if status is not self.PicovoiceStatuses.SUCCESS:
raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]('Initialization failed')
self.process_func = library.pv_porcupine_multiple_keywords_process
self.process_func.argtypes = [POINTER(self.CPorcupine), POINTER(c_short), POINTER(c_int)]
self.process_func.restype = self.PicovoiceStatuses
raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]('initialization failed')
self._delete_func = library.pv_porcupine_delete
self._delete_func.argtypes = [POINTER(self.CPorcupine)]
self._delete_func.restype = None
self._sample_rate = library.pv_sample_rate()
self.process_func = library.pv_porcupine_process
self.process_func.argtypes = [POINTER(self.CPorcupine), POINTER(c_short), POINTER(c_int)]
self.process_func.restype = self.PicovoiceStatuses
version_func = library.pv_porcupine_version
version_func.argtypes = []
version_func.restype = c_char_p
self._version = version_func().decode('utf-8')
self._frame_length = library.pv_porcupine_frame_length()
@property
def sample_rate(self):
"""Audio sample rate accepted by Porcupine library."""
self._sample_rate = library.pv_sample_rate()
return self._sample_rate
def delete(self):
"""Releases resources acquired by Porcupine's library."""
@property
def frame_length(self):
"""Number of audio samples per frame expected by C library."""
return self._frame_length
self._delete_func(self._handle)
def process(self, pcm):
"""
Monitors incoming audio stream for given wake word(s).
Processes a frame of the incoming audio stream and emits the detection result.
:param pcm: An array (or array-like) of consecutive audio samples. For more information regarding required audio
properties (i.e. sample rate, number of channels encoding, and number of samples per frame) please refer to
'include/pv_porcupine.h'.
:param pcm: A frame of audio samples. The number of samples per frame can be attained by calling
'.frame_length'. The incoming audio needs to have a sample rate equal to '.sample_rate' and be 16-bit
linearly-encoded. Porcupine operates on single-channel audio.
:return: For a single wake-word use cse True if wake word is detected. For multiple wake-word use case it
returns the index of detected wake-word. Indexing is 0-based and according to ordering of input keyword file
paths. It returns -1 when no keyword is detected.
@@ -153,7 +153,7 @@ class Porcupine(object):
result = c_int()
status = self.process_func(self._handle, (c_short * len(pcm))(*pcm), byref(result))
if status is not self.PicovoiceStatuses.SUCCESS:
raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]('Processing failed')
raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]()
keyword_index = result.value
@@ -162,7 +162,20 @@ class Porcupine(object):
else:
return keyword_index
def delete(self):
"""Releases resources acquired by Porcupine's library."""
@property
def version(self):
"""Getter for version"""
self._delete_func(self._handle)
return self._version
@property
def frame_length(self):
"""Getter for number of audio samples per frame."""
return self._frame_length
@property
def sample_rate(self):
"""Audio sample rate accepted by Picovoice."""
return self._sample_rate
+16 -8
View File
@@ -119,7 +119,15 @@
"publish_intents": true,
"reconnect_sec": 5,
"site_id": "default",
"username": ""
"username": "",
"tls": {
"enabled": false,
"ca_certs": "",
"cert_reqs": "CERT_REQUIRED",
"certfile": "",
"ciphers": "",
"keyfile": ""
}
},
"rhasspy": {
"listen_on_start": true,
@@ -324,31 +332,31 @@
"cache": false
},
"porcupine_params.pv": {
"url": "https://github.com/Picovoice/Porcupine/raw/master/lib/common/porcupine_params.pv",
"url": "https://github.com/Picovoice/porcupine/raw/v1.7/lib/common/porcupine_params.pv",
"cache": false
},
"porcupine.ppn": {
"cache": false,
"x86_64": {
"url": "https://github.com/Picovoice/Porcupine/raw/master/resources/keyword_files/linux/porcupine_linux.ppn"
"url": "https://github.com/Picovoice/Porcupine/raw/v1.7/resources/keyword_files/linux/porcupine_linux.ppn"
},
"armv7l": {
"url": "https://github.com/Picovoice/Porcupine/raw/master/resources/keyword_files/raspberrypi/porcupine_raspberrypi.ppn"
"url": "https://github.com/Picovoice/porcupine/raw/v1.7/resources/keyword_files/raspberry-pi/porcupine_raspberry-pi.ppn"
},
"aarch64": {
"url": "https://github.com/Picovoice/Porcupine/raw/master/resources/keyword_files/raspberrypi/porcupine_raspberrypi.ppn"
"url": "https://github.com/Picovoice/porcupine/raw/v1.7/resources/keyword_files/raspberry-pi/porcupine_raspberry-pi.ppn"
}
},
"libpv_porcupine.so": {
"cache": false,
"x86_64": {
"url": "https://github.com/Picovoice/Porcupine/raw/master/lib/linux/x86_64/libpv_porcupine.so"
"url": "https://github.com/Picovoice/porcupine/raw/v1.7/lib/linux/x86_64/libpv_porcupine.so"
},
"armv7l": {
"url": "https://github.com/Picovoice/Porcupine/raw/master/lib/raspberry-pi/cortex-a53/libpv_porcupine.so"
"url": "https://github.com/Picovoice/porcupine/raw/v1.7/lib/raspberry-pi/cortex-a53/libpv_porcupine.so"
},
"aarch64": {
"url": "https://github.com/Picovoice/Porcupine/raw/master/lib/raspberry-pi/cortex-a53/libpv_porcupine.so"
"url": "https://github.com/Picovoice/porcupine/raw/v1.7/lib/raspberry-pi/cortex-a53/libpv_porcupine.so"
}
}
}
+2
View File
@@ -2,6 +2,7 @@ adapt-parser==0.3.4
aiohttp==3.6.2
doit==0.31.1
fuzzywuzzy[speedup]==0.17.0
google-cloud-speech==1.3.1
google-cloud-texttospeech==0.5.0
html5lib==1.0.1
json5==0.7.0
@@ -10,6 +11,7 @@ networkx>=2.0
num2words==0.5.10
openfst==1.6.9
paho-mqtt==1.5.0
precise-runner==0.3.1
PyAudio==0.2.11
pydash==4.7.6
quart==0.6.15
+6 -3
View File
@@ -5,6 +5,7 @@ import logging
import os
import platform
import shutil
import ssl
import tempfile
from collections import defaultdict
from pathlib import Path
@@ -86,6 +87,8 @@ class RhasspyCore:
self.defaults = Profile.load_defaults(system_profiles_dir)
self.loop = asyncio.get_event_loop()
self.ssl_context = ssl.SSLContext()
self._session: Optional[aiohttp.ClientSession] = aiohttp.ClientSession()
self.dialogue_manager: Optional[RhasspyActor] = None
@@ -103,7 +106,7 @@ class RhasspyCore:
def siteId(self) -> str:
"""Get default MQTT siteId"""
try:
siteIds = self.profile.get("mqtt.siteId", "default").split(",")[0]
return self.profile.get("mqtt.siteId", "default").split(",")[0]
except Exception:
return "default"
@@ -523,7 +526,7 @@ class RhasspyCore:
self._logger.debug(status)
os.makedirs(os.path.dirname(filename), exist_ok=True)
async with self.session.get(url) as response:
async with self.session.get(url, ssl=self.ssl_context) as response:
with open(filename, "wb") as out_file:
async for chunk in response.content.iter_chunked(chunk_size):
out_file.write(chunk)
@@ -581,7 +584,7 @@ class RhasspyCore:
src_path = dest_path
# Check if file is already in cache
if os.path.exists(src_path) and (os.path.getsize(src_path) > 0):
if not delete and os.path.exists(src_path) and (os.path.getsize(src_path) > 0):
self._logger.debug(
"Using cached %s for %s", src_path, dest_name
)
+11
View File
@@ -389,6 +389,7 @@ class RasaIntentRecognizer(RhasspyActor):
RhasspyActor.__init__(self)
self.project_name = ""
self.parse_url = ""
self.min_confidence: float = 0
def to_started(self, from_state: str) -> None:
"""Transition to started state."""
@@ -397,6 +398,7 @@ class RasaIntentRecognizer(RhasspyActor):
self.project_name = rasa_config.get(
"project_name", f"rhasspy_{self.profile.name}"
)
self.min_confidence = rasa_config.get("min_confidence", 0)
self.parse_url = urljoin(url, "model/parse")
def in_started(self, message: Any, sender: RhasspyActor) -> None:
@@ -406,6 +408,15 @@ class RasaIntentRecognizer(RhasspyActor):
intent = self.recognize(message.text)
intent["intent"]["name"] = intent["intent"]["name"] or ""
logging.debug(repr(intent))
confidence = intent["intent"]["confidence"]
if confidence < self.min_confidence:
intent["intent"]["name"] = ""
self._logger.warning(
"Intent did not meet confidence threshold: %s < %s",
confidence,
self.min_confidence,
)
except Exception:
self._logger.exception("in_started")
intent = empty_intent()
+12 -1
View File
@@ -77,10 +77,12 @@ class HomeAssistantIntentHandler(RhasspyActor):
self.event_type_format = ""
self.pem_file = ""
self.handle_type: HomeAssistantHandleType = HomeAssistantHandleType.EVENT
self.speech_actor: Optional[RhasspyActor] = None
def to_started(self, from_state: str) -> None:
"""Transition to started state."""
self.hass_config = self.profile.get("home_assistant", {})
self.speech_actor = self.config.get("speech")
# Python format string for generating event type name
self.event_type_format = self.hass_config.get(
@@ -170,6 +172,15 @@ class HomeAssistantIntentHandler(RhasspyActor):
kwargs["verify"] = self.pem_file
response = requests.post(post_url, **kwargs)
response.raise_for_status()
intent = response.json()
self._logger.debug(intent)
# Check for speech
speech_text = intent.get("speech", {}).get("plain", {}).get("speech", "")
if speech_text and self.speech_actor:
self.send(self.speech_actor, SpeakSentence(speech_text))
else:
# Send event
post_url = urljoin(self.hass_config["url"], "api/events/" + event_type)
@@ -184,7 +195,7 @@ class HomeAssistantIntentHandler(RhasspyActor):
response = requests.post(post_url, **kwargs)
self._logger.debug("POSTed intent to %s", post_url)
response.raise_for_status()
response.raise_for_status()
# -------------------------------------------------------------------------
+3 -2
View File
@@ -193,7 +193,8 @@ class RasaIntentTrainer(RhasspyActor):
entity = None
sentence_tokens = []
entity_tokens = []
for token in intent_sent["raw_tokens"]:
for raw_token in intent_sent["raw_tokens"]:
token = raw_token
if entity and (raw_index >= entity["raw_end"]):
# Finish current entity
last_token = entity_tokens[-1]
@@ -217,7 +218,7 @@ class RasaIntentTrainer(RhasspyActor):
# Add directly to sentence
sentence_tokens.append(token)
raw_index += len(token) + 1
raw_index += len(raw_token) + 1
if entity:
# Finish final entity
+33 -4
View File
@@ -10,8 +10,13 @@ from typing import Any, Dict, List
import pydash
from rhasspy.actor import RhasspyActor
from rhasspy.events import (MqttConnected, MqttDisconnected, MqttMessage,
MqttPublish, MqttSubscribe)
from rhasspy.events import (
MqttConnected,
MqttDisconnected,
MqttMessage,
MqttPublish,
MqttSubscribe,
)
# -----------------------------------------------------------------------------
# Events
@@ -48,6 +53,7 @@ class HermesMqtt(RhasspyActor):
self.password = None
self.reconnect_sec = 5
self.publish_intents = True
self.tls = {"enabled": False}
# -------------------------------------------------------------------------
@@ -66,6 +72,7 @@ class HermesMqtt(RhasspyActor):
self.password = self.profile.get("mqtt.password", None)
self.reconnect_sec = self.profile.get("mqtt.reconnect_sec", 5)
self.publish_intents = self.profile.get("mqtt.publish_intents", True)
self.tls = self.profile.get("mqtt.tls", {"enabled": False})
if self.profile.get("mqtt.enabled", False):
self.transition("connecting")
@@ -84,6 +91,28 @@ class HermesMqtt(RhasspyActor):
self.client.on_message = self.on_message
self.client.on_disconnect = self.on_disconnect
if pydash.get(self.tls, "enabled", False):
import ssl
allowed_cert_reqs = {
"CERT_REQUIRED": ssl.CERT_REQUIRED,
"CERT_OPTIONAL": ssl.CERT_OPTIONAL,
"CERT_NONE": ssl.CERT_NONE,
}
self.client.tls_set(
ca_certs=pydash.get(self.tls, "ca_certs", None),
cert_reqs=pydash.get(
allowed_cert_reqs,
pydash.get(self.tls, "cert_reqs", "CERT_REQUIRED"),
ssl.CERT_REQUIRED,
),
certfile=pydash.get(self.tls, "certfile", None),
ciphers=pydash.get(self.tls, "ciphers", None),
keyfile=pydash.get(self.tls, "keyfile", None),
tls_version=ssl.PROTOCOL_TLS,
)
if self.username:
self._logger.debug("Logging in as %s", self.username)
self.client.username_pw_set(self.username, self.password)
@@ -259,12 +288,12 @@ class HermesMqtt(RhasspyActor):
"slotName": ev["entity"],
"confidence": 1,
"value": {"kind": ev["entity"], "value": ev["value"]},
"rawValue": ev["value"],
"rawValue": ev.get("raw_value", ev["value"]),
}
for ev in intent.get("entities", [])
],
"asrTokens": [],
"asrConfidence": 1
"asrConfidence": 1,
}
).encode()
+12 -1
View File
@@ -417,7 +417,18 @@
"reconnect_sec": { "type": "integer", "min": 0 },
"site_id": { "type": "string" },
"username": { "type": "string" },
"publish_intents": { "type": "boolean" }
"publish_intents": { "type": "boolean" },
"tls": {
"type": "dict",
"schema": {
"enabled": { "type": "boolean" },
"ca_certs": { "type": "string" },
"cert_reqs": { "type": "string" },
"certfile": { "type": "string" },
"ciphers": { "type": "string" },
"keyfile": { "type": "string" }
}
}
}
},
+91 -1
View File
@@ -25,6 +25,7 @@ def get_decoder_class(system: str) -> Type[RhasspyActor]:
"pocketsphinx",
"kaldi",
"remote",
"google",
"hass_stt",
"command",
], f"Invalid speech to text system: {system}"
@@ -38,6 +39,9 @@ def get_decoder_class(system: str) -> Type[RhasspyActor]:
if system == "remote":
# Use remote Rhasspy server
return RemoteDecoder
if system == "google":
# Use remote Google Cloud
return GoogleCloudDecoder
if system == "hass_stt":
# Use Home Assistant STT platform
return HomeAssistantSTTIntegration
@@ -320,6 +324,90 @@ class RemoteDecoder(RhasspyActor):
return response.text
# -----------------------------------------------------------------------------
# Google Cloud Speech-to-text decoder
# -----------------------------------------------------------------------------
class GoogleCloudDecoder(RhasspyActor):
"""Forwards speech to text request to Google Cloud STT service"""
def __init__(self) -> None:
RhasspyActor.__init__(self)
self.client = None
self.language_code = None
self.min_confidence: float = 0
def to_started(self, from_state: str) -> None:
"""Transition to started state."""
from google.cloud import speech
credentials_file = self.profile.get("speech_to_text.google.credentials")
self.min_confidence = self.profile.get("speech_to_text.google.min_confidence")
self.language_code = self.profile.get("locale").replace("_", "-")
from google.auth import environment_vars
os.environ[environment_vars.CREDENTIALS] = credentials_file
self.client = speech.SpeechClient()
def in_started(self, message: Any, sender: RhasspyActor) -> None:
"""Handle messages in started state."""
if isinstance(message, TranscribeWav):
try:
text, confidence = self.transcribe_wav(message.wav_data)
self._logger.debug(text)
self.send(
message.receiver or sender,
WavTranscription(
text, confidence=confidence, handle=message.handle
),
)
except Exception:
self._logger.exception("transcribing wav")
# Send empty transcription back
self.send(
message.receiver or sender,
WavTranscription("", confidence=0, handle=message.handle),
)
def transcribe_wav(self, wav_data: bytes) -> Tuple[str, float]:
"""POST to remote server and return response."""
from google.cloud.speech import enums
from google.cloud.speech import types
self._logger.debug(
"POSTing %d byte(s) of WAV data to Google Cloud STT", len(wav_data)
)
audio = types.RecognitionAudio(content=wav_data)
config = types.RecognitionConfig(
encoding=enums.RecognitionConfig.AudioEncoding.LINEAR16,
sample_rate_hertz=16000,
model="command_and_search",
language_code=self.language_code,
)
response = self.client.recognize(config, audio)
if len(response.results) == 0:
self._logger.debug("No results returned.")
return "", 0
result = response.results[0].alternatives[0]
self._logger.debug("Transcription confidence: %s", result.confidence)
if result.confidence >= self.min_confidence:
return result.transcript, result.confidence
self._logger.warning(
"Transcription did not meet confidence threshold: %s < %s",
result.confidence,
self.min_confidence,
)
return "", 0
# -----------------------------------------------------------------------------
# Kaldi Decoder
# http://kaldi-asr.org
@@ -565,7 +653,9 @@ class HomeAssistantSTTIntegration(RhasspyActor):
audio_data = audio_data[self.chunk_size :]
# POST WAV data to STT
response = requests.post(stt_url, data=generate_chunks(), **kwargs) # type: ignore
response = requests.post(
stt_url, data=generate_chunks(), **kwargs
) # type: ignore
response.raise_for_status()
response_json = response.json()
+2 -1
View File
@@ -925,7 +925,8 @@ class PorcupineWakeListener(RhasspyActor):
"""Load porcupine library."""
if self.handle is None:
for kw_path in self.keyword_paths:
assert kw_path.is_file(), f"Missing {kw_path}"
if not kw_path.is_file():
self._logger.error("Missing porcupine keyword at {kw_path}")
from porcupine import Porcupine
+9 -1
View File
@@ -109,7 +109,15 @@ const profileDefaults = {
"reconnect_sec": 5,
"site_id": "default",
"username": "",
"publish_intents": true
"publish_intents": true,
"tls": {
"enabled": false,
"ca_certs": "",
"cert_reqs": "CERT_REQUIRED",
"certfile": "",
"ciphers": "",
"keyfile": ""
}
},
"rhasspy": {
"default_profile": "en",
+2 -2
View File
@@ -86,7 +86,7 @@
<div class="form-row">
<div class="col">
<p class="text-muted">
Requires the <a href="https://www.home-assistant.io/integrations/intent/">intent component</a> in your <tt>configuration.yaml</tt>
Requires the <tt>intent</tt> component and <a href="https://www.home-assistant.io/integrations/intent_script">intent scripts</a> in your <tt>configuration.yaml</tt>
</p>
</div>
</div>
@@ -137,7 +137,7 @@
<div class="form-row">
<label for="remote-handle-url" class="col-form-label">Remote URL</label>
<div class="col">
<input id="remote-handle-url" type="text" class="form-control" v-model="profile.handle.remote.url" :disabled="profile.intent.system != 'remote'">
<input id="remote-handle-url" type="text" class="form-control" v-model="profile.handle.remote.url" :disabled="profile.handle.system != 'remote'">
</div>
</div>
</div>
+52
View File
@@ -70,6 +70,58 @@
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<input id="mqtt-tls-enabled" type="checkbox" v-model="profile.mqtt.tls.enabled" :disabled="!profile.mqtt.enabled">
<label for="mqtt-tls-enabled" class="col-form-label">Enable MQTT over TLS</label>
</div>
</div>
<template v-if="profile.mqtt.tls.enabled">
<div class="form-group">
<div class="form-row">
<label for="mqtt-tls-ca_certs" class="col-form-label">ca_certs</label>
<div class="col-sm-auto">
<input id="mqtt-tls-ca_certs" type="text" class="form-control" v-model="profile.mqtt.tls.ca_certs" :disabled="!profile.mqtt.enabled">
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<label for="mqtt-tls-cert_reqs" class="col-form-label">cert_reqs</label>
<div class="col-sm-auto">
<select id="mqtt-tls-cert_reqs" v-model="profile.mqtt.tls.cert_reqs" :disabled="!profile.mqtt.enabled">
<option value="CERT_REQUIRED" default>CERT_REQUIRED</option>
<option value="CERT_OPTIONAL">CERT_OPTIONAL</option>
<option value="CERT_NONE">CERT_NONE</option>
</select>
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<label for="mqtt-tls-certfile" class="col-form-label">certfile</label>
<div class="col-sm-auto">
<input id="mqtt-tls-certfile" type="text" class="form-control" v-model="profile.mqtt.tls.certfile" :disabled="!profile.mqtt.enabled">
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<label for="mqtt-tls-ciphers" class="col-form-label">ciphers</label>
<div class="col-sm-auto">
<input id="mqtt-tls-ciphers" type="text" class="form-control" v-model="profile.mqtt.tls.ciphers" :disabled="!profile.mqtt.enabled">
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<label for="mqtt-tls-keyfile" class="col-form-label">keyfile</label>
<div class="col-sm-auto">
<input id="mqtt-tls-keyfile" type="text" class="form-control" v-model="profile.mqtt.tls.keyfile" :disabled="!profile.mqtt.enabled">
</div>
</div>
</div>
</template>
<div class="form-group">
<div class="form-row">
<input type="checkbox" id="mqtt-publish_intents" v-model="profile.mqtt.publish_intents" :disabled="!profile.mqtt.enabled">
+38 -22
View File
@@ -89,28 +89,44 @@
</p>
</div>
<hr>
<!-- <div class="form-group"> -->
<!-- <div class="form-row"> -->
<!-- <div class="form-check"> -->
<!-- <input class="form-check-input" type="radio" name="wake-system" id="wake-system-precise" value="precise" v-model="profile.wake.system"> -->
<!-- <label class="form-check-label" for="wake-system-precise"> -->
<!-- Use <a href="https://github.com/MycroftAI/mycroft-precise">Mycroft Precise</a> on this device -->
<!-- </label> -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<!-- <div class="form-group"> -->
<!-- <div class="form-row"> -->
<!-- <label for="precise-model" class="col-form-label">Model Name</label> -->
<!-- <div class="col-sm-auto"> -->
<!-- <input id="precise-model" type="text" class="form-control" v-model="profile.wake.precise.model" :disabled="profile.wake.system != 'precise'"> -->
<!-- </div> -->
<!-- <div class="col text-muted"> -->
<!-- Put models in your profile directory -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<!-- <hr> -->
<div class="form-group">
<div class="form-row">
<div class="form-check">
<input class="form-check-input" type="radio" name="wake-system" id="wake-system-precise" value="precise" v-model="profile.wake.system">
<label class="form-check-label" for="wake-system-precise">
Use <a href="https://github.com/MycroftAI/mycroft-precise">Mycroft Precise</a> on this device
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<label for="precise-model" class="col-form-label">Model Name</label>
<div class="col-sm-auto">
<input id="precise-model" type="text" class="form-control" v-model="profile.wake.precise.model" :disabled="profile.wake.system != 'precise'">
</div>
<div class="col text-muted">
Put models in the <tt>precise</tt> directory in your profile
</div>
</div>
<div class="form-group">
<div class="form-row">
<label for="wake-precise-sensitivity" class="col-form-label">Sensitivity</label>
<div class="col-sm-auto">
<input id="wake-precise-sensitivity" type="text" class="form-control" v-model="profile.wake.precise.sensitivity" :disabled="profile.wake.system != 'precise'">
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<label for="wake-precise-trigger-level" class="col-form-label">Trigger Level</label>
<div class="col-sm-auto">
<input id="wake-precise-trigger-level" type="text" class="form-control" v-model="profile.wake.precise.trigger_level" :disabled="profile.wake.system != 'precise'">
</div>
</div>
</div>
</div>
<hr>
<div class="form-group">
<div class="form-row">
<div class="form-check">