diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml new file mode 100644 index 0000000..65ee102 --- /dev/null +++ b/.github/workflows/publish_release.yml @@ -0,0 +1,40 @@ +# This workflow will generate a release distribution and upload it to PyPI + +name: Publish Build and GitHub Release +on: + push: + branches: + - master + +jobs: + tag_release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Get Version + run: | + VERSION=$(python setup.py --version) + echo "VERSION=${VERSION}" >> $GITHUB_ENV + - uses: ncipollo/release-action@v1 + with: + token: ${{secrets.GITHUB_TOKEN}} + tag: ${{env.VERSION}} + build_and_publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v1 + with: + python-version: 3.8 + - name: Install Build Tools + run: | + python -m pip install build wheel + + - name: Build Distribution Packages + run: | + python setup.py bdist_wheel + - name: Publish to Test PyPI + uses: pypa/gh-action-pypi-publish@master + with: + password: ${{secrets.PYPI_TOKEN}} \ No newline at end of file diff --git a/.github/workflows/publish_test_build.yml b/.github/workflows/publish_test_build.yml new file mode 100644 index 0000000..33c3b4c --- /dev/null +++ b/.github/workflows/publish_test_build.yml @@ -0,0 +1,39 @@ +# This workflow will generate a distribution and upload it to PyPI + +name: Publish Alpha Build +on: + push: + branches: + - dev + paths-ignore: + - 'version.py' + +jobs: + build_and_publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + - name: Setup Python + uses: actions/setup-python@v1 + with: + python-version: 3.8 + - name: Install Build Tools + run: | + python -m pip install build wheel + - name: Increment Version + run: | + VER=$(python setup.py --version) + python version_bump.py + - name: Push Version Change + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: Increment Version + - name: Build Distribution Packages + run: | + python setup.py bdist_wheel + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@master + with: + password: ${{secrets.PYPI_TOKEN}} \ No newline at end of file diff --git a/.github/workflows/pull_master.yml b/.github/workflows/pull_master.yml new file mode 100644 index 0000000..8e9c5a8 --- /dev/null +++ b/.github/workflows/pull_master.yml @@ -0,0 +1,21 @@ +# This workflow will generate a PR for changes in cert into master + +name: Pull to Master +on: + push: + branches: + - dev + workflow_dispatch: + +jobs: + pull_changes: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: pull-request-action + uses: repo-sync/pull-request@v2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + pr_reviewer: 'neonreviewers' + pr_assignee: 'neondaniel' + pr_draft: true \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..525bb37 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# NEON AI (TM) SOFTWARE, Software Development Kit & Application Development System +# All trademark and other rights reserved by their respective owners +# Copyright 2008-2021 Neongecko.com Inc. +# BSD-3 License + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..fa8e145 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# Neon Iris +Neon Iris (Interactive Relay for Intelligence Systems) provides tools for +interacting with Neon systems remotely, via [MQ](https://github.com/NeonGeckoCom/chat_api_mq_proxy). + +Install the Iris Python package with: `pip install neon-iris` +The `iris` entrypoint is available to interact with a bus via CLI. Help is available via `iris --help`. diff --git a/neon_iris/__init__.py b/neon_iris/__init__.py new file mode 100644 index 0000000..d782cbb --- /dev/null +++ b/neon_iris/__init__.py @@ -0,0 +1,25 @@ +# NEON AI (TM) SOFTWARE, Software Development Kit & Application Development System +# All trademark and other rights reserved by their respective owners +# Copyright 2008-2021 Neongecko.com Inc. +# BSD-3 +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/neon_iris/cli.py b/neon_iris/cli.py new file mode 100644 index 0000000..5684f60 --- /dev/null +++ b/neon_iris/cli.py @@ -0,0 +1,100 @@ +# NEON AI (TM) SOFTWARE, Software Development Kit & Application Development System +# All trademark and other rights reserved by their respective owners +# Copyright 2008-2021 Neongecko.com Inc. +# BSD-3 +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import json +from time import sleep + +import click + +from click_default_group import DefaultGroup + +from neon_iris.client import NeonAIClient +from neon_iris.version import __version__ + + +@click.group("iris", cls=DefaultGroup, + no_args_is_help=True, invoke_without_command=True, + help="Iris: Interactive Relay for Intelligence Systems.\n\n" + "See also: mana COMMAND --help") +@click.option("--version", "-v", is_flag=True, required=False, + help="Print the current version") +def neon_iris_cli(version: bool = False): + if version: + click.echo(f"Iris version {__version__}") + + +@neon_iris_cli.command(help="Create an MQ client session") +@click.option('--mq_config', '-m', + help="Path to MQ Config file") +@click.option('--user-config', '-u', + help="Path to User Config file") +@click.option('--lang', '-l', default="en-us", + help="Language to accept input in") +@click.option('--audio', '-a', is_flag=True, default=False, + help="Flag to enable audio playback") +def start_client(mq_config, user_config, lang, audio): + if mq_config: + with open(mq_config) as f: + try: + mq_config = json.load(f) + except Exception as e: + mq_config = None + if user_config: + with open(user_config) as f: + try: + user_config = json.load(f) + except Exception as e: + user_config = None + client = NeonAIClient(mq_config, user_config) + client.audio_enabled = audio + click.echo("Enter '!{lang}' to change language\n" + "Enter '!quit' to quit.\n" + "Enter '!mute' or '!unmute' to change audio playback") + while True: + query = click.prompt("Query") + if query.startswith('!'): + if query == "!quit": + break + elif query == "!mute": + click.echo("Disabling Audio Playback") + client.audio_enabled = False + elif query == "!unmute": + click.echo("Enabling Audio Playback") + client.audio_enabled = True + else: + lang = query.split()[0].strip('!') + client.user_profiles[0]["speech"]["secondary_tts_language"] = lang + click.echo(f"Language set to {lang}") + else: + client.send_request(query, lang) + # Pad prompt for multiple responses + sleep(1) + click.echo("Shutting Down Client") + client.shutdown() + + +if __name__ == "__main__": + start_client(None, None, "en-us") diff --git a/neon_iris/client.py b/neon_iris/client.py new file mode 100644 index 0000000..2945be0 --- /dev/null +++ b/neon_iris/client.py @@ -0,0 +1,165 @@ +# NEON AI (TM) SOFTWARE, Software Development Kit & Application Development System +# All trademark and other rights reserved by their respective owners +# Copyright 2008-2021 Neongecko.com Inc. +# BSD-3 +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import json +import subprocess + +from os import makedirs +from os.path import join, isfile +from pprint import pformat +from queue import Queue +from tempfile import gettempdir +from threading import Event, Thread +from time import time +from uuid import uuid4 + +from mycroft_bus_client import Message +from pika.exceptions import StreamLostError + +from neon_utils.configuration_utils import get_neon_user_config, get_neon_local_config +from neon_utils.mq_utils import NeonMQHandler +from neon_utils.socket_utils import b64_to_dict +from neon_utils.file_utils import decode_base64_string_to_file + + +class NeonAIClient: + def __init__(self, mq_config: dict = None, user_config: dict = None): + self._uid = str(uuid4()) + self._vhost = "/neon_chat_api" + self._client = "mq_api" + self.client_name = "tester" + self._config = mq_config or get_neon_local_config().content.get("MQ") + self._connection = self._init_mq_connection() + self._request_queue = Queue() + self._response_event = Event() + user_config = user_config or \ + json.loads(json.dumps(get_neon_user_config().content)) + self.user_profiles = [user_config] + self.username = user_config["user"]["username"] + self.audio_cache_dir = join(gettempdir(), "neon_iris") + self.audio_enabled = True + makedirs(self.audio_cache_dir, exist_ok=True) + + Thread(target=self._handle_next_request, daemon=True).start() + + @property + def uid(self): + return self._uid + + def shutdown(self): + self._request_queue.put(None) + self._connection.stop() + + def _play_audio(self, audio_file: str): + playback_cmd = "mpg123" if audio_file.endswith(".mp3") else "paplay" + subprocess.Popen([playback_cmd, audio_file], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL).wait() + + def handle_neon_response(self, channel, method, _, body): + channel.basic_ack(delivery_tag=method.delivery_tag) + response = b64_to_dict(body) + if response["msg_type"] == "klat.response": + resp_data = response["data"]["responses"] + files = [] + sentences = [] + for lang, response in resp_data.items(): + sentences.append(response.get("sentence")) + if response.get("audio"): + for gender, data in response["audio"].items(): + filepath = "/".join([self.audio_cache_dir] + + response[gender].split('/')[-4:]) + files.append(filepath) + if not isfile(filepath): + decode_base64_string_to_file(data, filepath) + print(f"{pformat(sentences)}\n{pformat(files)}\n") + if self.audio_enabled: + for file in files: + self._play_audio(file) + else: + print(f"Response: {response['data']}\n") + self._response_event.set() + + def _handle_next_request(self): + while True: + request = self._request_queue.get() + if not request: + break + utterance, lang = request + self._response_event.clear() + self._send_request(utterance, lang) + self._response_event.wait(30) + + def send_request(self, utterance: str, lang: str = "en-us"): + self._response_event.clear() + self._request_queue.put((utterance, lang)) + if not self._response_event.wait(30): + print(f"No repsonse to: {utterance}") + while not self._request_queue.empty(): + self._response_event.wait(30) + + def _send_request(self, utterance: str, lang: str): + message = self._build_message(utterance, lang) + serialized = {"msg_type": message.msg_type, + "data": message.data, + "context": message.context} + try: + self._connection.emit_mq_message( + self._connection.connection, + queue="neon_chat_api_request", + request_data=serialized) + except StreamLostError: + print("Connection closed, attempting to re-establish") + if self._connection.connection.is_open: + self._connection.connection.close() + self._connection = self._init_mq_connection() + print("Reconnected, retrying request") + self._request_queue.put((utterance, lang)) + except Exception as e: + print(e) + self.shutdown() + + def _build_message(self, utterance: str, + lang: str = "en-us", + ident: str = None): + return Message("recognizer_loop:utterance", + {"utterances": [utterance], + "lang": lang}, + {"client_name": self.client_name, + "client": self._client, + "ident": ident or str(time()), + "username": self.username, + "user_profiles": self.user_profiles, + "klat": {"routing_key": self.uid} + }) + + def _init_mq_connection(self): + mq_connection = NeonMQHandler(self._config, "mq_handler", self._vhost) + mq_connection.register_consumer("neon_response_handler", self._vhost, + self.uid, self.handle_neon_response, + auto_ack=False) + mq_connection.run_consumers(daemon=True) + return mq_connection diff --git a/neon_iris/version.py b/neon_iris/version.py new file mode 100644 index 0000000..ef7228e --- /dev/null +++ b/neon_iris/version.py @@ -0,0 +1,29 @@ +# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework +# All trademark and other rights reserved by their respective owners +# Copyright 2008-2022 Neongecko.com Inc. +# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds, +# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo +# BSD-3 License +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +__version__ = "0.0.1" diff --git a/requirements/requirements.txt b/requirements/requirements.txt new file mode 100644 index 0000000..f944e5c --- /dev/null +++ b/requirements/requirements.txt @@ -0,0 +1,3 @@ +click~=8.0 +click-default-group~=1.2 +neon_utils~=0.15 \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..540638d --- /dev/null +++ b/setup.py @@ -0,0 +1,74 @@ +# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework +# All trademark and other rights reserved by their respective owners +# Copyright 2008-2022 Neongecko.com Inc. +# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds, +# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo +# BSD-3 License +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import setuptools + +from os import path + + +def get_requirements(requirements_filename: str): + requirements_file = path.join(path.abspath(path.dirname(__file__)), "requirements", requirements_filename) + with open(requirements_file, 'r', encoding='utf-8') as r: + requirements = r.readlines() + requirements = [r.strip() for r in requirements if r.strip() and not r.strip().startswith("#")] + return requirements + + +with open("README.md", "r") as f: + long_description = f.read() + +with open("neon_iris/version.py", "r", encoding="utf-8") as v: + for line in v.readlines(): + if line.startswith("__version__"): + if '"' in line: + version = line.split('"')[1] + else: + version = line.split("'")[1] + +setuptools.setup( + name="neon-iris", + version=version, + author='Neongecko', + author_email='developers@neon.ai', + license='BSD-3-Clause', + description="Interactive Relay for Intelligence Systems", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://github.com/neongeckocom/neon-iris", + packages=setuptools.find_packages(), + include_package_data=True, + classifiers=[ + "Programming Language :: Python :: 3", + "Operating System :: OS Independent" + ], + python_requires='>=3.6', + install_requires=get_requirements("requirements.txt"), + entry_points={ + 'console_scripts': ['iris=neon_iris.cli:neon_iris_cli'] + } +) diff --git a/version_bump.py b/version_bump.py new file mode 100644 index 0000000..1449fbc --- /dev/null +++ b/version_bump.py @@ -0,0 +1,56 @@ +# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework +# All trademark and other rights reserved by their respective owners +# Copyright 2008-2022 Neongecko.com Inc. +# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds, +# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo +# BSD-3 License +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import fileinput +from os.path import join, dirname + +with open(join(dirname(__file__), "neon_mana_utils", "version.py"), + "r", encoding="utf-8") as v: + for line in v.readlines(): + if line.startswith("__version__"): + if '"' in line: + version = line.split('"')[1] + else: + version = line.split("'")[1] + +if "a" not in version: + parts = version.split('.') + parts[-1] = str(int(parts[-1]) + 1) + version = '.'.join(parts) + version = f"{version}a0" +else: + post = version.split("a")[1] + new_post = int(post) + 1 + version = version.replace(f"a{post}", f"a{new_post}") + +for line in fileinput.input(join(dirname(__file__), "neon_mana_utils", + "version.py"), inplace=True): + if line.startswith("__version__"): + print(f"__version__ = \"{version}\"") + else: + print(line.rstrip('\n'))