Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/build-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: Build Tests

on:
pull_request:
branches: [dev, master]
workflow_dispatch:

jobs:
build:
uses: OpenVoiceOS/gh-automations/.github/workflows/build-tests.yml@dev
with:
python_versions: '["3.10", "3.11", "3.12", "3.13", "3.14"]'
install_extras: 'test'
test_path: 'test'
77 changes: 14 additions & 63 deletions .github/workflows/publish_stable.yml
Original file line number Diff line number Diff line change
@@ -1,72 +1,23 @@
name: Stable Release
name: Publish Stable Release

on:
workflow_dispatch:
push:
branches: [master]
workflow_dispatch:

permissions:
contents: write

jobs:
publish_stable:
uses: TigreGotico/gh-automations/.github/workflows/publish-stable.yml@master
secrets: inherit
if: github.actor != 'github-actions[bot]'
uses: OpenVoiceOS/gh-automations/.github/workflows/publish-stable.yml@dev
secrets:
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
MATRIX_TOKEN: ${{ secrets.MATRIX_TOKEN }}
with:
branch: 'master'
version_file: 'ovos_solver_rivescript_plugin/version.py'
setup_py: 'setup.py'
publish_pypi: true
publish_release: true

publish_pypi:
needs: publish_stable
if: success() # Ensure this job only runs if the previous job succeeds
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: dev
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
- name: Setup Python
uses: actions/setup-python@v1
with:
python-version: "3.11"
- name: Install Build Tools
run: |
python -m pip install build wheel
- name: version
run: echo "::set-output name=version::$(python setup.py --version)"
id: version
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: V${{ steps.version.outputs.version }}
release_name: Release ${{ steps.version.outputs.version }}
body: |
Changes in this Release
${{ steps.changelog.outputs.changelog }}
draft: false
prerelease: true
commitish: dev
- name: Build Distribution Packages
run: |
python setup.py sdist bdist_wheel
- name: Publish to Test PyPI
uses: pypa/gh-action-pypi-publish@master
with:
password: ${{secrets.PYPI_TOKEN}}


sync_dev:
needs: publish_stable
if: success() # Ensure this job only runs if the previous job succeeds
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
ref: master
- name: Push master -> dev
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: dev
sync_dev: true
notify_matrix: true
98 changes: 6 additions & 92 deletions .github/workflows/release_workflow.yml
Original file line number Diff line number Diff line change
@@ -1,108 +1,22 @@
name: Release Alpha and Propose Stable

on:
workflow_dispatch:
pull_request:
types: [closed]
branches: [dev]

jobs:
publish_alpha:
if: github.event.pull_request.merged == true
uses: TigreGotico/gh-automations/.github/workflows/publish-alpha.yml@master
if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
uses: OpenVoiceOS/gh-automations/.github/workflows/publish-alpha.yml@dev
secrets: inherit
with:
branch: 'dev'
version_file: 'ovos_solver_rivescript_plugin/version.py'
setup_py: 'setup.py'
update_changelog: true
publish_prerelease: true
propose_release: true
changelog_max_issues: 100

notify:
if: github.event.pull_request.merged == true
needs: publish_alpha
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Send message to Matrix bots channel
id: matrix-chat-message
uses: fadenb/matrix-chat-message@v0.0.6
with:
homeserver: 'matrix.org'
token: ${{ secrets.MATRIX_TOKEN }}
channel: '!WjxEKjjINpyBRPFgxl:krbel.duckdns.org'
message: |
new ${{ github.event.repository.name }} PR merged! https://github.com/${{ github.repository }}/pull/${{ github.event.number }}

publish_pypi:
needs: publish_alpha
if: success() # Ensure this job only runs if the previous job succeeds
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: dev
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
- name: Setup Python
uses: actions/setup-python@v1
with:
python-version: "3.11"
- name: Install Build Tools
run: |
python -m pip install build wheel
- name: version
run: echo "::set-output name=version::$(python setup.py --version)"
id: version
- name: Build Distribution Packages
run: |
python setup.py sdist bdist_wheel
- name: Publish to Test PyPI
uses: pypa/gh-action-pypi-publish@master
with:
password: ${{secrets.PYPI_TOKEN}}


propose_release:
needs: publish_alpha
if: success() # Ensure this job only runs if the previous job succeeds
runs-on: ubuntu-latest
steps:
- name: Checkout dev branch
uses: actions/checkout@v3
with:
ref: dev

- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.10'

- name: Get version from setup.py
id: get_version
run: |
VERSION=$(python setup.py --version)
echo "VERSION=$VERSION" >> $GITHUB_ENV

- name: Create and push new branch
run: |
git checkout -b release-${{ env.VERSION }}
git push origin release-${{ env.VERSION }}

- name: Open Pull Request from dev to master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Variables
BRANCH_NAME="release-${{ env.VERSION }}"
BASE_BRANCH="master"
HEAD_BRANCH="release-${{ env.VERSION }}"
PR_TITLE="Release ${{ env.VERSION }}"
PR_BODY="Human review requested!"

# Create a PR using GitHub API
curl -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: token $GITHUB_TOKEN" \
-d "{\"title\":\"$PR_TITLE\",\"body\":\"$PR_BODY\",\"head\":\"$HEAD_BRANCH\",\"base\":\"$BASE_BRANCH\"}" \
https://api.github.com/repos/${{ github.repository }}/pulls

publish_pypi: true
notify_matrix: true
50 changes: 47 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,56 @@
# Changelog

## [0.0.1a1](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/tree/0.0.1a1) (2025-06-08)
## [0.1.0a2](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/tree/0.1.0a2) (2026-08-14)

[Full Changelog](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/compare/0.0.0...0.0.1a1)
[Full Changelog](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/compare/0.0.2a5...0.1.0a2)

**Merged pull requests:**

- fix: compatibility with ovos-plugin-manager 1.X.X [\#1](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/pull/1) ([JarbasAl](https://github.com/JarbasAl))
- Migrate to pyproject.toml and register as ChatEngine \(opm.agents.chat\) [\#18](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/pull/18) ([JarbasAl](https://github.com/JarbasAl))

## [0.0.2a5](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/tree/0.0.2a5) (2026-08-02)

[Full Changelog](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/compare/0.0.2a4...0.0.2a5)

**Merged pull requests:**

- ci: migrate release workflow to shared OpenVoiceOS automations [\#16](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/pull/16) ([JarbasAl](https://github.com/JarbasAl))

## [0.0.2a4](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/tree/0.0.2a4) (2026-08-01)

[Full Changelog](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/compare/0.0.2a3...0.0.2a4)

**Merged pull requests:**

- docs: rewrite README in Simplified Technical English [\#15](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/pull/15) ([JarbasAl](https://github.com/JarbasAl))

## [0.0.2a3](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/tree/0.0.2a3) (2025-12-19)

[Full Changelog](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/compare/0.0.2a2...0.0.2a3)

**Merged pull requests:**

- chore\(deps\): update dependency python to 3.14 [\#6](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/pull/6) ([renovate[bot]](https://github.com/apps/renovate))

## [0.0.2a2](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/tree/0.0.2a2) (2025-12-18)

[Full Changelog](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/compare/0.0.2a1...0.0.2a2)

**Merged pull requests:**

- chore: Configure Renovate [\#5](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/pull/5) ([renovate[bot]](https://github.com/apps/renovate))

## [0.0.2a1](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/tree/0.0.2a1) (2025-11-22)

[Full Changelog](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/compare/V0.0.1...0.0.2a1)

**Merged pull requests:**

- Update requirements.txt [\#3](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/pull/3) ([JarbasAl](https://github.com/JarbasAl))

## [V0.0.1](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/tree/V0.0.1) (2025-06-08)

[Full Changelog](https://github.com/OpenVoiceOS/ovos-solver-plugin-rivescript/compare/0.0.1...V0.0.1)



Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
# <img src='https://raw.githack.com/FortAwesome/Font-Awesome/master/svgs/solid/robot.svg' card_color='#40DBB0' width='50' height='50' style='vertical-align:bottom'/> Rivescript Chatbot

Give Mycroft some sass with Rivescript!

Leverages the [Alice chatbot](https://www.chatbots.org/chatbot/a.l.i.c.e/) to create some fun interactions. Phrases not explicitly handled by other skills will be run by the chatbot, so nearly every interaction will have _some_ response. But be warned, Mycroft might become a bit obnoxious...
This plugin is a question solver that answers with a [Rivescript](https://www.rivescript.com/) chatbot. It uses the [Alice chatbot](https://www.chatbots.org/chatbot/a.l.i.c.e/) brain to answer phrases that no other skill handles, so almost every input gets some response. Answers can be casual and a bit sassy.

## Examples

## Examples
* "Do you like ice cream"
* "Do you like dogs"
* "I have a jump rope"


## Usage

Spoken answers api with a Rivescript backend
The plugin exposes a spoken-answers API with a Rivescript backend.

```python
from ovos_solver_rivescript_plugin import RivescriptSolver
Expand All @@ -26,3 +24,8 @@ sentence = d.spoken_answer("Do you like ice cream", {"lang": "pt-pt"})
print(sentence)
# O que queres mesmo saber?
```

## Related projects

* [OpenVoiceOS/ovos-plugin-manager](https://github.com/OpenVoiceOS/ovos-plugin-manager): loads and manages solver plugins like this one.
* [OpenVoiceOS/ovos-persona-server](https://github.com/OpenVoiceOS/ovos-persona-server): runs solver plugins as chat personas.
54 changes: 53 additions & 1 deletion ovos_solver_rivescript_plugin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import os
from datetime import date
from os.path import dirname, isdir
from typing import Optional
from typing import List, Optional

from ovos_plugin_manager.templates.solvers import QuestionSolver
from ovos_utils.log import LOG
from ovos_utils.xdg_utils import xdg_data_home
from rivescript import RiveScript

try:
from ovos_plugin_manager.templates.agents import ChatEngine, AgentMessage, MessageRole
except ImportError:
# ovos-plugin-manager < 2.2.3a1 does not ship the agents module yet.
# The legacy QuestionSolver below still works without it; only the
# ChatEngine registration is unavailable on such an old install.
ChatEngine = object
AgentMessage = None
MessageRole = None


class RivescriptBot:
XDG_PATH = f"{xdg_data_home()}/rivescript"
Expand Down Expand Up @@ -124,7 +134,49 @@ def get_spoken_answer(self, query: str,
return self.brain.ask_brain(query)


class RivescriptChatEngine(ChatEngine):
"""RiveScript chatbot exposed as a modern ChatEngine agent plugin.

RiveScript is a pattern-matching chatbot: it has no notion of tool
calling, so ``tools`` is accepted (callers pass it by keyword) and
ignored, and ``supports_tools`` stays at the base default of False.
"""

def __init__(self, config=None):
config = config or {"lang": "en-us"}
lang = config.get("lang") or "en-us"
if lang != "en-us" and lang not in os.listdir(RivescriptBot.XDG_PATH):
config["lang"] = lang = "en-us"
super().__init__(config)
self.brain = RivescriptBot(lang, self.config)
self.brain.load_brain()

def continue_chat(self, messages: List["AgentMessage"],
session_id: str = "default",
lang: Optional[str] = None,
units: Optional[str] = None,
tools=None) -> "AgentMessage":
"""
Answer the latest user message via the RiveScript brain.

RiveScript itself has no concept of chat history beyond the single
reply it is asked for, so only the most recent user message is used;
earlier turns in ``messages`` are ignored, same as upstream RiveScript
usage elsewhere in this plugin.
"""
query = next((m.content for m in reversed(messages)
if m.role == MessageRole.USER), "")
if not query:
return AgentMessage(role=MessageRole.ASSISTANT, content="")
answer = self.brain.ask_brain(query) or ""
return AgentMessage(role=MessageRole.ASSISTANT, content=answer)


if __name__ == "__main__":
bot = RivescriptSolver()
print(bot.get_spoken_answer("hello!"))
print(bot.spoken_answer("Qual é a tua comida favorita?", lang="pt-pt"))

chat = RivescriptChatEngine()
reply = chat.continue_chat([AgentMessage(role=MessageRole.USER, content="hello!")])
print(reply.content)
8 changes: 5 additions & 3 deletions ovos_solver_rivescript_plugin/version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# START_VERSION_BLOCK
VERSION_MAJOR = 0
VERSION_MINOR = 0
VERSION_BUILD = 1
VERSION_ALPHA = 0
VERSION_MINOR = 1
VERSION_BUILD = 0
VERSION_ALPHA = 2
# END_VERSION_BLOCK

__version__ = f"{VERSION_MAJOR}.{VERSION_MINOR}.{VERSION_BUILD}" + (f"a{VERSION_ALPHA}" if VERSION_ALPHA else "")
Loading