diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..26e59a2 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "pip" # See documentation for possible values + directory: "/requirements" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/build_tests.yml b/.github/workflows/build_tests.yml index f5a9411..3a71fbb 100644 --- a/.github/workflows/build_tests.yml +++ b/.github/workflows/build_tests.yml @@ -13,4 +13,6 @@ jobs: uses: neongeckocom/.github/.github/workflows/python_build_tests.yml@master with: test_pipaudit: true - pipaudit_ignored: "GHSA-r9hx-vwmv-q579 PYSEC-2022-43012 GHSA-j8r2-6x86-q33q" \ No newline at end of file + # PYSEC-2023-228 is a pip vulnerability that only exists in the pipeline + # GHSA-9wx4-h78v-vm56 is problematic but it's an issue upstream + pipaudit_ignored: "GHSA-r9hx-vwmv-q579 PYSEC-2022-43012 GHSA-j8r2-6x86-q33q PYSEC-2023-228 GHSA-9wx4-h78v-vm56" diff --git a/.github/workflows/install_tests.yml b/.github/workflows/install_tests.yml index 4aaabea..1df4dad 100644 --- a/.github/workflows/install_tests.yml +++ b/.github/workflows/install_tests.yml @@ -11,14 +11,15 @@ jobs: strategy: max-parallel: 2 matrix: - python-version: [ 3.7, 3.8, 3.9, "3.10" ] + python-version: [3.8, 3.9, "3.10", "3.11"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + cache: "pip" - name: Install Build Tools run: | python -m pip install build wheel @@ -31,4 +32,4 @@ jobs: python setup.py bdist_wheel - name: Install package run: | - pip install .[all] \ No newline at end of file + pip install .[all] diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index eba3247..6d1c3b1 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -4,29 +4,29 @@ on: branches: - dev paths-ignore: - - 'ovos_config/version.py' - - 'examples/**' - - '.github/**' - - '.gitignore' - - 'LICENSE' - - 'CHANGELOG.md' - - 'MANIFEST.in' - - 'readme.md' - - 'scripts/**' + - "ovos_config/version.py" + - "examples/**" + - ".github/**" + - ".gitignore" + - "LICENSE" + - "CHANGELOG.md" + - "MANIFEST.in" + - "readme.md" + - "scripts/**" push: branches: - master paths-ignore: - - 'ovos_config/version.py' - - 'requirements/**' - - 'examples/**' - - '.github/**' - - '.gitignore' - - 'LICENSE' - - 'CHANGELOG.md' - - 'MANIFEST.in' - - 'readme.md' - - 'scripts/**' + - "ovos_config/version.py" + - "requirements/**" + - "examples/**" + - ".github/**" + - ".gitignore" + - "LICENSE" + - "CHANGELOG.md" + - "MANIFEST.in" + - "readme.md" + - "scripts/**" workflow_dispatch: jobs: @@ -34,14 +34,15 @@ jobs: strategy: max-parallel: 2 matrix: - python-version: [ 3.7, 3.8, 3.9] + python-version: [3.8, 3.9, "3.10", "3.11"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + cache: "pip" - name: Install System Dependencies run: | sudo apt-get update @@ -62,4 +63,4 @@ jobs: - name: Upload coverage env: CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}} - uses: codecov/codecov-action@v2 + uses: codecov/codecov-action@v4 diff --git a/.gitignore b/.gitignore index 9595be5..cb7251c 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ dist # Created by unit tests .pytest_cache/ +test_conf.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 84ec512..f212c97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,89 +1,236 @@ # Changelog -## [V0.0.12a9](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.12a9) (2023-12-28) +## [V0.0.13a27](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a27) (2024-08-16) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.12a8...V0.0.12a9) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a26...V0.0.13a27) + +**Breaking changes:** + +- deprecate/ovos\_conf [\#138](https://github.com/OpenVoiceOS/ovos-config/pull/138) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.13a26](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a26) (2024-08-05) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a25...V0.0.13a26) + +**Merged pull requests:** + +- document "fake\_barge\_in" [\#144](https://github.com/OpenVoiceOS/ovos-config/pull/144) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.13a25](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a25) (2024-08-03) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a24...V0.0.13a25) **Merged pull requests:** -- stable utils [\#91](https://github.com/OpenVoiceOS/ovos-config/pull/91) ([JarbasAl](https://github.com/JarbasAl)) +- document "common\_query" config options [\#143](https://github.com/OpenVoiceOS/ovos-config/pull/143) ([JarbasAl](https://github.com/JarbasAl)) -## [V0.0.12a8](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.12a8) (2023-12-28) +## [V0.0.13a24](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a24) (2024-07-17) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a23...V0.0.13a24) + +**Merged pull requests:** -[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.12a7...V0.0.12a8) +- document audio options [\#141](https://github.com/OpenVoiceOS/ovos-config/pull/141) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.13a23](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a23) (2024-07-11) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a22...V0.0.13a23) + +**Merged pull requests:** + +- tweak OCP defaults [\#139](https://github.com/OpenVoiceOS/ovos-config/pull/139) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.13a22](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a22) (2024-06-25) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a21...V0.0.13a22) **Fixed bugs:** -- drop mycroft-core config location [\#90](https://github.com/OpenVoiceOS/ovos-config/pull/90) ([JarbasAl](https://github.com/JarbasAl)) +- revert to single thread [\#137](https://github.com/OpenVoiceOS/ovos-config/pull/137) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.13a21](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a21) (2024-06-22) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a20...V0.0.13a21) + +**Implemented enhancements:** + +- feat: add /usr/share as a config location [\#128](https://github.com/OpenVoiceOS/ovos-config/pull/128) ([PureTryOut](https://github.com/PureTryOut)) + +## [V0.0.13a20](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a20) (2024-06-22) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a19...V0.0.13a20) -## [V0.0.12a7](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.12a7) (2023-12-28) +**Fixed bugs:** -[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.12a6...V0.0.12a7) +- log\_level change should be handles by services [\#125](https://github.com/OpenVoiceOS/ovos-config/issues/125) **Merged pull requests:** -- fix instant listen inline doc [\#87](https://github.com/OpenVoiceOS/ovos-config/pull/87) ([emphasize](https://github.com/emphasize)) +- Update mycroft.conf [\#136](https://github.com/OpenVoiceOS/ovos-config/pull/136) ([JarbasAl](https://github.com/JarbasAl)) -## [V0.0.12a6](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.12a6) (2023-12-27) +## [V0.0.13a19](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a19) (2024-06-18) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.12a5...V0.0.12a6) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a18...V0.0.13a19) **Fixed bugs:** -- fix circular import [\#89](https://github.com/OpenVoiceOS/ovos-config/pull/89) ([emphasize](https://github.com/emphasize)) +- update workflows [\#108](https://github.com/OpenVoiceOS/ovos-config/issues/108) +- `ovos-config set` doesn't take the path syntax that `ovos-config get` outputs [\#73](https://github.com/OpenVoiceOS/ovos-config/issues/73) +- ovos-config command line not giving expected response [\#59](https://github.com/OpenVoiceOS/ovos-config/issues/59) +- fix config set [\#134](https://github.com/OpenVoiceOS/ovos-config/pull/134) ([JarbasAl](https://github.com/JarbasAl)) **Closed issues:** -- Exception fetching remote configuration: No module named 'ovos\_backend\_client' [\#75](https://github.com/OpenVoiceOS/ovos-config/issues/75) +- source/destination documentation [\#69](https://github.com/OpenVoiceOS/ovos-config/issues/69) + +## [V0.0.13a18](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a18) (2024-06-11) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a17...V0.0.13a18) -## [V0.0.12a5](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.12a5) (2023-12-23) +**Implemented enhancements:** + +- better listener defaults [\#133](https://github.com/OpenVoiceOS/ovos-config/pull/133) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.13a17](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a17) (2024-06-08) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.12a4...V0.0.12a5) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a16...V0.0.13a17) **Fixed bugs:** -- fix/untangle\_from\_LF [\#88](https://github.com/OpenVoiceOS/ovos-config/pull/88) ([JarbasAl](https://github.com/JarbasAl)) +- trying to black list a skill. throws error [\#118](https://github.com/OpenVoiceOS/ovos-config/issues/118) +- fix: unbound local var [\#127](https://github.com/OpenVoiceOS/ovos-config/pull/127) ([mikejgray](https://github.com/mikejgray)) -## [V0.0.12a4](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.12a4) (2023-12-19) +## [V0.0.13a16](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a16) (2024-06-06) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a15...V0.0.13a16) + +**Merged pull requests:** -[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.12a3...V0.0.12a4) +- Update python-dateutil requirement from ~=2.6 to ~=2.9 in /requirements [\#115](https://github.com/OpenVoiceOS/ovos-config/pull/115) ([dependabot[bot]](https://github.com/apps/dependabot)) + +## [V0.0.13a15](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a15) (2024-06-06) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a14...V0.0.13a15) **Fixed bugs:** -- Force websocket to bind on 127.0.0.1 [\#86](https://github.com/OpenVoiceOS/ovos-config/pull/86) ([goldyfruit](https://github.com/goldyfruit)) +- fix/typo [\#126](https://github.com/OpenVoiceOS/ovos-config/pull/126) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.13a14](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a14) (2024-06-04) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a13...V0.0.13a14) + +**Merged pull requests:** + +- feat/ocp\_pipeline [\#96](https://github.com/OpenVoiceOS/ovos-config/pull/96) ([NeonJarbas](https://github.com/NeonJarbas)) + +## [V0.0.13a13](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a13) (2024-05-30) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a12...V0.0.13a13) + +**Merged pull requests:** -## [V0.0.12a3](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.12a3) (2023-12-07) +- move to vosk [\#124](https://github.com/OpenVoiceOS/ovos-config/pull/124) ([JarbasAl](https://github.com/JarbasAl)) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.12a2...V0.0.12a3) +## [V0.0.13a12](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a12) (2024-02-26) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a11...V0.0.13a12) + +## [V0.0.13a11](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a11) (2024-02-26) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a10...V0.0.13a11) + +**Merged pull requests:** + +- Update mycroft.conf [\#112](https://github.com/OpenVoiceOS/ovos-config/pull/112) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.13a10](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a10) (2024-02-26) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a9...V0.0.13a10) + +**Merged pull requests:** + +- Update ovos-backend-client requirement from \<0.1.0 to \<0.2.0 in /requirements [\#104](https://github.com/OpenVoiceOS/ovos-config/pull/104) ([dependabot[bot]](https://github.com/apps/dependabot)) + +## [V0.0.13a9](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a9) (2024-02-26) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a8...V0.0.13a9) **Implemented enhancements:** -- feat/lang\_utils [\#85](https://github.com/OpenVoiceOS/ovos-config/pull/85) ([JarbasAl](https://github.com/JarbasAl)) +- improve env vars handling [\#54](https://github.com/OpenVoiceOS/ovos-config/pull/54) ([JarbasAl](https://github.com/JarbasAl)) + +**Merged pull requests:** + +- Update ovos-bus-client requirement from ~=0.0.3 to ~=0.0.8 in /requirements [\#106](https://github.com/OpenVoiceOS/ovos-config/pull/106) ([dependabot[bot]](https://github.com/apps/dependabot)) + +## [V0.0.13a8](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a8) (2024-02-24) -## [V0.0.12a2](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.12a2) (2023-12-06) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a7...V0.0.13a8) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.12a1...V0.0.12a2) +**Merged pull requests:** + +- fix: "adapt\_medium" before padatious [\#110](https://github.com/OpenVoiceOS/ovos-config/pull/110) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.13a7](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a7) (2024-02-07) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a6...V0.0.13a7) **Fixed bugs:** -- Update locale.py [\#84](https://github.com/OpenVoiceOS/ovos-config/pull/84) ([JarbasAl](https://github.com/JarbasAl)) +- fix/remove\_broken\_patch [\#107](https://github.com/OpenVoiceOS/ovos-config/pull/107) ([JarbasAl](https://github.com/JarbasAl)) -**Closed issues:** +## [V0.0.13a6](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a6) (2024-01-23) -- Lingua franca lang specific format module isn't loaded. [\#83](https://github.com/OpenVoiceOS/ovos-config/issues/83) -- Errors loading tts when mimic3-server is not installed [\#80](https://github.com/OpenVoiceOS/ovos-config/issues/80) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a5...V0.0.13a6) -## [V0.0.12a1](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.12a1) (2023-11-05) +**Merged pull requests:** -[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.11...V0.0.12a1) +- readd low adapt matches \(intent pipeline\) [\#101](https://github.com/OpenVoiceOS/ovos-config/pull/101) ([emphasize](https://github.com/emphasize)) + +## [V0.0.13a5](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a5) (2024-01-23) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a4...V0.0.13a5) + +**Implemented enhancements:** + +- Update mycroft.conf [\#95](https://github.com/OpenVoiceOS/ovos-config/pull/95) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.13a4](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a4) (2024-01-23) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a3...V0.0.13a4) + +## [V0.0.13a3](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a3) (2024-01-23) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a2...V0.0.13a3) + +**Implemented enhancements:** + +- default utterance plugins [\#99](https://github.com/OpenVoiceOS/ovos-config/pull/99) ([JarbasAl](https://github.com/JarbasAl)) + +**Merged pull requests:** + +- adjust adapt matcher pipeline defaults [\#100](https://github.com/OpenVoiceOS/ovos-config/pull/100) ([emphasize](https://github.com/emphasize)) + +## [V0.0.13a2](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a2) (2024-01-19) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.13a1...V0.0.13a2) + +**Implemented enhancements:** + +- update/stop\_pipeline [\#94](https://github.com/OpenVoiceOS/ovos-config/pull/94) ([JarbasAl](https://github.com/JarbasAl)) **Closed issues:** -- Invalid JSON Error [\#79](https://github.com/OpenVoiceOS/ovos-config/issues/79) +- Services don't start with malformed configuration [\#97](https://github.com/OpenVoiceOS/ovos-config/issues/97) + +## [V0.0.13a1](https://github.com/OpenVoiceOS/ovos-config/tree/V0.0.13a1) (2023-12-29) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-config/compare/V0.0.12...V0.0.13a1) **Merged pull requests:** -- removed deprecated mimic3 [\#81](https://github.com/OpenVoiceOS/ovos-config/pull/81) ([builderjer](https://github.com/builderjer)) +- document transformer plugins [\#93](https://github.com/OpenVoiceOS/ovos-config/pull/93) ([JarbasAl](https://github.com/JarbasAl)) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..617e3cd --- /dev/null +++ b/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2024 Casimiro Ferreira + + 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 + + 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. + diff --git a/ovos_config/__main__.py b/ovos_config/__main__.py index 19f2b3b..528053f 100644 --- a/ovos_config/__main__.py +++ b/ovos_config/__main__.py @@ -160,7 +160,7 @@ def show(user, system, remote, section, list_sections): # based on chosen configuration if name != "Joined": _sections = [k for k, v in config.items() if isinstance(v, dict)] - if len([k for k, v in config.items() if not isinstance(v, dict)]): + if [k for k, v in config.items() if not isinstance(v, dict)]: _sections.append("base") else: _sections = SECTIONS @@ -254,6 +254,7 @@ def set(key, value): ovos-config set -k blacklisted_skills -v myskill # Adds "myskill" as an blacklisted skill # Since this is a pretty specific key and a value is passed, the user won't be prompted """ + key = key.lstrip("/") tuples = list(walkDict(CONFIG, key, full_path=True)) values = [tup[1] for tup in tuples] paths = ["/".join(tup[0]) for tup in tuples] @@ -275,7 +276,7 @@ def set(key, value): console.print("User exit", style="red") exit() elif not paths: - console.print(f"[red]Error:[/red] No key that fits the query") + console.print("[red]Error:[/red] No key that fits the query") exit() else: choice = 0 @@ -292,6 +293,8 @@ def set(key, value): f"(type: [red]{selected_type}[/red]) ")) value = value.replace('"','').replace("'","").replace("`","") + local_conf = CONFIGS[2][1] + _value = None # type checking/casting try: if isinstance(selected_value, str): @@ -319,8 +322,7 @@ def set(key, value): except (TypeError, ValueError): console.print(f"[red]Error:[/red] The value passed can't be cast into {selected_type}") exit() - - local_conf = CONFIGS[2][1] + pathSet(local_conf, selected_path, _value) local_conf.store() diff --git a/ovos_config/config.py b/ovos_config/config.py index 4a82d8b..a6f3630 100644 --- a/ovos_config/config.py +++ b/ovos_config/config.py @@ -17,7 +17,8 @@ from typing import Optional from ovos_config.models import LocalConf, MycroftDefaultConfig, \ - MycroftSystemConfig, MycroftUserConfig, RemoteConf + OvosDistributionConfig, MycroftSystemConfig, MycroftUserConfig, \ + RemoteConf from ovos_config.locations import OLD_USER_CONFIG, get_xdg_config_save_path, \ get_xdg_config_locations from ovos_utils.file_utils import FileWatcher @@ -41,6 +42,7 @@ class Configuration(dict): __patch = LocalConf(None) # Patch config that skills can update to override config bus = None default = MycroftDefaultConfig() + distribution = OvosDistributionConfig() system = MycroftSystemConfig() remote = RemoteConf() # This includes both the user config and @@ -54,10 +56,6 @@ class Configuration(dict): _callbacks = [] def __init__(self): - # python does not support proper overloading - # when instantiation a Configuration object (new style) - # the get method is replaced for proper dict behaviour - self.get = self._real_get super().__init__(**self.load_all_configs()) # dict methods @@ -160,13 +158,14 @@ def reload(): @staticmethod def get_system_constraints() -> dict: """ - Get Configuration constraints. Constraints must come from SYSTEM config. + Get Configuration constraints. Constraints must come from DISTRIBUTION or SYSTEM config. If not defined, then load the DEFAULT constraints. These settings can not be set anywhere else! @return: dict of system configuration constraints """ - return Configuration.system.get("system") or \ + return Configuration.distribution.get("system") or \ + Configuration.system.get("system") or \ Configuration.default.get("system") or \ {} @@ -184,7 +183,7 @@ def load_all_configs(system_constraints: Optional[dict] = None) -> dict: skip_user = system_constraints.get("disable_user_config", False) skip_remote = system_constraints.get("disable_remote_config", False) - configs = [Configuration.default, Configuration.system] + configs = [Configuration.default, Configuration.distribution, Configuration.system] if not skip_remote: configs.insert(1, Configuration.remote) if not skip_user: @@ -275,7 +274,7 @@ def set_config_watcher(callback: Optional[callable] = None): Setup filewatcher to monitor for config file changes @param callback: optional method to call when configuration is changed """ - paths = [Configuration.system.path] + \ + paths = [Configuration.distribution.path, Configuration.system.path] + \ [c.path for c in Configuration.xdg_configs] if callback and callback not in Configuration._callbacks: Configuration._callbacks.append(callback) @@ -292,7 +291,8 @@ def _on_file_change(path: str): @param path: Configuration file path reporting a change """ # reload updated config - for cfg in Configuration.xdg_configs + [Configuration.system, + for cfg in Configuration.xdg_configs + [Configuration.distribution, + Configuration.system, Configuration.remote]: if cfg.path == path: old_cfg = hash(cfg) @@ -378,17 +378,6 @@ def patch_clear(message): Configuration.__patch = {} # Backwards compat methods - @staticmethod - def get(configs=None, cache=True, remote=True): - """DEPRECATED - use Configuration class instead""" - LOG.warning("Configuration.get() has been deprecated, use Configuration() instead") - # NOTE: this is only called if using the class directly - # if using an instance (dict object) self._real_get is called instead - return Configuration.load_config_stack(configs, cache, remote) - - def _real_get(self, key, default=None): - return self.__getitem__(key) or default - @staticmethod def clear_cache(message=None): """DEPRECATED - there is no cache anymore """ diff --git a/ovos_config/locations.py b/ovos_config/locations.py index fcfe712..6d0990e 100644 --- a/ovos_config/locations.py +++ b/ovos_config/locations.py @@ -55,8 +55,8 @@ def find_user_config(): if isfile(path): return path old, path = get_config_locations(default=False, web_cache=False, - system=False, old_user=True, - user=True) + distribution=False, system=False, + old_user=True, user=True) if isfile(path): return path if isfile(old): @@ -64,13 +64,15 @@ def find_user_config(): return path -def get_config_locations(default=True, web_cache=True, system=True, - old_user=True, user=True): +def get_config_locations(default=True, web_cache=True, distribution=True, + system=True, old_user=True, user=True): """return list of all possible config files paths sorted by priority taking into account ovos.conf""" locs = [] ovos_cfg = _ovos_config.get_ovos_config() if default: locs.append(ovos_cfg["default_config_path"]) + if distribution: + locs.append(f"/usr/share/{ovos_cfg['base_folder']}/{ovos_cfg['config_filename']}") if system: locs.append(f"/etc/{ovos_cfg['base_folder']}/{ovos_cfg['config_filename']}") if web_cache: @@ -104,6 +106,9 @@ def find_default_config(): DEFAULT_CONFIG = _ovos_config.get_ovos_config()['default_config_path'] +DISTRIBUTION_CONFIG = os.environ.get('OVOS_DISTRIBUTION_CONFIG', + f'/usr/share/{_ovos_config.get_xdg_base()}/' + f'{_ovos_config.get_config_filename()}') SYSTEM_CONFIG = os.environ.get('MYCROFT_SYSTEM_CONFIG', f'/etc/{_ovos_config.get_xdg_base()}/' f'{_ovos_config.get_config_filename()}') diff --git a/ovos_config/meta.py b/ovos_config/meta.py index 98be842..d6cb121 100644 --- a/ovos_config/meta.py +++ b/ovos_config/meta.py @@ -1,150 +1,46 @@ -"""This file will check a system level OpenVoiceOS specific config file - -The ovos config is json with comment support like the regular mycroft.conf - -Default locations tried by order until a file is found -- /etc/OpenVoiceOS/ovos.conf -- /etc/mycroft/ovos.conf - -XDG locations are then merged over the select default config (if found) - -Examples config: - -{ - // the "name of the core", - // eg, OVOS, Neon, Chatterbox... - // all XDG paths should respect this - // {xdg_path}/{base_folder}/some_resource - "base_folder": "OpenVoiceOS", - - // the filename of "mycroft.conf", - // eg, ovos.conf, chatterbox.conf, neon.conf... - // "mycroft.conf" paths are derived from this - // {xdg_path}/{base_folder}/{config_filename} - "config_filename": "mycroft.conf", - - // override the default.conf location, allows changing the default values - // eg, disable backend, disable skills, configure permissions - "default_config_path": "/etc/OpenVoiceOS/default_mycroft.conf", - - // this is intended for derivative products, if ovos is being imported - // from one of these modules then the values below will be used instead - // eg, mycroft/ovos/neon can coexist in the same machine - "module_overrides": { - "neon_core": { - "base_folder": "neon", - "config_filename": "neon.conf", - "default_config_path": "/opt/neon/neon.conf" - } - }, - // essentially aliases for the above, useful for microservice architectures - "submodule_mappings": { - "neon_speech": "neon_core", - "neon_audio": "neon_core", - "neon_enclosure": "neon_core" - } -} -""" -import os -from os.path import isfile, join, dirname +"""This file will check env vars and determine ovos config file locations -from json_database import JsonStorage +this info is used to determine the default XDG paths and default config file location -import ovos_config.locations as _oloc -from ovos_utils.json_helper import load_commented_json, merge_dict +OVOS_CONFIG_BASE_FOLDER - mycroft +OVOS_CONFIG_FILENAME - mycroft.conf +OVOS_DEFAULT_CONFIG - full path to default mycroft.conf +""" +import os +from os.path import dirname def get_ovos_config(): """ - Goes through all possible ovos.conf paths and loads them in order. Default - `base_folder` and `config_filename` are overridden by envvars - `OVOS_CONFIG_BASE_FOLDER` and `OVOS_CONFIG_FILENAME`, respectively. - Submodule overrides are applied to the final config if defined for the - calling module. - eg, if neon is calling this method then neon config overrides are loaded - + `base_folder`, `config_filename` and "default_config_path" are overridden by envvars + `OVOS_CONFIG_BASE_FOLDER`,`OVOS_CONFIG_FILENAME` and `OVOS_DEFAULT_CONFIG`, respectively. """ - from ovos_utils.system import is_running_from_module - - # populate default values - config = {"xdg": True, - "base_folder": os.environ.get("OVOS_CONFIG_BASE_FOLDER") or - "mycroft", - "config_filename": os.environ.get("OVOS_CONFIG_FILENAME") or - "mycroft.conf"} - try: - config["default_config_path"] = _oloc.find_default_config() - except FileNotFoundError: # not a mycroft device - config["default_config_path"] = join(dirname(__file__), "mycroft.conf") - - # load ovos.conf - for path in get_ovos_default_config_paths(): - try: - config = merge_dict(config, load_commented_json(path)) - except: - # tolerate bad json TODO proper exception (?) - pass - - # let's check for derivatives specific configs - # the assumption is that these cores are exclusive to each other, - # this will never find more than one override - # TODO this works if using dedicated .venvs what about system installs? - cores = config.get("module_overrides") or {} - for k in cores: - if is_running_from_module(k): - config = merge_dict(config, cores[k]) - break - else: - subcores = config.get("submodule_mappings") or {} - for k in subcores: - if is_running_from_module(k): - config = merge_dict(config, cores[subcores[k]]) - break - - return config + # let's check for os.env overrides, those take precedence over default values + return {"base_folder": os.environ.get("OVOS_CONFIG_BASE_FOLDER") or "mycroft", + "config_filename": os.environ.get("OVOS_CONFIG_FILENAME") or "mycroft.conf", + "default_config_path": os.environ.get("OVOS_DEFAULT_CONFIG") or f"{dirname(__file__)}/mycroft.conf"} def save_ovos_config(new_config): - """ update ovos.conf contents at ~/.config/OpenVoiceOS/ovos.conf """ - OVOS_CONFIG = join(_oloc.get_xdg_config_save_path("OpenVoiceOS"), - "ovos.conf") - cfg = JsonStorage(OVOS_CONFIG) - cfg.update(new_config) - cfg.store() - return cfg + """DEPRECATED - ovos.conf no longer used""" + from ovos_utils.log import LOG + LOG.warning("ovos.conf file has been deprecated! this method will be removed in next stable release") + return def get_ovos_default_config_paths(): - """ return a list of all existing ovos.conf file locations by order of precedence - - eg. ["/etc/OpenVoiceOS/ovos.conf", "/home/user/.config/OpenVoiceOS/ovos.conf"] - - """ + """DEPRECATED - ovos.conf no longer used""" from ovos_utils.log import LOG - - paths = [] - if isfile("/etc/OpenVoiceOS/ovos.conf"): - paths.append("/etc/OpenVoiceOS/ovos.conf") - elif isfile("/etc/mycroft/ovos.conf"): - LOG.warning("found /etc/mycroft/ovos.conf\n" - "This location has been DEPRECATED!\n" - "Please move your config to /etc/OpenVoiceOS/ovos.conf") - paths.append("/etc/mycroft/ovos.conf") - - # This includes both the user config and - # /etc/xdg/OpenVoiceOS/ovos.conf - for p in _oloc.get_xdg_config_dirs("OpenVoiceOS"): - if isfile(join(p, "ovos.conf")): - paths.append(join(p, "ovos.conf")) - - return paths + LOG.warning("ovos.conf file has been deprecated! this method will be removed in next stable release") + return [] def is_using_xdg(): - from ovos_utils.log import LOG - """ BACKWARDS COMPAT: logs warning and always returns True""" - LOG.warning("is_using_xdg has been deprecated! XDG specs are always honoured, this method will be removed in a future release") + from ovos_utils.log import LOG + LOG.warning( + "is_using_xdg has been deprecated! XDG specs are always honoured, " + "this method will be removed in next stable release") return True @@ -154,7 +50,6 @@ def get_xdg_base(): different derivative cores may change this folder, this value is derived from ovos.conf eg, "mycroft", "hivemind", "neon" .... """ - return get_ovos_config().get("base_folder") or "mycroft" @@ -167,9 +62,8 @@ def set_xdg_base(folder_name): NOTE: this value will be set globally, per core overrides in ovos.conf take precedence """ from ovos_utils.log import LOG - LOG.info(f"XDG base folder set to: '{folder_name}'") - save_ovos_config({"base_folder": folder_name}) + os.environ["OVOS_CONFIG_BASE_FOLDER"] = folder_name def set_config_filename(file_name, core_folder=None): @@ -185,7 +79,7 @@ def set_config_filename(file_name, core_folder=None): if core_folder: set_xdg_base(core_folder) LOG.info(f"config filename set to: '{file_name}'") - save_ovos_config({"config_filename": file_name}) + os.environ["OVOS_CONFIG_FILENAME"] = file_name def get_config_filename(): @@ -197,7 +91,7 @@ def get_config_filename(): return get_ovos_config().get("config_filename") or "mycroft.conf" -def set_default_config(file_path=None): +def set_default_config(file_path=f"{dirname(__file__)}/mycroft.conf"): """ full path to default config file to be used NOTE: this is a full path, not a directory! "config_filename" parameter is not used here @@ -206,7 +100,6 @@ def set_default_config(file_path=None): NOTE: this value will be set globally, per core overrides in ovos.conf take precedence """ from ovos_utils.log import LOG - - file_path = file_path or _oloc.find_default_config() + LOG.info(f"default config file changed to: {file_path}") - save_ovos_config({"default_config_path": file_path}) + os.environ["OVOS_DEFAULT_CONFIG"] = file_path diff --git a/ovos_config/models.py b/ovos_config/models.py index 10a0206..6d26b08 100644 --- a/ovos_config/models.py +++ b/ovos_config/models.py @@ -21,7 +21,7 @@ from ovos_utils.json_helper import load_commented_json, merge_dict from ovos_utils.log import LOG -from ovos_config.locations import USER_CONFIG, SYSTEM_CONFIG, WEB_CONFIG_CACHE, DEFAULT_CONFIG +from ovos_config.locations import USER_CONFIG, DISTRIBUTION_CONFIG, SYSTEM_CONFIG, WEB_CONFIG_CACHE, DEFAULT_CONFIG def is_remote_list(values): @@ -96,13 +96,13 @@ def load_local(self, path=None): """ path = path or self.path if not path: - LOG.error(f"in memory configuration, nothing to load") + LOG.error("in memory configuration, nothing to load") return if exists(path) and isfile(path): with self.__lock: try: if self._get_file_format(path) == "yaml": - with open(path) as f: + with open(path, encoding="utf-8") as f: config = yaml.safe_load(f) else: config = load_commented_json(path) @@ -120,7 +120,9 @@ def load_local(self, path=None): LOG.debug(f"Configuration '{path}' not defined, skipping") def reload(self): - if isfile(self.path) and self._last_loaded == getmtime(self.path): + if isfile(self.path) \ + and self._last_loaded \ + and self._last_loaded == getmtime(self.path): LOG.debug(f"{self.path} not changed since last load " f"(changed {time() - self._last_loaded} seconds ago)") return @@ -129,15 +131,15 @@ def reload(self): def store(self, path=None): path = path or self.path if not path: - LOG.error(f"in memory configuration, no save location") + LOG.error("in memory configuration, no save location") return with self.__lock: if self._get_file_format(path) == "yaml": - with open(path, 'w+') as f: + with open(path, 'w+', encoding="utf-8") as f: yaml.dump(dict(self), f, allow_unicode=True, default_flow_style=False, sort_keys=False) else: - with open(path, 'w+') as f: + with open(path, 'w+', encoding="utf-8") as f: json.dump(self, f, indent=2) def merge(self, conf): @@ -183,6 +185,11 @@ def set_root_config_path(self, root_config): self.reload() +class OvosDistributionConfig(ReadOnlyConfig): + def __init__(self, allow_overwrite=False): + super().__init__(DISTRIBUTION_CONFIG, allow_overwrite) + + class MycroftSystemConfig(ReadOnlyConfig): def __init__(self, allow_overwrite=False): super().__init__(SYSTEM_CONFIG, allow_overwrite) diff --git a/ovos_config/mycroft.conf b/ovos_config/mycroft.conf index 0980e35..d61e9c1 100644 --- a/ovos_config/mycroft.conf +++ b/ovos_config/mycroft.conf @@ -120,24 +120,112 @@ # internet_skills -> skills with internet requirements "ready_settings": ["skills"], + // To enable a utterance transformer plugin just add it's name with any relevant config + // these plugins can mutate the utterance between STT and the Intent stage + // they may also modify message.context with metadata + // plugins only load if they are installed and enabled in this section + "utterance_transformers": { + + "ovos-utterance-normalizer": {}, + + // cancel utterances mid command + "ovos-utterance-plugin-cancel": {}, + + // define utterance fixes via fuzzy match ~/.local/share/mycroft/corrections.json + // define unconditional replacements at word level ~/.local/share/mycroft/word_corrections.json + "ovos-utterance-corrections-plugin": {} + }, + + // To enable a metadata transformer plugin just add it's name with any relevant config + // these plugins can mutate the message.context between STT and the Intent stage + "metadata_transformers": {}, + // Intent Pipeline / plugins config "intents" : { + // the position in the pipeline where each engine matches can be configured in "pipeline" section below + + // adjust confidence thresholds for adapt pipeline + // adapt intents with conf lower than these values will be ignored + "adapt": { + "conf_high": 0.65, + "conf_med": 0.45, + "conf_low": 0.25 + }, + + // adjust confidence thresholds for padatious pipeline + // padatious/padacioso intents with conf lower than these values will be ignored + "padatious": { + "conf_high": 0.95, + "conf_med": 0.8, + "conf_low": 0.5, + + // path to save trained intent files + // by default uses XDG directories if not set + //"intent_cache": "~/.local/share/mycroft/intent_cache/", + + // set to false if multithreading is wanted + "single_thread": true + }, + + // Common Query gathers responses to questions from various skills and chooses the best answer + "common_query": { + // maximum seconds to wait for skill responses before giving up + "max_response_wait": 6, + // how much extra seconds to allow a skill to search if it requests so + "extension_time": 3, + // reranker plugins are responsible for selecting the best answer among skill responses in case of ties + // the default is a BM25 implementation from ovos-classifiers + "reranker": "ovos-choice-solver-bm25" + }, + + // OVOS Common Play - handle media requests + "OCP": { + // enable usage of a pretrained classifier for MediaType matching + // if disabled a simple .voc match is used + // NOTE: classifiers currently are english only + "experimental_media_classifier": false, + "experimental_binary_classifier": false, + // legacy forces old audio service instead of OCP + "legacy": false, + // min confidence (0.0 - 1.0) to accept MediaType + "classifier_threshold": 0.4, + // min conf for each result (0 - 100) + "min_score": 40, + // filter results from "wrong" MediaType + "filter_media": true, + // filter results we lack plugins to play + "filter_SEI": true, + // playback mode + // 0 - auto + // 10 - audio results only + // 20 - video results only + "playback_mode": 0, + // if MediaType query fails, try Generic query + "search_fallback": true + }, + // the pipeline is a ordered set of frameworks to send an utterance too // if one of the frameworks fails the next one is used, until an answer is found // NOTE: if padatious is not installed, it will be replaced with padacioso (much slower) // in the future these will become plugins, and new pipeline stages can be added by end users "pipeline": [ + "stop_high", "converse", + "ocp_high", "padatious_high", - "adapt", - "common_qa", + "adapt_high", + "ocp_medium", "fallback_high", + "stop_medium", + "adapt_medium", "padatious_medium", + "adapt_low", + "common_qa", "fallback_medium", - "padatious_low", "fallback_low" ] }, + // General skill values "skills": { @@ -164,15 +252,11 @@ "autogen_meta": false, // blacklisted skills to not load - // NB: This is the basename() of the directory where the skill lives, so if - // the skill you want to blacklist is in /usr/share/mycroft/skills/mycroft-alarm.mycroftai/ - // then you should write `["mycroft-alarm.mycroftai"]` below. - "blacklisted_skills": [], - - // priority skills to be loaded first - // DEPRECATED: specify skill loading requirements in individual skills instead - // This setting does not affect skills installed via setup.py - "priority_skills": [], + // NB: This is skill_id of the skill, usually defined in the skills setup.py + "blacklisted_skills": [ + // stop skill has been replaced with native core functionality + "skill-ovos-stop.openvoiceos" + ], // fallback skill configuration "fallbacks": { @@ -329,7 +413,7 @@ } }, - // The mycroft-core messagebus websocket + // The ovos-core messagebus websocket "websocket": { "host": "127.0.0.1", "port": 8181, @@ -367,6 +451,9 @@ "listener": { "sample_rate": 16000, + // mute global audio output volume while microphone is recording + "fake_barge_in": false, + // TODO - these names are confusing, update dinkum listener to give them more descriptive names // min speech seconds for audio to be considered speech "speech_begin": 0.3, @@ -379,12 +466,6 @@ // sound chunks sent to ww callback (eg, saving recordings) "wakeword_chunks_to_save": 15, - // if enabled the noise level is saved to a ipc file, useful for - // debuging if microphone is working but writes a lot to disk, - // recommended that you set "ipc_path" to a tmpfs - // DEPRECATED: used by old ovos-listener only - "mic_meter_ipc": false, - // Set 'save_path' to configure the location of files stored if // 'record_wake_words' and/or 'save_utterances' are set to 'true'. // WARNING: Make sure that user 'mycroft' has write-access on the @@ -412,6 +493,9 @@ "module": "ovos-microphone-plugin-alsa" }, + // if true, will remove silence from both ends of audio before sending it to STT + "remove_silence": true, + // Voice Activity Detection is used to determine when speech ended "VAD": { // silence method defined the main vad strategy @@ -440,7 +524,7 @@ "initial_energy_threshold": 1000.0, // vad module can be any plugin, by default it is not used // recommended plugin: "ovos-vad-plugin-silero" - "module": "ovos-vad-plugin-webrtcvad", + "module": "ovos-vad-plugin-silero", "ovos-vad-plugin-silero": {"threshold": 0.2}, "ovos-vad-plugin-webrtcvad": {"vad_mode": 3} }, @@ -459,12 +543,6 @@ // can disable this to listen all the time, allowing 'barge in' functionality. "mute_during_output" : false, - // How much (if at all) to 'duck' the speaker output during listening. A - // setting of 0.0 will not duck at all. A 1.0 will completely mute output - // while in a listening state. Values in between will lower the volume - // partially (this is optional behavior, depending on the enclosure). - "duck_while_listening" : 0.3, - // In milliseconds "phoneme_duration": 120, "multiplier": 1.0, @@ -483,7 +561,7 @@ // Skips all checks (eg. audio service confirmation) after the wake_word is recognized and // instantly continues to listen for a command - "instant_listen": false, + "instant_listen": true, // continuous listen is an experimental setting, it removes the need for // wake words and uses VAD only, a streaming STT is strongly recommended @@ -511,6 +589,7 @@ "listen": true, "fallback_ww": "hey_mycroft_precise" }, + // in case precise-lite is not installed, attempt to use classic precise "hey_mycroft_precise": { "module": "ovos-ww-plugin-precise", "version": "0.3", @@ -521,6 +600,7 @@ "listen": true, "fallback_ww": "hey_mycroft_vosk" }, + // in case classic precise is not installed, attempt to use vosk "hey_mycroft_vosk": { "module": "ovos-ww-plugin-vosk", "samples": ["hey mycroft", "hey microsoft", "hey mike roft", "hey minecraft"], @@ -528,6 +608,7 @@ "listen": true, "fallback_ww": "hey_mycroft_pocketsphinx" }, + // in case vosk is not installed, attempt to use pocketsphinx "hey_mycroft_pocketsphinx": { "module": "ovos-ww-plugin-pocketsphinx", "phonemes": "HH EY . M AY K R AO F T", @@ -535,39 +616,37 @@ "lang": "en-us", "listen": true }, + // default wakeup word to take ovos out of SLEEPING mode, "wake_up": { + "module": "ovos-ww-plugin-vosk", + "rule": "fuzzy", + "samples": ["wake up"], + "lang": "en-us", + // makes this a wakeup word for usage in SLEEPING mode + "wakeup": true, + "fallback_ww": "wake_up_pocketsphinx" + }, + // in case vosk plugin is not installed, attempt to use pocketsphinx + "wake_up_pocketsphinx": { "module": "ovos-ww-plugin-pocketsphinx", "phonemes": "W EY K . AH P", "threshold": 1e-20, "lang": "en-us", - // wakeupwords are only used in SLEEPING mode "wakeup": true } }, - // DEPRECATED: the concept of enclosure will no longer exist in ovos-core - // this has been replaced with PHAL, provides backwards compat for mycroft.client.enclosure module - "enclosure": { - // Platform name - // Override: SYSTEM (set by specific enclosures) - "platform": "PHAL", - - // The NTP sync should only forced on Raspberry Pi based devices. - "ntp_sync_on_boot": false - }, - "gui": { // Override: SYSTEM (set by specific enclosures) - // Uncomment or add "idle_display_skill" to set initial homescreen + // set skill_id of initial homescreen "idle_display_skill": "skill-ovos-homescreen.openvoiceos", - // Extensions provide additional GUI platform support for specific devices - // Currently supported devices: smartspeaker, bigscreen or generic + // GUI plugins / Extensions provide additional GUI platform support for specific devices "extension": "generic", // Generic extension can additionaly provide homescreen functionality - // homescreen support is disabled by default for generic extension "generic": { + // enable/disable homescreen "homescreen_supported": true } }, @@ -666,24 +745,43 @@ // Translation plugins "language": { - // default plugin comes bundled with ovos-classifiers - "detection_module": "ovos-lang-detect-ngram-lm", - // default uses public servers for nllb + //by default uses public servers for translation // https://github.com/OpenVoiceOS/ovos-translate-server - // https://github.com/OpenVoiceOS/ovos-translate-plugin-nllb + "detection_module": "ovos-lang-detector-plugin-server", "translation_module": "ovos-translate-plugin-server" }, - // Media playback + // placeholder to help in migration to ovos-media + // if set to False the legacy audio service won't load + "enable_old_audioservice": true, + "Audio": { // message.context may contains a source and destination // native audio (playback / TTS) will only be played if a // message destination is a native_source or if missing (considered a broadcast) "native_sources": ["debug_cli", "audio", "mycroft-gui"], + // default audio player to be used by old_audioservice + // needs to be set under "backends" section, if not installed the setting is ignored without errors + // DO NOT use "OCP", that is not a valid option and only located in "backends" for legacy reasons + "default-backend": "mpv", + "backends": { "OCP": { + // LEGACY CONFIG - OCP is in the process of being replaced by ovos-media + // if you are already using ovos-media this config does nothing "type": "ovos_common_play", + // define order of preference for playback plugins + "preferred_audio_services": ["mpv", "vlc", "simple"], + // allow OCP to be controlled via MPRIS + "disable_mpris": true, + // dbus type for MPRIS, "session" or "system" + "dbus_type": "session", + // if MPRIS is enabled above, also allow OCP to control MPRIS enabled 3rd party applications + // voice enables them (next/prev/stop/resume..) + // and stops them when OCP starts it's own playback + // NOTE: OCP can be controlled itself via MPRIS independentely of this setting + "manage_external_players": false, "active": true }, "simple": { @@ -692,14 +790,19 @@ }, "vlc": { "type": "ovos_vlc", - "active": true + "active": true, + // volume used during audio_ducking + "initial_volume": 100, + "low_volume": 50 + }, + "mpv": { + "type": "ovos_mpv", + "active": true, + // volume used during audio_ducking + "initial_volume": 100, + "low_volume": 50 } - }, - // DEPRECATED - this value is only used as a fallback when OCP is not installed - // OCP is a full fledged media player that handles everything from video to playlists - // it plugs into the audio service api to capture playback and provide backwards compat - // OCP will delegate to the audio backends when needed - "default-backend": "OCP" + } }, "debug": false diff --git a/ovos_config/utils.py b/ovos_config/utils.py index 1b7c6b9..a264392 100644 --- a/ovos_config/utils.py +++ b/ovos_config/utils.py @@ -65,8 +65,8 @@ def init_module_config(module_name: str, module_override: str, # Check for and update submodules if module_name == "__main__": - raise ValueError(f"Configuring `__main__` has unintended consequences" - f"and is not supported here") + raise ValueError("Configuring `__main__` has unintended consequences" + "and is not supported here") if module_name in ovos_conf['submodule_mappings']: LOG.debug(f"{module_name} already configured, skipping configuration") else: @@ -109,4 +109,3 @@ def init_module_config(module_name: str, module_override: str, importlib.reload(ovos_config.models) importlib.reload(ovos_config.config) importlib.reload(ovos_config) - diff --git a/ovos_config/version.py b/ovos_config/version.py index 4e8dfb1..cbb1e3f 100644 --- a/ovos_config/version.py +++ b/ovos_config/version.py @@ -1,6 +1,6 @@ # START_VERSION_BLOCK VERSION_MAJOR = 0 -VERSION_MINOR = 0 -VERSION_BUILD = 12 +VERSION_MINOR = 1 +VERSION_BUILD = 0 VERSION_ALPHA = 0 # END_VERSION_BLOCK diff --git a/requirements/extras.txt b/requirements/extras.txt index 0cee470..009ac69 100644 --- a/requirements/extras.txt +++ b/requirements/extras.txt @@ -1 +1 @@ -ovos_backend_client < 0.1.0 +ovos_backend_client < 0.2.0 diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 863f583..165f9fe 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,5 +1,5 @@ PyYAML>=5.4.0,<7.0.0 combo_lock~=0.2 -python-dateutil~=2.6 +python-dateutil~=2.9 ovos-utils >= 0.0.37 rich-click ~=1.6 diff --git a/requirements/tests.txt b/requirements/tests.txt index 206465c..74a681e 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -1,6 +1,6 @@ coveralls==1.8.2 flake8==3.7.9 -pytest==5.2.4 +pytest==8.2.2 pytest-cov==2.8.1 cov-core==1.15.0 sphinx==2.2.1 @@ -8,4 +8,4 @@ sphinx-rtd-theme==0.4.3 mock_msm~=0.9.2 ovos-stt-plugin-vosk>=0.1.3 python-vlc==1.1.2 -ovos-bus-client~=0.0.3 \ No newline at end of file +ovos-bus-client~=0.0.8 \ No newline at end of file diff --git a/test/unittests/test_configuration.py b/test/unittests/test_configuration.py index 59c3910..2927fa1 100644 --- a/test/unittests/test_configuration.py +++ b/test/unittests/test_configuration.py @@ -39,15 +39,6 @@ def tearDown(self): Configuration.load_config_stack([{}], True) Configuration._callbacks = [] - def test_get(self): - from ovos_config.config import Configuration - d1 = {'a': 1, 'b': {'c': 1, 'd': 2}} - d2 = {'b': {'d': 'changed'}} - d = Configuration.get([d1, d2]) - self.assertEqual(d['a'], d1['a']) - self.assertEqual(d['b']['d'], d2['b']['d']) - self.assertEqual(d['b']['c'], d1['b']['c']) - @patch('mycroft.api.DeviceApi') @skip("requires backend to be enabled, TODO refactor test!") def test_remote(self, mock_api): diff --git a/test/unittests/test_locations.py b/test/unittests/test_locations.py index 9a23c1a..14bb450 100644 --- a/test/unittests/test_locations.py +++ b/test/unittests/test_locations.py @@ -55,21 +55,22 @@ def test_get_config_locations(self, config_path, webcache_loc, webcache_loc.return_value = "webcache" from ovos_config.locations import get_config_locations self.assertEqual(get_config_locations(False, False, False, - False, False), list()) + False, False, False + ), list()) self.assertEqual(get_config_locations(), - ['/test/default.yml', '/etc/test/test.yaml', - 'webcache', '~/.test/test.yaml', 'config/test.yaml']) + ['/test/default.yml', '/usr/share/test/test.yaml', + '/etc/test/test.yaml', 'webcache', + '~/.test/test.yaml', 'config/test.yaml']) @mock.patch("ovos_config.meta.get_config_filename") @mock.patch("ovos_config.meta.get_xdg_base") - @mock.patch("ovos_utils.system.is_running_from_module") @mock.patch("os.path.isfile") - def test_globals(self, fcheck, mod_check, xdg_base, config_filename): + def test_globals(self, fcheck, xdg_base, config_filename): fcheck.return_value = True xdg_base.return_value = "test" config_filename.return_value = "test.yaml" - mod_check.return_value = False + os.environ["OVOS_DISTRIBUTION_CONFIG"] = "mycroft/distribution/config" os.environ["MYCROFT_SYSTEM_CONFIG"] = "mycroft/system/config" os.environ["MYCROFT_WEB_CACHE"] = "mycroft/web/config" @@ -86,9 +87,11 @@ def test_globals(self, fcheck, mod_check, xdg_base, config_filename): importlib.reload(ovos_config.meta) # Test all config paths respect environment overrides/configured values - from ovos_config.locations import DEFAULT_CONFIG, SYSTEM_CONFIG, \ - OLD_USER_CONFIG, USER_CONFIG, REMOTE_CONFIG, WEB_CONFIG_CACHE + from ovos_config.locations import DEFAULT_CONFIG, DISTRIBUTION_CONFIG, \ + SYSTEM_CONFIG, OLD_USER_CONFIG, USER_CONFIG, REMOTE_CONFIG, \ + WEB_CONFIG_CACHE + self.assertEqual(DISTRIBUTION_CONFIG, "mycroft/distribution/config") self.assertEqual(SYSTEM_CONFIG, "mycroft/system/config") self.assertEqual(OLD_USER_CONFIG, expanduser("~/.test/test.yaml")) @@ -97,12 +100,14 @@ def test_globals(self, fcheck, mod_check, xdg_base, config_filename): self.assertEqual(REMOTE_CONFIG, "mycroft.ai") self.assertEqual(WEB_CONFIG_CACHE, "mycroft/web/config") - # Override module check and reload to test default config override - mod_check.return_value = True + + # test default config override + self.assertTrue(DEFAULT_CONFIG != "/tmp/test.yaml") + os.environ["OVOS_DEFAULT_CONFIG"] = "/tmp/test.yaml" importlib.reload(ovos_config.locations) importlib.reload(ovos_config.models) importlib.reload(ovos_config.config) - # Ensure default path is read from ovos.conf + # Ensure default path is read from env var from ovos_config.locations import DEFAULT_CONFIG self.assertEqual(DEFAULT_CONFIG, "/tmp/test.yaml") # Ensure default config values are present in Configuration object diff --git a/test/unittests/test_utils.py b/test/unittests/test_utils.py deleted file mode 100644 index 8f4759b..0000000 --- a/test/unittests/test_utils.py +++ /dev/null @@ -1,127 +0,0 @@ -import os -import shutil -import json -import importlib -from copy import deepcopy -from os.path import dirname, join, isfile - -from unittest import TestCase - - -_DEFAULT_CONFIG_PATH = join(dirname(__file__), "mycroft.conf") -_TEST_CONFIG_OVERRIDE = {"base_folder": "neon", - "config_filename": "neon.yaml", - "default_config_path": _DEFAULT_CONFIG_PATH} - - -class TestUtils(TestCase): - def test_init_ovos_conf(self): - test_config_dir = join(dirname(__file__), "test_init_config") - from ovos_config.utils import init_module_config - os.environ["XDG_CONFIG_HOME"] = test_config_dir - - if isfile(join(test_config_dir, "OpenVoiceOS", "ovos.conf")): - os.remove(join(test_config_dir, "OpenVoiceOS", "ovos.conf")) - - # Init 'test_module' to use 'neon_core' config - init_module_config("test_module", "neon", _TEST_CONFIG_OVERRIDE) - - with open(join(test_config_dir, "OpenVoiceOS", "ovos.conf")) as f: - config = json.load(f) - - # Patch local tests - - self.assertEqual(config, {"module_overrides": { - "neon": { - "base_folder": "neon", - "config_filename": "neon.yaml", - "default_config_path": _DEFAULT_CONFIG_PATH - } - }, - "submodule_mappings": { - "test_module": "neon" - }}) - - # init same module again, config should be unchanged - init_module_config("test_module", "neon", _TEST_CONFIG_OVERRIDE) - with open(join(test_config_dir, "OpenVoiceOS", "ovos.conf")) as f: - config2 = json.load(f) - # Patch local tests - config2['module_overrides']['neon'].setdefault( - 'default_config_path', "") - self.assertEqual(config, config2) - - # init another different module - init_module_config("other_test_module", "neon", _TEST_CONFIG_OVERRIDE) - with open(join(test_config_dir, "OpenVoiceOS", "ovos.conf")) as f: - config3 = json.load(f) - - self.assertEqual(config3, {"module_overrides": { - "neon": { - "base_folder": "neon", - "config_filename": "neon.yaml", - "default_config_path": _DEFAULT_CONFIG_PATH - } - }, - "submodule_mappings": { - "test_module": "neon", - "other_test_module": "neon" - }}) - - # init neon_core - init_module_config("neon_core", "neon", _TEST_CONFIG_OVERRIDE) - with open(join(test_config_dir, "OpenVoiceOS", "ovos.conf")) as f: - config4 = json.load(f) - # Patch local tests - config4['module_overrides']['neon'].setdefault( - 'default_config_path', "") - self.assertEqual(config4, {"module_overrides": { - "neon": { - "base_folder": "neon", - "config_filename": "neon.yaml", - "default_config_path": _DEFAULT_CONFIG_PATH - } - }, - "submodule_mappings": { - "test_module": "neon", - "other_test_module": "neon", - "neon_core": "neon" - }}) - - # Override default config with test file - import inspect - import ovos_config.models - import ovos_config.config - from ovos_config.meta import get_ovos_config - - ovos_config.DEFAULT_CONFIG = join(dirname(__file__), "mycroft" - "configuration", "mycroft.conf") - old_value = deepcopy(ovos_config.DEFAULT_CONFIG) - - # Init config and validate other config file is loaded - stack = inspect.stack() - mod = inspect.getmodule(stack[1][0]) - this_modname = mod.__name__.split('.')[0] - init_module_config(this_modname, "neon", _TEST_CONFIG_OVERRIDE) - self.assertNotEqual(old_value, ovos_config.DEFAULT_CONFIG) - self.assertEqual(ovos_config.models.DEFAULT_CONFIG, - ovos_config.DEFAULT_CONFIG) - self.assertEqual(ovos_config.config.Configuration.default.path, - ovos_config.DEFAULT_CONFIG) - - # Test default config - self.assertTrue(ovos_config.config.Configuration()['default_config']) - self.assertEqual(get_ovos_config()['default_config_path'], - _DEFAULT_CONFIG_PATH) - - # Test module imports - self.assertEqual(ovos_config.Configuration, - ovos_config.config.Configuration) - - # Cleanup configuration and force reload of pre-test defaults - os.environ.pop("XDG_CONFIG_HOME") - shutil.rmtree(test_config_dir) - del ovos_config.config.Configuration - importlib.reload(ovos_config.locations) - importlib.reload(ovos_config.models) - importlib.reload(ovos_config.config)