chore: import upstream snapshot with attribution
CI Github Actions / Run Tests (push) Waiting to run
Automatic PR Merger / mergepal (push) Waiting to run
Docs Tests / Check for file changes (push) Waiting to run
Docs Tests / Test Documentation (push) Blocked by required conditions
Docs Tests / Documentation Linting Checks (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-performance) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-policies) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-cli) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-core-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-full-model-training) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-performance) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-policies) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-cli) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-core-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-full-model-training) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-predictors) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-other-unit-tests) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-performance) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-policies) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.10, test-cli) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.10, test-core-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.10, test-full-model-training) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-predictors) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.10, test-other-unit-tests) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.10, test-performance) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.10, test-policies) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.8, test-cli) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.8, test-core-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-predictors) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-other-unit-tests) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.8, test-full-model-training) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-predictors) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.8, test-other-unit-tests) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.8, test-performance) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.8, test-policies) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.9, test-cli) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.9, test-core-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.9, test-full-model-training) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-predictors) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.9, test-other-unit-tests) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.9, test-performance) (push) Blocked by required conditions
Continuous Integration / Run Tests (windows-2022, 3.9, test-policies) (push) Blocked by required conditions
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.10) (push) Blocked by required conditions
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.8) (push) Blocked by required conditions
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.9) (push) Blocked by required conditions
Continuous Integration / Run Flaky Tests (windows-2022, 3.10) (push) Blocked by required conditions
Continuous Integration / Run Flaky Tests (windows-2022, 3.8) (push) Blocked by required conditions
Continuous Integration / Run Flaky Tests (windows-2022, 3.9) (push) Blocked by required conditions
Continuous Integration / Check for file changes (push) Waiting to run
Continuous Integration / Wait for docs tests (push) Blocked by required conditions
Continuous Integration / Code Quality (push) Blocked by required conditions
Continuous Integration / Check for changelog (push) Waiting to run
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-cli) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-core-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-full-model-training) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-featurizers) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-predictors) (push) Blocked by required conditions
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-other-unit-tests) (push) Blocked by required conditions
Continuous Integration / Upload coverage reports to codeclimate (push) Blocked by required conditions
Continuous Integration / Run Non-Sequential Integration Tests (push) Blocked by required conditions
Continuous Integration / Run Broker Integration Tests (push) Blocked by required conditions
Continuous Integration / Run Sequential Integration Tests (push) Blocked by required conditions
Continuous Integration / Build Docker base images and setup environment (push) Waiting to run
Continuous Integration / Build Docker (default) (push) Blocked by required conditions
Continuous Integration / Build Docker (full) (push) Blocked by required conditions
Continuous Integration / Build Docker (mitie-en) (push) Blocked by required conditions
Continuous Integration / Build Docker (spacy-de) (push) Blocked by required conditions
Continuous Integration / Build Docker (spacy-en) (push) Blocked by required conditions
Continuous Integration / Build Docker (spacy-it) (push) Blocked by required conditions
Continuous Integration / Deploy to PyPI (push) Blocked by required conditions
Continuous Integration / Notify Slack & Publish Release Notes (push) Blocked by required conditions
Publish Documentation / Evaluate release tag (push) Waiting to run
Publish Documentation / Prebuild Docs (push) Blocked by required conditions
Publish Documentation / Preview Docs (push) Blocked by required conditions
Publish Documentation / Check for file changes (push) Waiting to run
Publish Documentation / Publish Docs (push) Waiting to run
Semgrep / Semgrep Workflow Security Scan (push) Waiting to run

This commit is contained in:
wehub-resource-sync
2026-07-13 13:24:47 +08:00
commit dc6079821b
1384 changed files with 261110 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
version: "2"
exclude_patterns:
- rasa/core/utils.py # codeclimate has some encoding issues with this files because of emojis
- .*
- .github/
- CHANGELOG.mdx
- CODEOWNERS
- CODE_OF_CONDUCT.md
- Dockerfile
- LICENSE.txt
- Makefile
- NOTICE
- PRONCIPLES.md
- README.md
- binder/
- changelog/
- data/
- docs/
- examples/
- poetry.lock
- pyproject.toml
- tests/
- stubs/
- scripts/
- security.txt
- secrets.tar.enc
checks:
argument-count:
config:
threshold: 10
file-lines:
enabled: false
method-count:
enabled: false
+12
View File
@@ -0,0 +1,12 @@
version = 1
test_patterns = ["tests/**"]
exclude_patterns = ["docs/**"]
[[analyzers]]
name = "python"
enabled = true
[analyzers.meta]
runtime_version = "3.x.x"
+27
View File
@@ -0,0 +1,27 @@
# [Choice] Python version (use -bullseye variants on local arm64/Apple Silicon): 3, 3.10, 3.9, 3.8, 3.7, 3.6, 3-bullseye, 3.10-bullseye, 3.9-bullseye, 3.8-bullseye, 3.7-bullseye, 3.6-bullseye, 3-buster, 3.10-buster, 3.9-buster, 3.8-buster, 3.7-buster, 3.6-buster
ARG VARIANT=3-bullseye
FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT}
ENV PYTHONFAULTHANDLER=1 \
PYTHONUNBUFFERED=1 \
PYTHONHASHSEED=random \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
ARG NODE_VERSION="none"
RUN if [ "${NODE_VERSION}" != "nne" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
# [Optional] If your requirements rarely change, uncomment this section to add them to the image.
# COPY requirements.txt /tmp/pip-tmp/
# RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \
# && rm -rf /tmp/pip-tmp
RUN pip install poetry==1.1.10 pre-commit
COPY ../poetry.lock ../pyproject.toml /tmp/pip-tmp/rasa/
RUN cd /tmp/pip-tmp/rasa && poetry config virtualenvs.create false \
&& poetry install --no-interaction --no-ansi --no-root
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
+50
View File
@@ -0,0 +1,50 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.233.0/containers/python-3-postgres
// Update the VARIANT arg in docker-compose.yml to pick a Python version
{
"name": "Rasa Open Source",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/rasa",
// Set *default* container specific settings.json values on container create.
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
"python.linting.banditPath": "/usr/local/py-utils/bin/bandit",
"python.linting.ruffPath": "/usr/local/py-utils/bin/ruff",
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy",
"python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle",
"python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint",
"python.testing.pytestPath": "/usr/local/py-utils/bin/pytest"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance"
],
// memory is required for frontend build...fails for machines with less than 10g
// "hostRequirements": {
// "memory": "12gb"
// },
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// This can be used to network with other containers or the host.
"forwardPorts": [
5005
],
// Use 'postCreateCommand' to run commands after the container is created.
"updateContentCommand": "make install && make install-docs && cd / && mkdir example && rasa init --no-prompt --init-dir example",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
//"remoteUser": "vscode",
"features": {
"docker-in-docker": "20.10",
"docker-from-docker": "20.10",
"git": "os-provided",
"github-cli": "latest",
"sshd": "latest"
}
}
+57
View File
@@ -0,0 +1,57 @@
version: '3.8'
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
args:
# Update 'VARIANT' to pick a version of Python: 3, 3.10, 3.9, 3.8, 3.7, 3.6
# Append -bullseye or -buster to pin to an OS version.
# Use -bullseye variants on local arm64/Apple Silicon.
VARIANT: "3.8"
# Optional Node.js version to install
NODE_VERSION: "16"
environment:
DB_DRIVER: "postgresql"
DB_USER: "admin"
DB_PASSWORD: "postgres"
volumes:
- ..:/workspaces/rasa:cached
# Overrides default command so things don't shut down after the process ends.
command: sleep infinity
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
network_mode: service:db
# Uncomment the next line to use a non-root user for all processes.
# user: vscode
db:
image: "bitnamilegacy/postgresql:11.15.0"
restart: unless-stopped
volumes:
- postgres-data:/bitnami/postgresql
environment:
POSTGRESQL_USERNAME: admin
POSTGRESQL_DATABASE: rasa
POSTGRESQL_PASSWORD: postgres
duckling:
restart: unless-stopped
image: "rasa/duckling:0.2.0.2"
expose:
- "8000"
command: ["duckling-example-exe", "--no-access-log", "--no-error-log"]
redis:
restart: unless-stopped
image: "bitnamilegacy/redis:6.2.7"
environment:
REDIS_PASSWORD: "redis"
expose:
- "6379"
volumes:
postgres-data: null
+11
View File
@@ -0,0 +1,11 @@
docker*
docs
.git*
**/*.pyc
**/__pycache__
!docker/configs
rasa/tests
rasa/scripts
data/
examples/
docker-data/*
+3
View File
@@ -0,0 +1,3 @@
* -text
# Reclassifies `Dockerfile*` files as Dockerfile:
Dockerfile.* linguist-language=Dockerfile
+2
View File
@@ -0,0 +1,2 @@
<!-- IF YOU ARE ASKING A USAGE QUESTION (E.G. "HOW DO I DO XYZ") PLEASE POST
YOUR QUESTION ON https://forum.rasa.com INSTEAD -->
+11
View File
@@ -0,0 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: Bug Report
url: https://rasa-open-source.atlassian.net/browse/OSS
about: Create a report to help us improve https://rasa-open-source.atlassian.net/browse/OSS
- name: Feature request
url: https://rasa-open-source.atlassian.net/browse/OSS
about: Suggest an idea on how to improve Rasa https://rasa-open-source.atlassian.net/browse/OSS
- name: Ask a question
url: https://forum.rasa.com/
about: If you have a "How do I?" question please ask in the forum https://forum.rasa.com
@@ -0,0 +1,10 @@
:bulb: This pull request was created automatically to merge a release branch back into the `main` branch.
The changes you see here should have already been reviewed by someone, and shouldn't need an extra
review. Nonetheless, if you notice something that needs to be addressed, please reach out to the person
responsible for the original changes. In case additional changes need to be made, they need to target the release branch
(not this pull request nor `main`).
:auto_rickshaw: This PR should be merged automatically once it has been approved. If it doesn't happen:
- [ ] Handle merge conflicts
- [ ] Fix build errors
+8
View File
@@ -0,0 +1,8 @@
**Proposed changes**:
- ...
**Status (please check what you already did)**:
- [ ] added some tests for the functionality
- [ ] updated the documentation
- [ ] updated the changelog (please check [changelog](https://github.com/RasaHQ/rasa/tree/main/changelog) for instructions)
- [ ] reformat files using `black` (please check [Readme](https://github.com/RasaHQ/rasa#code-style) for instructions)
+28
View File
@@ -0,0 +1,28 @@
backend:
- 'pyproject.toml'
- 'poetry.lock'
- 'rasa/**/*'
- 'tests/**/*'
- 'data/**/*'
- 'examples/**/*'
- 'Makefile'
- '.github/workflows/continous-integration.yml'
- '.github/workflows/security-scans.yml'
docker:
- 'pyproject.toml'
- 'poetry.lock'
- 'rasa/**/*'
- 'docker/**/*'
- 'Makefile'
docs:
- 'docs/**/*'
- 'changelog/*'
- 'CHANGELOG.mdx'
- 'tests/docs/*'
- 'data/**/*'
- 'examples/**/*'
- 'Makefile'
- '.github/workflows/documentation.yml'
- '.github/workflows/ci-docs-tests.yml'
+49
View File
@@ -0,0 +1,49 @@
## Example configuration
#################### syntax #################
## include:
## - dataset: ["<dataset_name>"]
## config: ["<configuration_name>"]
#
## Example:
## include:
## - dataset: ["Carbon Bot"]
## config: ["Sparse + DIET(bow) + ResponseSelector(bow)"]
#
## Shortcut:
## You can use the "all" shortcut to include all available configurations or datasets
#
## Example: Use the "Sparse + EmbeddingIntent + ResponseSelector(bow)" configuration
## for all available datasets
## include:
## - dataset: ["all"]
## config: ["Sparse + DIET(bow) + ResponseSelector(bow)"]
#
## Example: Use all available configurations for the "Carbon Bot" and "Sara" datasets
## and for the "Hermit" dataset use the "Sparse + DIET + ResponseSelector(T2T)" and
## "BERT + DIET + ResponseSelector(T2T)" configurations:
## include:
## - dataset: ["Carbon Bot", "Sara"]
## config: ["all"]
## - dataset: ["Hermit"]
## config: ["Sparse + DIET(seq) + ResponseSelector(t2t)", "BERT + DIET(seq) + ResponseSelector(t2t)"]
#
## Example: Define a branch name to check-out for a dataset repository. Default branch is 'main'
## dataset_branch: "test-branch"
## include:
## - dataset: ["Carbon Bot", "Sara"]
## config: ["all"]
#
## Example: Define number of repetitions. This will inform how often to repeat all runs defined in the include section. Default is 1
## num_repetitions: 2
## include:
## - dataset: ["Carbon Bot", "Sara"]
## config: ["Sparse + DIET(seq) + ResponseSelector(t2t)"]
##
## Shortcuts:
## You can use the "all" shortcut to include all available configurations or datasets.
## You can use the "all-nlu" shortcut to include all available NLU configurations or datasets.
## You can use the "all-core" shortcut to include all available core configurations or datasets.
include:
- dataset: ["Carbon Bot"]
config: ["Sparse + DIET(bow) + ResponseSelector(bow)"]
+3
View File
@@ -0,0 +1,3 @@
{
"body": "```yml\r\ninclude:\r\n - dataset: [\"all\"]\r\n config: [\"all\"]\r\n```"
}
+25
View File
@@ -0,0 +1,25 @@
{
"default_image_tag": "latest",
"config": [
{
"TF": "2.3",
"IMAGE_TAG": "cuda-10.1-cudnn7"
},
{
"TF": "2.5",
"IMAGE_TAG": "cuda-11.2.0-cudnn8"
},
{
"TF": "2.6",
"IMAGE_TAG": "cuda-11.2.0-cudnn8"
},
{
"TF": "2.7",
"IMAGE_TAG": "cuda-11.2.0-cudnn8"
},
{
"TF": "2.11",
"IMAGE_TAG": "cuda-11.2.0-cudnn8"
}
]
}
+34
View File
@@ -0,0 +1,34 @@
version: 2
updates:
- package-ecosystem: pip
directory: "/"
schedule:
interval: weekly
time: "13:00"
pull-request-branch-name:
separator: "-"
open-pull-requests-limit: 10
labels:
- type:dependencies
- release:main
ignore:
- dependency-name: prompt-toolkit
versions:
- "> 2.0.10"
- dependency-name: pytest-asyncio
versions:
- "> 0.10.0"
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
day: monday
time: "12:00"
pull-request-branch-name:
separator: "-"
open-pull-requests-limit: 10
reviewers:
- RasaHQ/infrastructure-squad
labels:
- type:dependencies
@@ -0,0 +1,17 @@
{
"problemMatcher": [
{
"owner": "flake8-error",
"severity": "error",
"pattern": [
{
"regexp": "^([^:]+):(\\d+):(\\d+):\\s+([DCFNWE]\\d+\\s+.+)$",
"file": 1,
"line": 2,
"column": 3,
"message": 4
}
]
}
]
}
+12
View File
@@ -0,0 +1,12 @@
# Configuration for probot-no-response - https://github.com/probot/no-response
# Number of days of inactivity before an Issue is closed for lack of response
daysUntilClose: 14
# Label requiring a response
responseRequiredLabel: status:more-details-needed
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
closeComment: >
This issue has been automatically closed because there has been no response
to our request for more information from the original author. Without this,
we don't have enough information to help you. Please comment below with the
requested information if you still need help.
+2
View File
@@ -0,0 +1,2 @@
# The poetry version is stored in a separate file due to the https://github.com/python-poetry/poetry/issues/3316
poetry-version=1.8.2
@@ -0,0 +1,74 @@
# GitHub Runner deployment - uses to deploy a github runner
# which is used by the CI for model regression tests
apiVersion: apps/v1
kind: Deployment
metadata:
name: github-runner-{{getenv "GITHUB_RUN_ID"}}
namespace: github-runner
labels:
app: github-runner
pod: github-runner-{{getenv "GITHUB_RUN_ID"}}
spec:
replicas: {{getenv "NUM_REPLICAS" "1"}}
selector:
matchLabels:
app: github-runner
pod: github-runner-{{getenv "GITHUB_RUN_ID"}}
template:
metadata:
labels:
app: github-runner
pod: github-runner-{{getenv "GITHUB_RUN_ID"}}
spec:
priorityClassName: high-priority
automountServiceAccountToken: false
terminationGracePeriodSeconds: 720
containers:
- name: github-runner
image: {{getenv "GH_RUNNER_IMAGE"}}:{{getenv "GH_RUNNER_IMAGE_TAG" "latest"}}
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 30
periodSeconds: 15
failureThreshold: 3
exec:
command:
- /bin/bash
- -c
- "if [[ `curl -sX GET -H \"Authorization: token ${GITHUB_PAT}\" \
https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPOSITORY}/actions/runners | \
jq -r '.runners[] | select(.name == \"'${POD_NAME}'\") | .status'` == \"offline\" ]]; then \
echo \"The GitHub API returns offline status for the ${POD_NAME} runner\" && exit 1; fi"
resources:
limits:
nvidia.com/gpu: 1
requests:
nvidia.com/gpu: 1
memory: 10G
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
# RUNNER_LABELS - defines labels
# with which a github-runner will be registered
- name: RUNNER_LABELS
value: "self-hosted,gpu,kubernetes,{{getenv "GITHUB_RUN_ID"}}"
# GITHUB_OWNER - a name of the repository owner
- name: GITHUB_OWNER
valueFrom:
secretKeyRef:
name: github-rasa
key: owner
# GITHUB_REPOSITORY - a name of the repository
- name: GITHUB_REPOSITORY
valueFrom:
secretKeyRef:
name: github-rasa
key: repository
# GITHUB_PAT - Personal Access Token
- name: GITHUB_PAT
valueFrom:
secretKeyRef:
name: github-rasa
key: pat
+120
View File
@@ -0,0 +1,120 @@
import argparse
import logging
import time
from typing import List, NamedTuple, Optional, Text
from transformers import AutoTokenizer, TFAutoModel
import rasa.shared.utils.io
from rasa.nlu.utils.hugging_face.registry import (
model_weights_defaults,
model_class_dict,
)
logger = logging.getLogger(__name__)
COMP_NAME = "LanguageModelFeaturizer"
DEFAULT_MODEL_NAME = "bert"
class LmfSpec(NamedTuple):
"""Holds information about the LanguageModelFeaturizer."""
model_name: Text
model_weights: Text
cache_dir: Optional[Text] = None
def get_model_name_and_weights_from_config(
config_path: str,
) -> List[LmfSpec]:
config = rasa.shared.utils.io.read_config_file(config_path)
logger.info(config)
steps = config.get("pipeline", [])
# Look for LanguageModelFeaturizer steps
steps = list(filter(lambda x: x["name"] == COMP_NAME, steps))
lmf_specs = []
for lmfeat_step in steps:
if "model_name" not in lmfeat_step:
if "model_weights" in lmfeat_step:
model_weights = lmfeat_step["model_weights"]
raise KeyError(
"When model_name is not given, then model_weights cannot be set. "
f"Here, model_weigths is set to {model_weights}"
)
model_name = DEFAULT_MODEL_NAME
model_weights = model_weights_defaults[DEFAULT_MODEL_NAME]
else:
model_name = lmfeat_step["model_name"]
if model_name not in model_class_dict:
raise KeyError(
f"'{model_name}' not a valid model name. Choose from "
f"{str(list(model_class_dict.keys()))} or create"
f"a new class inheriting from this class to support your model."
)
model_weights = lmfeat_step.get("model_weights")
if not model_weights:
logger.info(
f"Model weights not specified. Will choose default model "
f"weights: {model_weights_defaults[model_name]}"
)
model_weights = model_weights_defaults[model_name]
cache_dir = lmfeat_step.get("cache_dir", None)
lmf_specs.append(LmfSpec(model_name, model_weights, cache_dir))
return lmf_specs
def instantiate_to_download(comp: LmfSpec) -> None:
"""Instantiates Auto class instances, but only to download."""
_ = AutoTokenizer.from_pretrained(comp.model_weights, cache_dir=comp.cache_dir)
logger.info("Done with AutoTokenizer, now doing TFAutoModel")
_ = TFAutoModel.from_pretrained(comp.model_weights, cache_dir=comp.cache_dir)
def download(config_path: str):
lmf_specs = get_model_name_and_weights_from_config(config_path)
if not lmf_specs:
logger.info(f"No {COMP_NAME} found, therefore, skipping download")
return
for lmf_spec in lmf_specs:
logger.info(
f"model_name: {lmf_spec.model_name}, "
f"model_weights: {lmf_spec.model_weights}, "
f"cache_dir: {lmf_spec.cache_dir}"
)
start = time.time()
instantiate_to_download(lmf_spec)
duration_in_sec = time.time() - start
logger.info(f"Instantiating Auto classes takes {duration_in_sec:.2f}seconds")
def create_argument_parser() -> argparse.ArgumentParser:
"""Downloads pretrained models, i.e., Huggingface weights."""
parser = argparse.ArgumentParser(
description="Downloads pretrained models, i.e., Huggingface weights, "
"e.g. path to bert_diet_responset2t.yml"
)
parser.add_argument(
"-c",
"--config",
type=str,
required=True,
help="The path to the config yaml file.",
)
return parser
if __name__ == "__main__":
arg_parser = create_argument_parser()
cmdline_args = arg_parser.parse_args()
download(cmdline_args.config)
+55
View File
@@ -0,0 +1,55 @@
# Collect the results of the various model test runs which are done as part of
# the model regression CI pipeline and dump them as a single file artifact.
# This artifact will the then be published at the end of the tests.
from collections import defaultdict
import json
import os
from pathlib import Path
from typing import Dict, List
def combine_result(
result1: Dict[str, dict], result2: Dict[str, Dict[str, Dict]]
) -> Dict[str, Dict[str, List]]:
"""Combines 2 result dicts to accumulated dict of the same format.
Args:
result1: dict of key: dataset, value: (dict of key: config, value: list of res)
Example: {
"Carbon Bot": {
"Sparse + DIET(bow) + ResponseSelector(bow)": [{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.88,
}
},
"test_run_time": "47s",
}]
}
}
result2: dict of key: dataset, value: (dict of key: config, value: list of res)
Returns:
dict of key: dataset, and value: (dict of key: config value: list of results)
"""
combined_dict = defaultdict(lambda: defaultdict(list))
for new_dict in [result1, result2]:
for dataset, results_for_dataset in new_dict.items():
for config, res in results_for_dataset.items():
for res_dict in res:
combined_dict[dataset][config].append(res_dict)
return combined_dict
if __name__ == "__main__":
data = {}
reports_dir = Path(os.environ["REPORTS_DIR"])
reports_paths = list(reports_dir.glob("*/report.json"))
for report_path in reports_paths:
report_dict = json.load(open(report_path))
data = combine_result(data, report_dict)
summary_file = os.environ["SUMMARY_FILE"]
with open(summary_file, "w") as f:
json.dump(data, f, sort_keys=True, indent=2)
+293
View File
@@ -0,0 +1,293 @@
# Send model regression test results to Datadog
# with a summary of all test results.
# Also write them into a report file.
import copy
import datetime
import json
import os
from typing import Any, Dict, List, Text, Tuple
from datadog_api_client.v1 import ApiClient, Configuration
from datadog_api_client.v1.api.metrics_api import MetricsApi
from datadog_api_client.v1.model.metrics_payload import MetricsPayload
from datadog_api_client.v1.model.point import Point
from datadog_api_client.v1.model.series import Series
DD_ENV = "rasa-regression-tests"
DD_SERVICE = "rasa"
METRIC_RUNTIME_PREFIX = "rasa.perf.benchmark."
METRIC_ML_PREFIX = "rasa.perf.ml."
CONFIG_REPOSITORY = "training-data"
TASK_MAPPING = {
"intent_report.json": "intent_classification",
"CRFEntityExtractor_report.json": "entity_prediction",
"DIETClassifier_report.json": "entity_prediction",
"response_selection_report.json": "response_selection",
"story_report.json": "story_prediction",
}
METRICS = {
"test_run_time": "TEST_RUN_TIME",
"train_run_time": "TRAIN_RUN_TIME",
"total_run_time": "TOTAL_RUN_TIME",
}
MAIN_TAGS = {
"config": "CONFIG",
"dataset": "DATASET_NAME",
}
OTHER_TAGS = {
"config_repository_branch": "DATASET_REPOSITORY_BRANCH",
"dataset_commit": "DATASET_COMMIT",
"accelerator_type": "ACCELERATOR_TYPE",
"type": "TYPE",
"index_repetition": "INDEX_REPETITION",
"host_name": "HOST_NAME",
}
GIT_RELATED_TAGS = {
"pr_id": "PR_ID",
"pr_url": "PR_URL",
"github_event": "GITHUB_EVENT_NAME",
"github_run_id": "GITHUB_RUN_ID",
"github_sha": "GITHUB_SHA",
"workflow": "GITHUB_WORKFLOW",
}
def create_dict_of_env(name_to_env: Dict[Text, Text]) -> Dict[Text, Text]:
return {name: os.environ[env_var] for name, env_var in name_to_env.items()}
def _get_is_external_and_dataset_repository_branch() -> Tuple[bool, Text]:
is_external = os.environ["IS_EXTERNAL"]
dataset_repository_branch = os.environ["DATASET_REPOSITORY_BRANCH"]
if is_external.lower() in ("yes", "true", "t", "1"):
is_external_flag = True
dataset_repository_branch = os.environ["EXTERNAL_DATASET_REPOSITORY_BRANCH"]
else:
is_external_flag = False
return is_external_flag, dataset_repository_branch
def prepare_datasetrepo_and_external_tags() -> Dict[Text, Any]:
is_external, dataset_repo_branch = _get_is_external_and_dataset_repository_branch()
return {
"dataset_repository_branch": dataset_repo_branch,
"external_dataset_repository": is_external,
}
def prepare_dsrepo_and_external_tags_as_str() -> Dict[Text, Text]:
return {
"dataset_repository_branch": os.environ["DATASET_REPOSITORY_BRANCH"],
"external_dataset_repository": os.environ["IS_EXTERNAL"],
}
def transform_to_seconds(duration: Text) -> float:
"""Transform string (with hours, minutes, and seconds) to seconds.
Args:
duration: Examples: '1m27s', '1m27.3s', '27s', '1h27s', '1h1m27s'
Raises:
Exception: If the input is not supported.
Returns:
Duration converted in seconds.
"""
h_split = duration.split("h")
if len(h_split) == 1:
rest = h_split[0]
hours = 0
else:
hours = int(h_split[0])
rest = h_split[1]
m_split = rest.split("m")
if len(m_split) == 2:
minutes = int(m_split[0])
seconds = float(m_split[1].rstrip("s"))
elif len(m_split) == 1:
minutes = 0
seconds = float(m_split[0].rstrip("s"))
else:
raise Exception(f"Unsupported duration: {duration}")
overall_seconds = hours * 60 * 60 + minutes * 60 + seconds
return overall_seconds
def prepare_ml_metric(result: Dict[Text, Any]) -> Dict[Text, float]:
"""Converts a nested result dict into a list of metrics.
Args:
result: Example
{'accuracy': 1.0,
'weighted avg': {
'precision': 1.0, 'recall': 1.0, 'f1-score': 1.0, 'support': 28
}
}
Returns:
Dict of metric name and metric value
"""
metrics_ml = {}
result = copy.deepcopy(result)
result.pop("file_name", None)
task = result.pop("task", None)
for metric_name, metric_value in result.items():
if isinstance(metric_value, float):
metric_full_name = f"{task}.{metric_name}"
metrics_ml[metric_full_name] = float(metric_value)
elif isinstance(metric_value, dict):
for mname, mval in metric_value.items():
metric_full_name = f"{task}.{metric_name}.{mname}"
metrics_ml[metric_full_name] = float(mval)
else:
raise Exception(
f"metric_value {metric_value} has",
f"unexpected type {type(metric_value)}",
)
return metrics_ml
def prepare_ml_metrics(results: List[Dict[Text, Any]]) -> Dict[Text, float]:
metrics_ml = {}
for result in results:
new_metrics_ml = prepare_ml_metric(result)
metrics_ml.update(new_metrics_ml)
return metrics_ml
def prepare_datadog_tags() -> List[Text]:
tags = {
"env": DD_ENV,
"service": DD_SERVICE,
"branch": os.environ["BRANCH"],
"config_repository": CONFIG_REPOSITORY,
**prepare_dsrepo_and_external_tags_as_str(),
**create_dict_of_env(MAIN_TAGS),
**create_dict_of_env(OTHER_TAGS),
**create_dict_of_env(GIT_RELATED_TAGS),
}
tags_list = [f"{k}:{v}" for k, v in tags.items()]
return tags_list
def send_to_datadog(results: List[Dict[Text, Any]]) -> None:
"""Sends metrics to datadog."""
# Prepare
tags_list = prepare_datadog_tags()
timestamp = datetime.datetime.now().timestamp()
series = []
# Send metrics about runtime
metrics_runtime = create_dict_of_env(METRICS)
for metric_name, metric_value in metrics_runtime.items():
overall_seconds = transform_to_seconds(metric_value)
series.append(
Series(
metric=f"{METRIC_RUNTIME_PREFIX}{metric_name}.gauge",
type="gauge",
points=[Point([timestamp, overall_seconds])],
tags=tags_list,
)
)
# Send metrics about ML model performance
metrics_ml = prepare_ml_metrics(results)
for metric_name, metric_value in metrics_ml.items():
series.append(
Series(
metric=f"{METRIC_ML_PREFIX}{metric_name}.gauge",
type="gauge",
points=[Point([timestamp, float(metric_value)])],
tags=tags_list,
)
)
body = MetricsPayload(series=series)
with ApiClient(Configuration()) as api_client:
api_instance = MetricsApi(api_client)
response = api_instance.submit_metrics(body=body)
if response.get("status") != "ok":
print(response)
def read_results(file: Text) -> Dict[Text, Any]:
with open(file) as json_file:
data = json.load(json_file)
keys = [
"accuracy",
"weighted avg",
"macro avg",
"micro avg",
"conversation_accuracy",
]
result = {key: data[key] for key in keys if key in data}
return result
def get_result(file_name: Text, file: Text) -> Dict[Text, Any]:
result = read_results(file)
result["file_name"] = file_name
result["task"] = TASK_MAPPING[file_name]
return result
def send_all_to_datadog() -> None:
results = []
for dirpath, dirnames, files in os.walk(os.environ["RESULT_DIR"]):
for f in files:
if any(f.endswith(valid_name) for valid_name in TASK_MAPPING.keys()):
result = get_result(f, os.path.join(dirpath, f))
results.append(result)
send_to_datadog(results)
def generate_json(file: Text, task: Text, data: dict) -> dict:
config = os.environ["CONFIG"]
dataset = os.environ["DATASET_NAME"]
if dataset not in data:
data = {dataset: {config: []}, **data}
elif config not in data[dataset]:
data[dataset] = {config: [], **data[dataset]}
assert len(data[dataset][config]) <= 1
data[dataset][config] = [
{
"config_repository": CONFIG_REPOSITORY,
**prepare_datasetrepo_and_external_tags(),
**create_dict_of_env(METRICS),
**create_dict_of_env(OTHER_TAGS),
**(data[dataset][config][0] if data[dataset][config] else {}),
task: read_results(file),
}
]
return data
def create_report_file() -> None:
data = {}
for dirpath, dirnames, files in os.walk(os.environ["RESULT_DIR"]):
for f in files:
if f not in TASK_MAPPING.keys():
continue
data = generate_json(os.path.join(dirpath, f), TASK_MAPPING[f], data)
with open(os.environ["SUMMARY_FILE"], "w") as f:
json.dump(data, f, sort_keys=True, indent=2)
if __name__ == "__main__":
send_all_to_datadog()
create_report_file()
+79
View File
@@ -0,0 +1,79 @@
#!/bin/bash
DD_API_KEY=$1
ACCELERATOR_TYPE=$2
NVML_INTERVAL_IN_SEC=${3:-15} # 15 seconds are the default interval
# Install Datadog system agent
DD_AGENT_MAJOR_VERSION=7 DD_API_KEY=$DD_API_KEY DD_SITE="datadoghq.eu" bash -c "$(curl -L https://s3.amazonaws.com/dd-agent/scripts/install_script.sh)"
DATADOG_YAML_PATH=/etc/datadog-agent/datadog.yaml
sudo chmod 666 $DATADOG_YAML_PATH
# Associate metrics with tags and env
{
echo "env: rasa-regression-tests"
echo "tags:"
echo "- service:rasa"
echo "- accelerator_type:${ACCELERATOR_TYPE}"
echo "- dataset:${DATASET_NAME}"
echo "- config:${CONFIG}"
echo "- dataset_commit:${DATASET_COMMIT}"
echo "- branch:${BRANCH}"
echo "- github_sha:${GITHUB_SHA}"
echo "- pr_id:${PR_ID:-schedule}"
echo "- pr_url:${PR_URL:-schedule}"
echo "- type:${TYPE}"
echo "- dataset_repository_branch:${DATASET_REPOSITORY_BRANCH}"
echo "- external_dataset_repository:${IS_EXTERNAL:-none}"
echo "- config_repository:training-data"
echo "- config_repository_branch:${DATASET_REPOSITORY_BRANCH}"
echo "- workflow:${GITHUB_WORKFLOW:-none}"
echo "- github_run_id:${GITHUB_RUN_ID:-none}"
echo "- github_event:${GITHUB_EVENT_NAME:-none}"
echo "- index_repetition:${INDEX_REPETITION}"
echo "- host_name:${HOST_NAME}"
echo ""
echo "apm_config:"
echo " enabled: true"
echo "process_config:"
echo " enabled: false"
echo "use_dogstatsd: true"
} >> $DATADOG_YAML_PATH
# Enable system_core integration
sudo mv /etc/datadog-agent/conf.d/system_core.d/conf.yaml.example /etc/datadog-agent/conf.d/system_core.d/conf.yaml
if [[ "${ACCELERATOR_TYPE}" == "GPU" ]]; then
# Install and enable NVML integration
sudo datadog-agent integration --allow-root install -t datadog-nvml==1.0.1
sudo -u dd-agent -H /opt/datadog-agent/embedded/bin/pip3 install grpcio pynvml
NVML_CONF_FPATH="/etc/datadog-agent/conf.d/nvml.d/conf.yaml"
sudo mv "${NVML_CONF_FPATH}.example" ${NVML_CONF_FPATH}
if [[ "${NVML_INTERVAL_IN_SEC}" != 15 ]]; then
# Append a line to the NVML config file
sudo echo " min_collection_interval: ${NVML_INTERVAL_IN_SEC}" | sudo tee -a ${NVML_CONF_FPATH} > /dev/null
fi
fi
# Apply changes
sudo service datadog-agent stop
# Restart agent (such that GPU/NVML metrics are collected)
# Adusted code from /etc/init/datadog-agent.conf
INSTALL_DIR="/opt/datadog-agent"
AGENTPATH="$INSTALL_DIR/bin/agent/agent"
PIDFILE="$INSTALL_DIR/run/agent.pid"
AGENT_USER="dd-agent"
LD_LIBRARY_PATH="/usr/local/cuda/extras/CUPTI/lib64:/usr/local/cuda/lib64:/usr/local/nvidia/lib:/usr/local/nvidia/lib64"
sudo -E start-stop-daemon --start --background --quiet --chuid $AGENT_USER --pidfile $PIDFILE --user $AGENT_USER --startas /bin/bash -- -c "LD_LIBRARY_PATH=$LD_LIBRARY_PATH $AGENTPATH run -p $PIDFILE"
# Adusted code from /etc/init/datadog-agent-process.conf
TRACE_AGENTPATH="$INSTALL_DIR/embedded/bin/trace-agent"
TRACE_PIDFILE="$INSTALL_DIR/run/trace-agent.pid"
sudo -E start-stop-daemon --start --background --quiet --chuid $AGENT_USER --pidfile $TRACE_PIDFILE --user $AGENT_USER --startas /bin/bash -- -c "LD_LIBRARY_PATH=$LD_LIBRARY_PATH $TRACE_AGENTPATH --config $DATADOG_YAML_PATH --pid $TRACE_PIDFILE"
# Adusted code from /etc/init/datadog-agent-trace.conf
PROCESS_AGENTPATH="$INSTALL_DIR/embedded/bin/process-agent"
PROCESS_PIDFILE="$INSTALL_DIR/run/process-agent.pid"
SYSTEM_PROBE_YAML="/etc/datadog-agent/system-probe.yaml"
sudo -E start-stop-daemon --start --background --quiet --chuid $AGENT_USER --pidfile $PROCESS_PIDFILE --user $AGENT_USER --startas /bin/bash -- -c "LD_LIBRARY_PATH=$LD_LIBRARY_PATH $PROCESS_AGENTPATH --config=$DATADOG_YAML_PATH --sysprobe-config=$SYSTEM_PROBE_YAML --pid=$PROCESS_PIDFILE"
+14
View File
@@ -0,0 +1,14 @@
import sys
import tensorflow as tf
def check_gpu_not_available():
num_gpus = len(tf.config.list_physical_devices("GPU"))
print(f"Num GPUs Available: {num_gpus}")
if num_gpus > 0:
sys.exit(1)
if __name__ == "__main__":
check_gpu_not_available()
+14
View File
@@ -0,0 +1,14 @@
import sys
import tensorflow as tf
def check_gpu_available():
num_gpus = len(tf.config.list_physical_devices("GPU"))
print(f"Num GPUs Available: {num_gpus}")
if num_gpus <= 0:
sys.exit(1)
if __name__ == "__main__":
check_gpu_available()
+18
View File
@@ -0,0 +1,18 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 90
# Label to use when marking an issue as stale
staleLabel: stale
pulls:
# Give more time before closing PRs
daysUntilClose: 21
# Comment to post when marking a PR as stale. Set to `false` to disable
markComment: >
This PR has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale PR. Set to `false` to disable
closeComment: >
This PR has been automatically closed due to inactivity. Please reopen
this PR or a new one if you plan to follow-up on it. Thank you for your
contributions.
+63
View File
@@ -0,0 +1,63 @@
# gomplate templates for GitHub Actions
This document describes gomplate templates use for GitHub Actions.
## Requirements
You have to have installed [gomplate](https://docs.gomplate.ca/installing/) tool in order to render a template file.
> gomplate is a template renderer which supports a growing list of datastores, such as: JSON (including EJSON - encrypted JSON), YAML, AWS EC2 metadata, BoltDB, Hashicorp Consul and Hashicorp Vault secrets.
## Templates
Below you can find a list of templates with their description and the commands to render them.
### `configuration_variables.tmpl`
The template maps dataset name and configuration name for the model regression tests into paths where files are located. As a result, the template returns two environment variables `DATASET` and `CONFIG` which contain paths to file/directory.
#### How to run locally
```shell
gomplate -d mapping=<path_to_json_file_with_mapping> -f .github/templates/configuration_variables.tmpl
```
### `model_regression_test_config_comment.tmpl`
The template returns a comment message which is used as a help description in a PR. The template reads the `.github/configs/mr-test-example.yaml` file and include it as example content.
The help message is triggered by adding `status:model-regression-tests` label.
Comment with a help message is added if a PR doesn't contain a comment with a configuration for the model regression tests.
#### How to run locally
```shell
gomplate -f .github/templates/model_regression_test_config_comment.tmpl
```
The template uses the `GITHUB_ACTOR` environment variable, you have to export the variable before executing the command.
### `model_regression_test_config_to_json.tmpl`
The template reads an issue/a PR comment and transforms a YAML code block into JSON.
#### How to run locally
```shell
gomplate -d github=https://api.github.com/repos/${{ github.repository }}/issues/comments/${{ comment-id }} -H 'github=Authorization:token ${{ secrets.GITHUB_TOKEN }}' -f .github/templates/model_regression_test_config_to_json.tmpl
```
### `model_regression_test_results.tmpl`
The template reads a file with a report (the report file is available as an artifact in the model regression tests workflow) and returns markdown table with a summary of tests.
#### How to run locally
```shell
gomplate -d data=report.json -d results_main=report_main.json -f .github/templates/model_regression_test_results.tmpl
```
In order to be able to use the `.github/templates/model_regression_test_results.tmpl` template you need the following files:
- `report.json` - the file with a report generated by the `CI - Model Regression` workflow run in a PR. The report is available to download as an artifact in the workflow related to the PR.
- `report_main.json` - the file with a report generated by the `CI - Model Regression` workflow that is triggered on schedule event. A list of the workflows that you can download an artifact from, can be found [here](https://github.com/RasaHQ/rasa/actions?query=workflow%3A%22CI+-+Model+Regression%22+event%3Aschedule).
@@ -0,0 +1,43 @@
{{- /*
The template maps dataset name and configuration name for the model
regression tests into paths where files are located. As a result,
the template returns two environment variables `DATASET` and `CONFIG`
which contain paths to file/directory.
*/ -}}
{{- $mapping := (datasource "mapping") -}}
{{- $dataset := (index $mapping.datasets (getenv "DATASET_NAME")) -}}
{{- $config := $mapping.configurations -}}
{{- if has $dataset "repository" }}
export DATASET="{{ $dataset.repository }}"
export IS_EXTERNAL="true"
echo "::add-mask::{{ $dataset.repository }}"
{{ if has $dataset "repository_branch" }}
export EXTERNAL_DATASET_REPOSITORY_BRANCH="{{ $dataset.repository_branch }}"
{{ else }}
export EXTERNAL_DATASET_REPOSITORY_BRANCH="main"
{{ end }}
{{- else if has $dataset "path" }}
export DATASET="{{ $dataset.path }}"
export IS_EXTERNAL="false"
echo "::add-mask::{{ $dataset.path }}"
{{ end }}
{{- if has $dataset "train" }}
export TRAIN_DIR="{{ $dataset.train }}"
{{ end }}
{{- if has $dataset "test" }}
export TEST_DIR="{{ $dataset.test }}"
{{ end }}
{{- if has $dataset "domain" }}
export DOMAIN_FILE="{{ $dataset.domain }}"
{{ end }}
{{- if (has $config.nlu (getenv "CONFIG_NAME")) }}
export CONFIG="{{ $dataset.language }}/nlu/{{ index $config.nlu (getenv "CONFIG_NAME") }}"
echo "::add-mask::{{ $dataset.language }}/nlu/{{ index $config.nlu (getenv "CONFIG_NAME") }}"
{{ else if (has $config.core (getenv "CONFIG_NAME")) }}
export CONFIG="{{ $dataset.language }}/core/{{ index $config.core (getenv "CONFIG_NAME") }}"
echo "::add-mask::{{ $dataset.language }}/core/{{ index $config.core (getenv "CONFIG_NAME") }}"
{{ end -}}
@@ -0,0 +1,45 @@
{{- /*
The template returns a comment message which is used as a help description
in a PR. The template reads the `.github/configs/mr-test-example.yaml` file
and include it as example content.
The help message is triggered by adding `status:model-regression-tests` label.
Comment with a help message is added if a PR doesn't contain a comment
with a configuration for the model regression tests.
*/ -}}
{{ define "check_available_configuration" -}}
NLU
{{- if has .dataset "domain" -}}
, Core
{{- end -}}
{{- end -}}
Hey @{{ .Env.GITHUB_ACTOR }}! :wave: To run model regression tests, comment with the `/modeltest` command and a configuration.
_Tips :bulb:: The model regression test will be run on `push` events. You can re-run the tests by re-add `status:model-regression-tests` label or use a `Re-run jobs` button in Github Actions workflow._
_Tips :bulb:: Every time when you want to change a configuration you should edit the comment with the previous configuration._
You can copy this in your comment and customize:
> /modeltest
> ~~~yml
>```yml
>##########
>## Available datasets
>##########
{{range (coll.Keys (datasource "mapping").datasets)}}># - "{{ . }}" ({{ template "check_available_configuration" (dict "dataset" (index (datasource "mapping").datasets .)) }}){{"\n"}}{{ end -}}
>
>##########
>## Available NLU configurations
>##########
{{range (coll.Keys (datasource "mapping").configurations.nlu)}}># - "{{.}}"{{"\n"}}{{ end -}}
>
>##########
>## Available Core configurations
>##########
{{range (coll.Keys (datasource "mapping").configurations.core)}}># - "{{.}}"{{"\n"}}{{ end -}}
>
{{range split (file.Read ".github/configs/mr-test-example.yaml") "\n"}}>{{.}}{{"\n"}}{{ end -}}
>```
@@ -0,0 +1,71 @@
{{- /*
The template reads an issue/a PR comment and transforms a YAML code block into JSON.
*/ -}}
{{ define "check_config_type" -}}
{{- if has (datasource "mapping").configurations.nlu . -}}
nlu
{{- else if has (datasource "mapping").configurations.core . -}}
core
{{- end -}}
{{- end -}}
{{- $config := ((datasource "github").body | regexp.Find "```(?s)(.*)```" | regexp.ReplaceLiteral "```.*|\r" "" | yaml | toJSON | json) -}}
{{- $num_repetitions := 1 -}}
{{- if has $config "num_repetitions" -}}
{{- $num_repetitions = $config.num_repetitions -}}
{{- end -}}
{"include":[
{{- $inc := coll.Slice -}}
{{- $dataset := coll.Slice -}}
{{- range $pair := $config.include -}}
{{- /* use all available datasets if value is equal to all */ -}}
{{- if eq (index $pair.dataset 0) "all" -}}
{{ $dataset = (coll.Keys (datasource "mapping").datasets) }}
{{- else if eq (index $pair.dataset 0) "all-core" -}}
{{- range $dataset_name, $dataset_spec := (datasource "mapping").datasets -}}
{{- if has $dataset_spec "domain" -}}
{{ $dataset = (coll.Append $dataset_name $dataset) -}}
{{- end -}}
{{- end -}}
{{- else if eq (index $pair.dataset 0) "all-nlu" -}}
{{- range $dataset_name, $dataset_spec := (datasource "mapping").datasets -}}
{{- if not (has $dataset_spec "domain") -}}
{{ $dataset = (coll.Append $dataset_name $dataset) -}}
{{- end -}}
{{- end -}}
{{- else -}}
{{- $dataset = $pair.dataset -}}
{{- end -}}
{{- range $index_dataset, $value_dataset := $dataset -}}
{{- range $index_config, $value_config := $pair.config -}}
{{ range $index_repetition, $element := (strings.Repeat $num_repetitions "x " | strings.Trim " " | strings.Split " ") }}
{{- /* use all available configurations if value is equal to all */ -}}
{{- if eq $value_config "all" -}}
{{- range $config_type := (coll.Keys (datasource "mapping").configurations) -}}
{{- range $config_name, $config_file := (index (datasource "mapping").configurations $config_type ) -}}
{{ $inc = (coll.Append (dict "index_repetition" $index_repetition "dataset" $value_dataset "config" $config_name "type" $config_type | toJSON) $inc) -}}
{{- end -}}
{{- end -}}
{{- else if eq $value_config "all-core" -}}
{{- range $config_name, $config_file := (datasource "mapping").configurations.core -}}
{{ $inc = (coll.Append (dict "index_repetition" $index_repetition "dataset" $value_dataset "config" $config_name "type" "core" | toJSON) $inc) -}}
{{- end -}}
{{- else if eq $value_config "all-nlu" -}}
{{- range $config_name, $config_file := (datasource "mapping").configurations.nlu -}}
{{ $inc = (coll.Append (dict "index_repetition" $index_repetition "dataset" $value_dataset "config" $config_name "type" "nlu" | toJSON) $inc) -}}
{{- end -}}
{{- else -}}
{{- if has (datasource "mapping").configurations.nlu $value_config -}}
{{ $inc = (coll.Append (dict "index_repetition" $index_repetition "dataset" $value_dataset "config" $value_config "type" "nlu" | toJSON) $inc) -}}
{{- else if has (datasource "mapping").configurations.core $value_config -}}
{{ $inc = (coll.Append (dict "index_repetition" $index_repetition "dataset" $value_dataset "config" $value_config "type" "core" | toJSON) $inc) -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- join $inc "," -}}
]}
@@ -0,0 +1,13 @@
{{- /*
The template reads a PR comment and gets the dataset branch for the training-data
repository.
*/ -}}
{{- $config := ((datasource "github").body | regexp.Find "```(?s)(.*)```" | regexp.ReplaceLiteral "```.*|\r" "" | yaml | toJSON | json) -}}
{{- $dataset_branch := "main" -}}
{{- /* if a branch name for dataset repository is not defined use the main branch */ -}}
{{- if has $config "dataset_branch" -}}
{{- $dataset_branch = $config.dataset_branch -}}
{{- end -}}
export DATASET_BRANCH="{{ $dataset_branch }}"
@@ -0,0 +1,159 @@
{{- /*
The template reads a file with a report (the report file is available
as an artifact in the model regression tests workflow) and returns
a markdown table with a summary of the tests.
*/ -}}
{{- /*
The print_result_nlu template returns data depends on available fields.
*/ -}}
{{ define "print_result_nlu" -}}
{{- if and (has (index .branch "micro avg") "f1-score") (has (index .main "micro avg") "f1-score") -}}
{{ printf "%.4f" (index (index .branch "micro avg") "f1-score") }} ({{ printf "%.2f" ((index (index .main "micro avg") "f1-score") | math.Sub (index (index .branch "micro avg") "f1-score")) }})
{{- else if and (has .branch "accuracy") (has .main "accuracy") -}}
{{ printf "%.4f" .branch.accuracy }} ({{ printf "%.2f" (.main.accuracy | math.Sub .branch.accuracy) }})
{{- else if and (has .branch "accuracy") (has (index .main "micro avg") "f1-score") -}}
{{ printf "%.4f" .branch.accuracy }} ({{ printf "%.2f" ((index (index .main "micro avg") "f1-score") | math.Sub .branch.accuracy) }})
{{- else if and (has (index .branch "micro avg") "f1-score") (has .main "accuracy") -}}
{{ printf "%.4f" (index (index .branch "micro avg") "f1-score") }} ({{ printf "%.2f" (.main.accuracy | math.Sub (index (index .branch "micro avg") "f1-score")) }})
{{- else if (has .branch "accuracy") -}}
{{ printf "%.4f" .branch.accuracy }} (`no data`)
{{- else if has (index .branch "micro avg") "f1-score" -}}
{{ printf "%.4f" (index (index .branch "micro avg") "f1-score") }} (`no data`)
{{- else -}}
`no data`
{{- end -}}
{{- end -}}
{{- /*
The print_result_core template returns data depends on available fields.
*/ -}}
{{ define "print_result_core_micro_avg" -}}
{{- if and (has (index .branch "micro avg") "f1-score") (has (index .main "micro avg") "f1-score") -}}
{{ printf "%.4f" (index (index .branch "micro avg") "f1-score") }} ({{ printf "%.2f" ((index (index .main "micro avg") "f1-score") | math.Sub (index (index .branch "micro avg") "f1-score")) }})
{{- else if and (has .branch "accuracy") (has .main "accuracy") -}}
{{ printf "%.4f" .branch.accuracy }} ({{ printf "%.2f" (.main.accuracy | math.Sub .branch.accuracy) }})
{{- else if and (has .branch "accuracy") (has (index .main "micro avg") "f1-score") -}}
{{ printf "%.4f" .branch.accuracy }} ({{ printf "%.2f" ((index (index .main "micro avg") "f1-score") | math.Sub .branch.accuracy) }})
{{- else if and (has (index .branch "micro avg") "f1-score") (has .main "accuracy") -}}
{{ printf "%.4f" (index (index .branch "micro avg") "f1-score") }} ({{ printf "%.2f" (.main.accuracy | math.Sub (index (index .branch "micro avg") "f1-score")) }})
{{- else if (has .branch "accuracy") -}}
{{ printf "%.4f" .branch.accuracy }} (`no data`)
{{- else if has (index .branch "micro avg") "f1-score" -}}
{{ printf "%.4f" (index (index .branch "micro avg") "f1-score") }} (`no data`)
{{- else -}}
`no data`
{{- end -}}
{{- end -}}
{{ define "print_result_core_conversation_accuracy" -}}
{{- if and (has (index .branch "conversation_accuracy") "accuracy") (has (index .main "conversation_accuracy") "accuracy") -}}
{{ printf "%.4f" (index (index .branch "conversation_accuracy") "accuracy") }} ({{ printf "%.2f" ((index (index .main "conversation_accuracy") "accuracy") | math.Sub (index (index .branch "conversation_accuracy") "accuracy")) }})
{{- else if has (index .branch "conversation_accuracy") "accuracy" -}}
{{ printf "%.4f" (index (index .branch "conversation_accuracy") "accuracy") }} (`no data`)
{{- else -}}
`no data`
{{- end -}}
{{- end -}}
{{ define "print_table_nlu" }}
{{- $available_types := (index .results_for_dataset | jsonpath `@..type`) -}}
{{- if isKind "string" $available_types }}{{- $available_types = (index .results_for_dataset | jsonpath `@..type` | slice) -}}{{- end -}}
{{- if has $available_types "nlu" -}}
| Configuration | Intent Classification Micro F1 | Entity Recognition Micro F1 | Response Selection Micro F1 |
|---------------|-----------------|-----------------|-------------------|
{{ range $config_name, $config_data_array := .results_for_dataset -}}
{{ range $config_data := $config_data_array }}
{{- if eq $config_data.type "nlu" -}}
| `{{ $config_name }}`<br> test: `{{ $config_data.test_run_time }}`, train: `{{ $config_data.train_run_time }}`, total: `{{ $config_data.total_run_time }}`|
{{- if has $config_data "intent_classification" -}}
{{- $intent_class_main := dict -}}
{{- if has $.results_for_dataset_main $config_name -}}
{{- $intent_class_main = (index (index $.results_for_dataset_main $config_name) 0).intent_classification -}}
{{- end -}}
{{- $intent_class := $config_data.intent_classification -}}
{{ template "print_result_nlu" (dict "branch" $intent_class "main" $intent_class_main) }}|
{{- else -}}
`no data`|
{{- end -}}
{{- if has $config_data "entity_prediction" -}}
{{- $entity_class_main := dict -}}
{{- if has $.results_for_dataset_main $config_name -}}
{{- $entity_class_main = (index (index $.results_for_dataset_main $config_name) 0).entity_prediction -}}
{{- end -}}
{{- $entity_class := $config_data.entity_prediction -}}
{{ template "print_result_nlu" (dict "branch" $entity_class "main" $entity_class_main) }}|
{{- else -}}
`no data`|
{{- end -}}
{{- if has $config_data "response_selection" -}}
{{- $response_class_main := dict -}}
{{- if has $.results_for_dataset_main $config_name -}}
{{- $response_class_main = (index (index $.results_for_dataset_main $config_name) 0).response_selection -}}
{{- end -}}
{{- $response_class := $config_data.response_selection -}}
{{ template "print_result_nlu" (dict "branch" $response_class "main" $response_class_main) }}|
{{- else -}}
`no data`|
{{- end }}
{{end}}
{{- end}}
{{- end}}
{{- end -}}
{{- end -}}
{{- define "print_table_core" -}}
{{- $available_types := (index .results_for_dataset | jsonpath `@..type`) -}}
{{- if isKind "string" $available_types }}{{- $available_types = (index .results_for_dataset | jsonpath `@..type` | slice) -}}{{- end -}}
{{- if has $available_types "core" -}}
| Dialog Policy Configuration | Action Level Micro Avg. F1 | Conversation Level Accuracy | Run Time Train | Run Time Test |
|---------------|-----------------|-----------------|-------------------|-------------------|
{{ range $config_name, $config_data_array := .results_for_dataset -}}
{{ range $config_data := $config_data_array }}
{{- if eq $config_data.type "core" -}}
| `{{ $config_name }}` |
{{- if has $config_data "story_prediction" -}}
{{- $story_prediction_main := dict -}}
{{- if has $.results_for_dataset_main $config_name -}}
{{- $story_prediction_main = (index (index $.results_for_dataset_main $config_name) 0).story_prediction -}}
{{- end -}}
{{- $story_prediction := $config_data.story_prediction -}}
{{ template "print_result_core_micro_avg" (dict "branch" $story_prediction "main" $story_prediction_main) }}|
{{- else -}}
`no data`|
{{- end -}}
{{- if has $config_data "story_prediction" -}}
{{- $story_prediction_main := dict -}}
{{- if has $.results_for_dataset_main $config_name -}}
{{- $story_prediction_main = (index (index $.results_for_dataset_main $config_name) 0).story_prediction -}}
{{- end -}}
{{- $story_prediction := index $config_data.story_prediction -}}
{{ template "print_result_core_conversation_accuracy" (dict "branch" $story_prediction "main" $story_prediction_main) }}|
{{- else -}}
`no data`|
{{- end -}}
`{{ $config_data.train_run_time }}`| `{{ $config_data.test_run_time }}`|
{{ end }}
{{- end}}
{{- end}}
{{- end -}}
{{- end -}}
{{- $results_main := (datasource "results_main") -}}
{{ range $dataset, $results_for_dataset := (datasource "data")}}
{{ $results_for_dataset_main := (index $results_main $dataset) -}}
{{ $content_dicts := index $results_for_dataset (index (keys $results_for_dataset) 0) -}}
{{ $one_content_dict := index $content_dicts 0 -}}
{{- if ($one_content_dict).external_dataset_repository -}}
Dataset: `{{$dataset}}`, Dataset repository branch: `{{ ($one_content_dict).dataset_repository_branch }}` (external repository), commit: `{{ ($one_content_dict).dataset_commit }}`
Configuration repository branch: `{{ ($one_content_dict).config_repository_branch }}`
{{ else -}}
Dataset: `{{$dataset}}`, Dataset repository branch: `{{ ($one_content_dict).dataset_repository_branch }}`, commit: `{{ ($one_content_dict).dataset_commit }}`
{{ end -}}
{{ template "print_table_nlu" (dict "results_for_dataset" $results_for_dataset "results_for_dataset_main" $results_for_dataset_main) }}
{{ template "print_table_core" (dict "results_for_dataset" $results_for_dataset "results_for_dataset_main" $results_for_dataset_main) }}
{{- end }}
@@ -0,0 +1,23 @@
# Configuration for Rasa NLU.
# https://rasa.com/docs/rasa/nlu/components/
language: en
pipeline:
- name: WhitespaceTokenizer
- name: LanguageModelFeaturizer
alias: "lmf"
- name: RegexFeaturizer
alias: "rf"
- name: LexicalSyntacticFeaturizer
alias: "lsf"
- name: DIETClassifier
epochs: 50
random_seed: 42
- name: ResponseSelector
epochs: 100
num_transformer_layers: 2
transformer_size: 256
hidden_layers_size:
text: []
label: []
random_seed: 42
featurizers: ["lmf"]
@@ -0,0 +1,3 @@
{
"body": "/modeltest\r\n\r\n```yml\r\ndataset_branch: \"test_dataset_branch\"\r\ninclude:\r\n - dataset: [\"financial-demo\"]\r\n config: [\"TEST\"]\r\n ```\r\n\r\n<!-- comment-id:comment_configuration -->"
}
@@ -0,0 +1,3 @@
{
"body": "/modeltest\r\n\r\n```yml\r\ninclude:\r\n - dataset: [\"financial-demo\"]\r\n config: [\"TEST\"]\r\n ```\r\n\r\n<!-- comment-id:comment_configuration -->"
}
+120
View File
@@ -0,0 +1,120 @@
{
"search_transactions": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1,
"confused_with": {}
},
"greet": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 2,
"confused_with": {}
},
"out_of_scope": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1,
"confused_with": {}
},
"thankyou": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1,
"confused_with": {}
},
"help": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 2,
"confused_with": {}
},
"inform": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1,
"confused_with": {}
},
"goodbye": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1,
"confused_with": {}
},
"affirm": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 3,
"confused_with": {}
},
"pay_cc": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 2,
"confused_with": {}
},
"check_balance": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 5,
"confused_with": {}
},
"deny": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1,
"confused_with": {}
},
"ask_transfer_charge": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1,
"confused_with": {}
},
"transfer_money": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 3,
"confused_with": {}
},
"check_recipients": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 2,
"confused_with": {}
},
"check_earnings": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 2,
"confused_with": {}
},
"accuracy": 1.0,
"macro avg": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 28
},
"weighted avg": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 28
}
}
@@ -0,0 +1,303 @@
{
"RasaHQ/financial-demo": {
"BERT + DIET(bow) + ResponseSelector(bow)": [{
"accelerator_type": "GPU",
"config_repository": "training-data",
"config_repository_branch": "main",
"dataset_commit": "52a3ad3eb5292d56542687e23b06703431f15ead",
"dataset_repository_branch": "fix-model-regression-tests",
"entity_prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
"precision": 0.8,
"recall": 0.7,
"support": 14
},
"micro avg": {
"f1-score": 0.8333333333333333,
"precision": 1.0,
"recall": 0.7142857142857143,
"support": 14
},
"weighted avg": {
"f1-score": 0.738095238095238,
"precision": 0.7857142857142857,
"recall": 0.7142857142857143,
"support": 14
}
},
"external_dataset_repository": true,
"intent_classification": {
"accuracy": 1.0,
"macro avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 28
},
"weighted avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 28
}
},
"test_run_time": "35s",
"total_run_time": "2m2s",
"train_run_time": "1m28s",
"type": "nlu"
}],
"BERT + DIET(seq) + ResponseSelector(t2t)": [{
"accelerator_type": "GPU",
"config_repository": "training-data",
"config_repository_branch": "main",
"dataset_commit": "52a3ad3eb5292d56542687e23b06703431f15ead",
"dataset_repository_branch": "fix-model-regression-tests",
"entity_prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
"precision": 0.8,
"recall": 0.7,
"support": 14
},
"micro avg": {
"f1-score": 0.8333333333333333,
"precision": 1.0,
"recall": 0.7142857142857143,
"support": 14
},
"weighted avg": {
"f1-score": 0.738095238095238,
"precision": 0.7857142857142857,
"recall": 0.7142857142857143,
"support": 14
}
},
"external_dataset_repository": true,
"intent_classification": {
"accuracy": 1.0,
"macro avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 28
},
"weighted avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 28
}
},
"test_run_time": "55s",
"total_run_time": "2m8s",
"train_run_time": "1m14s",
"type": "nlu"
}],
"Rules + Memo + TED": [{
"accelerator_type": "GPU",
"config_repository": "training-data",
"config_repository_branch": "main",
"dataset_commit": "52a3ad3eb5292d56542687e23b06703431f15ead",
"dataset_repository_branch": "fix-model-regression-tests",
"external_dataset_repository": true,
"story_prediction": {
"accuracy": 1.0,
"conversation_accuracy": {
"accuracy": 1.0,
"correct": 48,
"total": 48,
"with_warnings": 0
},
"macro avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 317
},
"weighted avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 317
}
},
"test_run_time": "51s",
"total_run_time": "8m15s",
"train_run_time": "7m24s",
"type": "core"
}]
},
"RasaHQ/retail-demo": {
"BERT + DIET(bow) + ResponseSelector(bow)": [{
"accelerator_type": "GPU",
"config_repository": "training-data",
"config_repository_branch": "main",
"dataset_commit": "8226b51b4312aa4d3723098cf6d4028feea040b4",
"dataset_repository_branch": "fix-model-regression-tests",
"entity_prediction": {
"macro avg": {
"f1-score": 0.25,
"precision": 0.25,
"recall": 0.25,
"support": 6
},
"micro avg": {
"f1-score": 0.2857142857142857,
"precision": 1.0,
"recall": 0.16666666666666666,
"support": 6
},
"weighted avg": {
"f1-score": 0.16666666666666666,
"precision": 0.16666666666666666,
"recall": 0.16666666666666666,
"support": 6
}
},
"external_dataset_repository": true,
"intent_classification": {
"macro avg": {
"f1-score": 0.8,
"precision": 0.8,
"recall": 0.85,
"support": 16
},
"micro avg": {
"f1-score": 0.8387096774193549,
"precision": 0.8666666666666667,
"recall": 0.8125,
"support": 16
},
"weighted avg": {
"f1-score": 0.8125,
"precision": 0.875,
"recall": 0.8125,
"support": 16
}
},
"test_run_time": "29s",
"total_run_time": "1m16s",
"train_run_time": "47s",
"type": "nlu"
}],
"BERT + DIET(seq) + ResponseSelector(t2t)": [{
"accelerator_type": "GPU",
"config_repository": "training-data",
"config_repository_branch": "main",
"dataset_commit": "8226b51b4312aa4d3723098cf6d4028feea040b4",
"dataset_repository_branch": "fix-model-regression-tests",
"entity_prediction": {
"macro avg": {
"f1-score": 0.25,
"precision": 0.25,
"recall": 0.25,
"support": 6
},
"micro avg": {
"f1-score": 0.2857142857142857,
"precision": 1.0,
"recall": 0.16666666666666666,
"support": 6
},
"weighted avg": {
"f1-score": 0.16666666666666666,
"precision": 0.16666666666666666,
"recall": 0.16666666666666666,
"support": 6
}
},
"external_dataset_repository": true,
"intent_classification": {
"accuracy": 0.875,
"macro avg": {
"f1-score": 0.8300000000000001,
"precision": 0.8166666666666667,
"recall": 0.85,
"support": 16
},
"weighted avg": {
"f1-score": 0.85,
"precision": 0.8333333333333333,
"recall": 0.875,
"support": 16
}
},
"test_run_time": "56s",
"total_run_time": "2m2s",
"train_run_time": "1m6s",
"type": "nlu"
}],
"Rules + Memo": [{
"accelerator_type": "GPU",
"config_repository": "training-data",
"config_repository_branch": "main",
"dataset_commit": "8226b51b4312aa4d3723098cf6d4028feea040b4",
"dataset_repository_branch": "fix-model-regression-tests",
"external_dataset_repository": true,
"story_prediction": {
"conversation_accuracy": {
"accuracy": 0.8888888888888888,
"correct": 8,
"total": 9,
"with_warnings": 0
},
"macro avg": {
"f1-score": 0.9663698541747322,
"precision": 1.0,
"recall": 0.946007696007696,
"support": 67
},
"micro avg": {
"f1-score": 0.9692307692307692,
"precision": 1.0,
"recall": 0.9402985074626866,
"support": 67
},
"weighted avg": {
"f1-score": 0.9656317714563074,
"precision": 1.0,
"recall": 0.9402985074626866,
"support": 67
}
},
"test_run_time": "10s",
"total_run_time": "19s",
"train_run_time": "10s",
"type": "core"
}],
"Rules + Memo + TED": [{
"accelerator_type": "GPU",
"config_repository": "training-data",
"config_repository_branch": "main",
"dataset_commit": "8226b51b4312aa4d3723098cf6d4028feea040b4",
"dataset_repository_branch": "fix-model-regression-tests",
"external_dataset_repository": true,
"story_prediction": {
"accuracy": 1.0,
"conversation_accuracy": {
"accuracy": 1.0,
"correct": 9,
"total": 9,
"with_warnings": 0
},
"macro avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 67
},
"weighted avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 67
}
},
"test_run_time": "31s",
"total_run_time": "4m57s",
"train_run_time": "4m27s",
"type": "core"
}]
}
}
@@ -0,0 +1,70 @@
{
"RasaHQ/retail-demo": {
"Rules + Memo + TED": [{
"accelerator_type": "GPU",
"config_repository": "training-data",
"config_repository_branch": "main",
"dataset_commit": "8226b51b4312aa4d3723098cf6d4028feea040b4",
"dataset_repository_branch": "fix-model-regression-tests",
"external_dataset_repository": true,
"story_prediction": {
"accuracy": 1.0,
"conversation_accuracy": {
"accuracy": 1.0,
"correct": 9,
"total": 9,
"with_warnings": 0
},
"macro avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 67
},
"weighted avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 67
}
},
"test_run_time": "31s",
"total_run_time": "4m57s",
"train_run_time": "4m27s",
"type": "core"
},
{
"accelerator_type": "GPU",
"config_repository": "training-data",
"config_repository_branch": "main",
"dataset_commit": "8226b51b4312aa4d3723098cf6d4028feea040b4",
"dataset_repository_branch": "fix-model-regression-tests",
"external_dataset_repository": true,
"story_prediction": {
"accuracy": 1.0,
"conversation_accuracy": {
"accuracy": 1.0,
"correct": 9,
"total": 9,
"with_warnings": 0
},
"macro avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 67
},
"weighted avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 67
}
},
"test_run_time": "41s",
"total_run_time": "5m57s",
"train_run_time": "5m27s",
"type": "core"
}]
}
}
@@ -0,0 +1,98 @@
{
"RasaHQ/financial-demo": {
"BERT + DIET(seq) + ResponseSelector(t2t)": [{
"accelerator_type": "CPU",
"config_repository": "training-data",
"config_repository_branch": "main",
"dataset_commit": "52a3ad3eb5292d56542687e23b06703431f15ead",
"dataset_repository_branch": "fix-model-regression-tests",
"entity_prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
"precision": 0.8,
"recall": 0.7,
"support": 14
},
"micro avg": {
"f1-score": 0.8333333333333333,
"precision": 1.0,
"recall": 0.7142857142857143,
"support": 14
},
"weighted avg": {
"f1-score": 0.738095238095238,
"precision": 0.7857142857142857,
"recall": 0.7142857142857143,
"support": 14
}
},
"external_dataset_repository": true,
"intent_classification": {
"accuracy": 1.0,
"macro avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 28
},
"weighted avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 28
}
},
"test_run_time": "1m29s",
"total_run_time": "4m24s",
"train_run_time": "2m55s",
"type": "nlu"
},
{
"accelerator_type": "CPU",
"config_repository": "training-data",
"config_repository_branch": "main",
"dataset_commit": "52a3ad3eb5292d56542687e23b06703431f15ead",
"dataset_repository_branch": "fix-model-regression-tests",
"entity_prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
"precision": 0.8,
"recall": 0.7,
"support": 14
},
"micro avg": {
"f1-score": 0.8333333333333333,
"precision": 1.0,
"recall": 0.7142857142857143,
"support": 14
},
"weighted avg": {
"f1-score": 0.738095238095238,
"precision": 0.7857142857142857,
"recall": 0.7142857142857143,
"support": 14
}
},
"external_dataset_repository": true,
"intent_classification": {
"accuracy": 1.0,
"macro avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 28
},
"weighted avg": {
"f1-score": 1.0,
"precision": 1.0,
"recall": 1.0,
"support": 28
}
},
"test_run_time": "2m29s",
"total_run_time": "5m24s",
"train_run_time": "3m55s",
"type": "nlu"
}]
}
}
+101
View File
@@ -0,0 +1,101 @@
from copy import deepcopy
import sys
import tempfile
from pathlib import Path
import pytest
from ruamel.yaml import YAML
sys.path.append(".github/scripts")
import download_pretrained # noqa: E402
CONFIG_FPATH = Path(__file__).parent / "test_data" / "bert_diet_response2t.yml"
def test_download_pretrained_lmf_exists_no_params():
lmf_specs = download_pretrained.get_model_name_and_weights_from_config(CONFIG_FPATH)
assert lmf_specs[0].model_name == "bert"
assert lmf_specs[0].model_weights == "rasa/LaBSE"
def test_download_pretrained_lmf_exists_with_model_name():
yaml = YAML(typ="safe")
config = yaml.load(CONFIG_FPATH)
steps = config.get("pipeline", [])
step = list(filter(lambda x: x["name"] == download_pretrained.COMP_NAME, steps))[0]
step["model_name"] = "roberta"
step["cache_dir"] = "/this/dir"
with tempfile.NamedTemporaryFile("w+") as fp:
yaml.dump(config, fp)
fp.seek(0)
lmf_specs = download_pretrained.get_model_name_and_weights_from_config(fp.name)
assert lmf_specs[0].model_name == "roberta"
assert lmf_specs[0].model_weights == "roberta-base"
assert lmf_specs[0].cache_dir == "/this/dir"
def test_download_pretrained_unknown_model_name():
yaml = YAML(typ="safe")
config = yaml.load(CONFIG_FPATH)
steps = config.get("pipeline", [])
step = list(filter(lambda x: x["name"] == download_pretrained.COMP_NAME, steps))[0]
step["model_name"] = "unknown"
with tempfile.NamedTemporaryFile("w+") as fp:
yaml.dump(config, fp)
fp.seek(0)
with pytest.raises(KeyError):
download_pretrained.get_model_name_and_weights_from_config(fp.name)
def test_download_pretrained_multiple_model_names():
yaml = YAML(typ="safe")
config = yaml.load(CONFIG_FPATH)
steps = config.get("pipeline", [])
step = list(filter(lambda x: x["name"] == download_pretrained.COMP_NAME, steps))[0]
step_new = deepcopy(step)
step_new["model_name"] = "roberta"
steps.append(step_new)
with tempfile.NamedTemporaryFile("w+") as fp:
yaml.dump(config, fp)
fp.seek(0)
lmf_specs = download_pretrained.get_model_name_and_weights_from_config(fp.name)
assert len(lmf_specs) == 2
assert lmf_specs[1].model_name == "roberta"
def test_download_pretrained_with_model_name_and_nondefault_weight():
yaml = YAML(typ="safe")
config = yaml.load(CONFIG_FPATH)
steps = config.get("pipeline", [])
step = list(filter(lambda x: x["name"] == download_pretrained.COMP_NAME, steps))[0]
step["model_name"] = "bert"
step["model_weights"] = "bert-base-uncased"
with tempfile.NamedTemporaryFile("w+") as fp:
yaml.dump(config, fp)
fp.seek(0)
lmf_specs = download_pretrained.get_model_name_and_weights_from_config(fp.name)
assert lmf_specs[0].model_name == "bert"
assert lmf_specs[0].model_weights == "bert-base-uncased"
def test_download_pretrained_lmf_doesnt_exists():
yaml = YAML(typ="safe")
config = yaml.load(CONFIG_FPATH)
steps = config.get("pipeline", [])
step = list(filter(lambda x: x["name"] == download_pretrained.COMP_NAME, steps))[0]
steps.remove(step)
with tempfile.NamedTemporaryFile("w+") as fp:
yaml.dump(config, fp)
fp.seek(0)
lmf_specs = download_pretrained.get_model_name_and_weights_from_config(fp.name)
assert len(lmf_specs) == 0
@@ -0,0 +1,27 @@
import pathlib
import subprocess
import pytest
from typing import Text
TEMPLATE_FPATH = ".github/templates/model_regression_test_read_dataset_branch.tmpl"
REPO_DIR = pathlib.Path("").absolute()
TEST_DATA_DIR = str(pathlib.Path(__file__).parent / "test_data")
DEFAULT_DATASET_BRANCH = "main"
@pytest.mark.parametrize(
"comment_body_file,expected_dataset_branch",
[
("comment_body.json", "test_dataset_branch"),
("comment_body_no_dataset_branch.json", DEFAULT_DATASET_BRANCH),
],
)
def test_read_dataset_branch(comment_body_file: Text, expected_dataset_branch: Text):
cmd = (
"gomplate "
f"-d github={TEST_DATA_DIR}/{comment_body_file} "
f"-f {TEMPLATE_FPATH}"
)
output = subprocess.check_output(cmd.split(" "), cwd=REPO_DIR)
output = output.decode("utf-8").strip()
assert output == f'export DATASET_BRANCH="{expected_dataset_branch}"'
@@ -0,0 +1,50 @@
import pathlib
import subprocess
TEMPLATE_FPATH = ".github/templates/model_regression_test_results.tmpl"
REPO_DIR = pathlib.Path("").absolute()
TEST_DATA_DIR = str(pathlib.Path(__file__).parent / "test_data")
def test_comment_nlu():
cmd = (
"gomplate "
f"-d data={TEST_DATA_DIR}/report_listformat_nlu.json "
f"-d results_main={TEST_DATA_DIR}/report-on-schedule-2022-02-02.json "
f"-f {TEMPLATE_FPATH}"
)
output = subprocess.check_output(cmd.split(" "), cwd=REPO_DIR)
output = output.decode("utf-8")
expected_output = """
Dataset: `RasaHQ/financial-demo`, Dataset repository branch: `fix-model-regression-tests` (external repository), commit: `52a3ad3eb5292d56542687e23b06703431f15ead`
Configuration repository branch: `main`
| Configuration | Intent Classification Micro F1 | Entity Recognition Micro F1 | Response Selection Micro F1 |
|---------------|-----------------|-----------------|-------------------|
| `BERT + DIET(seq) + ResponseSelector(t2t)`<br> test: `1m29s`, train: `2m55s`, total: `4m24s`|1.0000 (0.00)|0.8333 (0.00)|`no data`|
| `BERT + DIET(seq) + ResponseSelector(t2t)`<br> test: `2m29s`, train: `3m55s`, total: `5m24s`|1.0000 (0.00)|0.8333 (0.00)|`no data`|
""" # noqa E501
assert output == expected_output
def test_comment_core():
cmd = (
"gomplate "
f"-d data={TEST_DATA_DIR}/report_listformat_core.json "
f"-d results_main={TEST_DATA_DIR}/report-on-schedule-2022-02-02.json "
f"-f {TEMPLATE_FPATH}"
)
output = subprocess.check_output(cmd.split(" "), cwd=REPO_DIR)
output = output.decode("utf-8")
expected_output = """
Dataset: `RasaHQ/retail-demo`, Dataset repository branch: `fix-model-regression-tests` (external repository), commit: `8226b51b4312aa4d3723098cf6d4028feea040b4`
Configuration repository branch: `main`
| Dialog Policy Configuration | Action Level Micro Avg. F1 | Conversation Level Accuracy | Run Time Train | Run Time Test |
|---------------|-----------------|-----------------|-------------------|-------------------|
| `Rules + Memo + TED` |1.0000 (0.00)|1.0000 (0.00)|`4m27s`| `31s`|
| `Rules + Memo + TED` |1.0000 (0.00)|1.0000 (0.00)|`5m27s`| `41s`|
""" # noqa E501
assert output == expected_output
+208
View File
@@ -0,0 +1,208 @@
import sys
sys.path.append(".github/scripts")
from mr_generate_summary import combine_result # noqa: E402
RESULT1 = {
"financial-demo": {
"BERT + DIET(bow) + ResponseSelector(bow)": [
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
}
},
"test_run_time": "47s",
}
]
}
}
def test_same_ds_different_config():
result2 = {
"financial-demo": {
"Sparse + DIET(bow) + ResponseSelector(bow)": [
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.88,
}
},
"test_run_time": "47s",
}
]
}
}
expected_combined = {
"financial-demo": {
"BERT + DIET(bow) + ResponseSelector(bow)": [
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
}
},
"test_run_time": "47s",
}
],
"Sparse + DIET(bow) + ResponseSelector(bow)": [
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.88,
}
},
"test_run_time": "47s",
}
],
}
}
actual_combined = combine_result(RESULT1, result2)
assert actual_combined == expected_combined
actual_combined = combine_result(result2, RESULT1)
assert actual_combined == expected_combined
def test_different_ds_same_config():
result2 = {
"Carbon Bot": {
"Sparse + DIET(bow) + ResponseSelector(bow)": [
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.88,
}
},
"test_run_time": "47s",
}
]
}
}
expected_combined = {
"financial-demo": {
"BERT + DIET(bow) + ResponseSelector(bow)": [
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
}
},
"test_run_time": "47s",
}
],
},
"Carbon Bot": {
"Sparse + DIET(bow) + ResponseSelector(bow)": [
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.88,
}
},
"test_run_time": "47s",
}
]
},
}
actual_combined = combine_result(RESULT1, result2)
assert actual_combined == expected_combined
actual_combined = combine_result(result2, RESULT1)
assert actual_combined == expected_combined
def test_start_empty():
result2 = {}
expected_combined = {
"financial-demo": {
"BERT + DIET(bow) + ResponseSelector(bow)": [
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
}
},
"test_run_time": "47s",
}
]
}
}
actual_combined = combine_result(RESULT1, result2)
assert actual_combined == expected_combined
actual_combined = combine_result(result2, RESULT1)
assert actual_combined == expected_combined
def test_combine_result_repetition():
expected_combined = {
"financial-demo": {
"BERT + DIET(bow) + ResponseSelector(bow)": [
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
}
},
"test_run_time": "47s",
},
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
}
},
"test_run_time": "47s",
},
]
}
}
actual_combined = combine_result(RESULT1, RESULT1)
assert actual_combined == expected_combined
def test_combine_result_repetition_3times():
expected_combined = {
"financial-demo": {
"BERT + DIET(bow) + ResponseSelector(bow)": [
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
}
},
"test_run_time": "47s",
},
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
}
},
"test_run_time": "47s",
},
{
"Entity Prediction": {
"macro avg": {
"f1-score": 0.7333333333333333,
}
},
"test_run_time": "47s",
},
]
}
}
tmp_combined = combine_result(RESULT1, RESULT1)
actual_combined = combine_result(tmp_combined, RESULT1)
assert actual_combined == expected_combined
actual_combined = combine_result(RESULT1, tmp_combined)
assert actual_combined == expected_combined
+132
View File
@@ -0,0 +1,132 @@
import os
from pathlib import Path
import sys
from unittest import mock
sys.path.append(".github/scripts")
from mr_publish_results import ( # noqa: E402
prepare_ml_metric,
prepare_ml_metrics,
transform_to_seconds,
generate_json,
prepare_datadog_tags,
)
EXAMPLE_CONFIG = "Sparse + BERT + DIET(seq) + ResponseSelector(t2t)"
EXAMPLE_DATASET_NAME = "financial-demo"
ENV_VARS = {
"BRANCH": "my-branch",
"PR_ID": "10927",
"PR_URL": "https://github.com/RasaHQ/rasa/pull/10856/",
"GITHUB_EVENT_NAME": "pull_request",
"GITHUB_RUN_ID": "1882718340",
"GITHUB_SHA": "abc",
"GITHUB_WORKFLOW": "CI - Model Regression",
"IS_EXTERNAL": "false",
"DATASET_REPOSITORY_BRANCH": "main",
"CONFIG": EXAMPLE_CONFIG,
"DATASET_NAME": EXAMPLE_DATASET_NAME,
"CONFIG_REPOSITORY_BRANCH": "main",
"DATASET_COMMIT": "52a3ad3eb5292d56542687e23b06703431f15ead",
"ACCELERATOR_TYPE": "CPU",
"TEST_RUN_TIME": "1m54s",
"TRAIN_RUN_TIME": "4m4s",
"TOTAL_RUN_TIME": "5m58s",
"TYPE": "nlu",
"INDEX_REPETITION": "0",
"HOST_NAME": "github-runner-2223039222-22df222fcd-2cn7d",
}
@mock.patch.dict(os.environ, ENV_VARS, clear=True)
def test_generate_json():
f = Path(__file__).parent / "test_data" / "intent_report.json"
result = generate_json(f, task="intent_classification", data={})
assert isinstance(result[EXAMPLE_DATASET_NAME][EXAMPLE_CONFIG], list)
actual = result[EXAMPLE_DATASET_NAME][EXAMPLE_CONFIG][0]["intent_classification"]
expected = {
"accuracy": 1.0,
"weighted avg": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 28,
},
"macro avg": {"precision": 1.0, "recall": 1.0, "f1-score": 1.0, "support": 28},
}
assert expected == actual
def test_transform_to_seconds():
assert 87.0 == transform_to_seconds("1m27s")
assert 87.3 == transform_to_seconds("1m27.3s")
assert 27.0 == transform_to_seconds("27s")
assert 3627.0 == transform_to_seconds("1h27s")
assert 3687.0 == transform_to_seconds("1h1m27s")
def test_prepare_ml_model_perf_metrics():
results = [
{
"macro avg": {
"precision": 0.8,
"recall": 0.8,
"f1-score": 0.8,
"support": 14,
},
"micro avg": {
"precision": 1.0,
"recall": 0.7857142857142857,
"f1-score": 0.88,
"support": 14,
},
"file_name": "DIETClassifier_report.json",
"task": "Entity Prediction",
},
{
"accuracy": 1.0,
"weighted avg": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 28,
},
"macro avg": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 28,
},
"file_name": "intent_report.json",
"task": "Intent Classification",
},
]
metrics_ml = prepare_ml_metrics(results)
assert len(metrics_ml) == 17
def test_prepare_ml_model_perf_metrics_simple():
result = {
"accuracy": 1.0,
"weighted avg": {"precision": 1, "recall": 1.0, "f1-score": 1, "support": 28},
"task": "Intent Classification",
}
metrics_ml = prepare_ml_metric(result)
assert len(metrics_ml) == 5
for _, v in metrics_ml.items():
assert isinstance(v, float)
key, value = "Intent Classification.accuracy", 1.0
assert key in metrics_ml and value == metrics_ml[key]
key, value = "Intent Classification.weighted avg.f1-score", 1.0
assert key in metrics_ml and value == metrics_ml[key]
@mock.patch.dict(os.environ, ENV_VARS, clear=True)
def test_prepare_datadog_tags():
tags_list = prepare_datadog_tags()
assert "dataset:financial-demo" in tags_list
+27
View File
@@ -0,0 +1,27 @@
import os
import sys
from unittest import mock
import pytest
sys.path.append(".github/scripts")
import validate_cpu # noqa: E402
import validate_gpus # noqa: E402
ENV_VARS = {
"CUDA_VISIBLE_DEVICES": "-1",
}
@mock.patch.dict(os.environ, ENV_VARS, clear=True)
def test_validate_cpu_succeeds_when_there_are_no_gpus():
validate_cpu.check_gpu_not_available()
@mock.patch.dict(os.environ, ENV_VARS, clear=True)
def test_validate_gpus_exits_when_there_are_no_gpus():
# This unit test assumes that unit tests are run on a CPU
with pytest.raises(SystemExit) as pytest_wrapped_e:
validate_gpus.check_gpu_available()
assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 1
+22
View File
@@ -0,0 +1,22 @@
name: Automatic PR Merger
on:
push: {} # update PR when base branch is updated
jobs:
# thats's all. single step is needed - if PR is mergeable according to
# branch protection rules it will be merged automatically
mergepal:
runs-on: ubuntu-24.04
if: github.repository == 'RasaHQ/rasa'
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: rasahq/update-pr-branch@f7012036a6d5659cfbc37f180716963511e81f95
with:
token: ${{ secrets.UPDATE_BRANCH_PAT }}
# required parameter by original action -
# check is already done through protected branches so not needed for us
required_approval_count: 0
# update branch despite failing check runs
require_passed_checks: false
+164
View File
@@ -0,0 +1,164 @@
name: Docs Tests
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, labeled]
concurrency:
group: ci-docs-tests-${{ github.ref }} # branch name
cancel-in-progress: true
env:
DEFAULT_PYTHON_VERSION: "3.10"
jobs:
changes:
name: Check for file changes
runs-on: ubuntu-24.04
outputs:
docs: ${{ steps.filter.outputs.docs }}
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50
id: filter
with:
token: ${{ secrets.GITHUB_TOKEN }}
filters: .github/change_filters.yml
test_documentation:
name: Test Documentation
runs-on: ubuntu-24.04
needs: [changes]
if: needs.changes.outputs.docs == 'true' && false # disabled as docs are moved out in new versions
steps:
- name: Checkout git repository 🕝
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Set up Python ${{ env.DEFAULT_PYTHON_VERSION }} 🐍
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
- name: Set up Node 12.x 🦙
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
with:
node-version: "12.x"
- name: Read Poetry Version 🔢
run: |
echo "POETRY_VERSION=$(scripts/poetry-version.sh)" >> $GITHUB_ENV
shell: bash
- name: Install poetry 🦄
uses: Gr1N/setup-poetry@15821dc8a61bc630db542ae4baf6a7c19a994844 # v8
with:
poetry-version: ${{ env.POETRY_VERSION }}
- name: Load Poetry Cached Libraries ⬇
id: cache-poetry
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: .venv
key: ${{ runner.os }}-poetry-${{ env.POETRY_VERSION }}-${{ env.DEFAULT_PYTHON_VERSION }}-${{ hashFiles('**/poetry.lock') }}-${{ secrets.POETRY_CACHE_VERSION }}
restore-keys: ${{ runner.os }}-poetry-${{ env.DEFAULT_PYTHON_VERSION }}
- name: Clear Poetry cache
if: steps.cache-poetry.outputs.cache-hit == 'true' && contains(github.event.pull_request.labels.*.name, 'tools:clear-poetry-cache-docs-tests')
run: rm -r .venv
- name: Create virtual environment
if: (steps.cache-poetry.outputs.cache-hit != 'true' || contains(github.event.pull_request.labels.*.name, 'tools:clear-poetry-cache-docs-tests'))
run: python -m venv create .venv
- name: Set up virtual environment
if: needs.changes.outputs.docs == 'true'
run: poetry config virtualenvs.in-project true
- name: Load Yarn Cached Packages ⬇
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: docs/node_modules
key: ${{ runner.os }}-yarn-12.x-${{ hashFiles('docs/yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-12.x
- name: Install Dependencies 📦
run: |
sudo apt-get -y install libpq-dev
make install-full install-docs
- name: Run Swagger 🕵️‍♀️
run: |
npm install -g swagger-cli
swagger-cli validate docs/static/spec/action-server.yml
swagger-cli validate docs/static/spec/rasa.yml
- name: Test Docs 🕸
run: make test-docs
documentation_lint:
name: Documentation Linting Checks
runs-on: ubuntu-24.04
needs: [changes]
if: needs.changes.outputs.docs == 'true' && false # disabled as docs are moved out in new versions
steps:
- name: Checkout git repository 🕝
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Set up Python ${{ env.DEFAULT_PYTHON_VERSION }} 🐍
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
- name: Set up Node 12.x 🦙
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
with:
node-version: "12.x"
- name: Read Poetry Version 🔢
run: |
echo "POETRY_VERSION=$(scripts/poetry-version.sh)" >> $GITHUB_ENV
shell: bash
- name: Install poetry 🦄
uses: Gr1N/setup-poetry@15821dc8a61bc630db542ae4baf6a7c19a994844 # v8
with:
poetry-version: ${{ env.POETRY_VERSION }}
- name: Load Poetry Cached Libraries ⬇
id: cache-poetry
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: .venv
key: ${{ runner.os }}-poetry-${{ env.POETRY_VERSION }}-${{ env.DEFAULT_PYTHON_VERSION }}-${{ hashFiles('**/poetry.lock') }}-${{ secrets.POETRY_CACHE_VERSION }}
restore-keys: ${{ runner.os }}-poetry-${{ env.DEFAULT_PYTHON_VERSION }}
- name: Clear Poetry cache
if: steps.cache-poetry.outputs.cache-hit == 'true' && contains(github.event.pull_request.labels.*.name, 'tools:clear-poetry-cache-docs-tests')
run: rm -r .venv
- name: Create virtual environment
if: (steps.cache-poetry.outputs.cache-hit != 'true' || contains(github.event.pull_request.labels.*.name, 'tools:clear-poetry-cache-docs-tests'))
run: python -m venv create .venv
- name: Set up virtual environment
if: needs.changes.outputs.docs == 'true'
run: poetry config virtualenvs.in-project true
- name: Load Yarn Cached Packages ⬇
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: docs/node_modules
key: ${{ runner.os }}-yarn-12.x-${{ hashFiles('docs/yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-12.x
- name: Install Dependencies 📦
run: |
sudo apt-get -y install libpq-dev
make install-full install-docs
- name: Docs Linting Checks 🕸
run: make lint-docs
+76
View File
@@ -0,0 +1,76 @@
name: CI Github Actions
on:
push:
branches:
- main
tags:
- "*"
pull_request:
env:
DEFAULT_PYTHON_VERSION: "3.10"
jobs:
test:
name: Run Tests
runs-on: ubuntu-24.04
#missing matrix
strategy:
fail-fast: false
steps:
- name: Checkout git repository 🕝
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Download gomplate
run: |-
sudo curl -o /usr/local/bin/gomplate -sSL https://github.com/hairyhenderson/gomplate/releases/download/v3.9.0/gomplate_linux-amd64
sudo chmod +x /usr/local/bin/gomplate
- name: Set up Python ${{ env.DEFAULT_PYTHON_VERSION }} 🐍
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
- name: Read Poetry Version 🔢
run: |
echo "POETRY_VERSION=$(scripts/poetry-version.sh)" >> $GITHUB_ENV
shell: bash
- name: Install poetry 🦄
uses: Gr1N/setup-poetry@15821dc8a61bc630db542ae4baf6a7c19a994844 # v8
with:
poetry-version: ${{ env.POETRY_VERSION }}
- name: Load Poetry Cached Libraries ⬇
id: cache-poetry
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: .venv
key: ${{ runner.os }}-poetry-${{ env.POETRY_VERSION }}-${{ env.DEFAULT_PYTHON_VERSION }}-${{ hashFiles('**/poetry.lock') }}-${{ secrets.POETRY_CACHE_VERSION }}
restore-keys: ${{ runner.os }}-poetry-${{ env.DEFAULT_PYTHON_VERSION }}
- name: Clear Poetry cache
if: steps.cache-poetry.outputs.cache-hit == 'true' && contains(github.event.pull_request.labels.*.name, 'tools:clear-poetry-cache-unit-tests')
run: rm -r .venv
- name: Create virtual environment
if: (steps.cache-poetry.outputs.cache-hit != 'true' || contains(github.event.pull_request.labels.*.name, 'tools:clear-poetry-cache-unit-tests'))
run: python -m venv create .venv
- name: Set up virtual environment
run: poetry config virtualenvs.in-project true
- name: Install Dependencies 📦
run: |
make install-full
- name: Lint Code 🎎
run: |
poetry run ruff check .github --extend-ignore D
poetry run black --check .github
- name: Test Code 🔍
run: |
make test-gh-actions
@@ -0,0 +1,724 @@
# The docs: https://www.notion.so/rasa/The-CI-for-model-regression-tests-92af7185e08e4fb2a0c764770a8e9095
name: CI - Model Regression on schedule
on:
schedule:
# Run once a week
- cron: "1 23 * * */7"
env:
GKE_ZONE: us-central1
GCLOUD_VERSION: "318.0.0"
TF_FORCE_GPU_ALLOW_GROWTH: true
GITHUB_ISSUE_LABELS: '["type:bug :bug:", "tool:model-regression-tests"]'
PERFORMANCE_DROP_THRESHOLD: -0.05
NVML_INTERVAL_IN_SEC: 1
jobs:
read_test_configuration:
name: Reads tests configuration
runs-on: ubuntu-24.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
matrix_length: ${{ steps.set-matrix.outputs.matrix_length }}
steps:
- name: Checkout main
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Checkout dataset
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
with:
repository: ${{ secrets.DATASET_REPOSITORY }}
token: ${{ secrets.ML_TEST_SA_PAT }}
path: "dataset"
ref: "main"
- name: Download gomplate
run: |-
sudo curl -o /usr/local/bin/gomplate -sSL https://github.com/hairyhenderson/gomplate/releases/download/v3.9.0/gomplate_linux-amd64
sudo chmod +x /usr/local/bin/gomplate
- name: Check if a configuration file exists
run: test -f .github/configs/mr-test-schedule.json
- name: Set matrix values
id: set-matrix
shell: bash
run: |-
matrix=$(gomplate -d mapping=./dataset/dataset_config_mapping.json -d github=.github/configs/mr-test-schedule.json -f .github/templates/model_regression_test_config_to_json.tmpl)
matrix_length=$(echo $matrix | jq '.[] | length')
echo "matrix_length=$matrix_length" >> $GITHUB_OUTPUT
echo "matrix=$matrix" >> $GITHUB_OUTPUT
deploy_runner_gpu:
name: Deploy Github Runner - GPU
needs: read_test_configuration
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Setup Python
id: python
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: '3.8'
- name: Export CLOUDSDK_PYTHON env variable
run: |
echo "CLOUDSDK_PYTHON=${{ steps.python.outputs.python-path }}" >> $GITHUB_OUTPUT
export CLOUDSDK_PYTHON=${{ steps.python.outputs.python-path }}
- name: Download gomplate
run: |-
curl -o gomplate -sSL https://github.com/hairyhenderson/gomplate/releases/download/v3.9.0/gomplate_linux-amd64
chmod 755 gomplate
- name: Get TensorFlow version
run: |-
# Read TF version from poetry.lock file
pip install toml
TF_VERSION=$(scripts/read_tensorflow_version.sh)
echo "TensorFlow version: $TF_VERSION"
echo TF_VERSION=$TF_VERSION >> $GITHUB_ENV
# Use compatible CUDA/cuDNN with the given TF version
- name: Prepare GitHub runner image tag
run: |-
GH_RUNNER_IMAGE_TAG=$(jq -r 'if (.config | any(.TF == "${{ env.TF_VERSION }}" )) then (.config[] | select(.TF == "${{ env.TF_VERSION }}") | .IMAGE_TAG) else .default_image_tag end' .github/configs/tf-cuda.json)
echo "GitHub runner image tag for TensorFlow ${{ env.TF_VERSION }} is ${GH_RUNNER_IMAGE_TAG}"
echo GH_RUNNER_IMAGE_TAG=$GH_RUNNER_IMAGE_TAG >> $GITHUB_ENV
num_max_replicas=3
matrix_length=${{ needs.read_test_configuration.outputs.matrix_length }}
if [[ $matrix_length -gt $num_max_replicas ]]; then
NUM_REPLICAS=$num_max_replicas
else
NUM_REPLICAS=$matrix_length
fi
echo NUM_REPLICAS=$NUM_REPLICAS >> $GITHUB_ENV
- name: Send warning if the current TF version does not have CUDA image tags configured
if: env.GH_RUNNER_IMAGE_TAG == 'latest'
env:
TF_CUDA_FILE: ./github/config/tf-cuda.json
run: |-
echo "::warning file=${TF_CUDA_FILE},line=3,col=1,endColumn=3::Missing cuda config for tf ${{ env.TF_VERSION }}. If you are not sure how to config CUDA, please reach out to infrastructure."
- name: Notify slack on tf-cuda config updates
if: env.GH_RUNNER_IMAGE_TAG == 'latest'
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
uses: voxmedia/github-action-slack-notify-build@3665186a8c1a022b28a1dbe0954e73aa9081ea9e
with:
channel_id: ${{ secrets.SLACK_ALERTS_CHANNEL_ID }}
status: WARNING
color: warning
- name: Render deployment template
run: |-
export GH_RUNNER_IMAGE_TAG=${{ env.GH_RUNNER_IMAGE_TAG }}
export GH_RUNNER_IMAGE=${{ secrets.GH_RUNNER_IMAGE }}
./gomplate -f .github/runner/github-runner-deployment.yaml.tmpl -o runner_deployment.yaml
# Setup gcloud auth
- uses: google-github-actions/auth@e8df18b60c5dd38ba618c121b779307266153fbf
with:
service_account: ${{ secrets.GKE_RASA_CI_GPU_SA_NAME_RASA_CI_CD }}
credentials_json: ${{ secrets.GKE_SA_RASA_CI_CD_GPU_RASA_CI_CD }}
# Get the GKE credentials for the cluster
- name: Get GKE Cluster Credentials
uses: google-github-actions/get-gke-credentials@894c221960ab1bc16a69902f29f090638cca753f
with:
cluster_name: ${{ secrets.GKE_GPU_CLUSTER_RASA_CI_CD }}
location: ${{ env.GKE_ZONE }}
project_id: ${{ secrets.GKE_SA_RASA_CI_GPU_PROJECT_RASA_CI_CD }}
- name: Deploy Github Runner
run: |-
kubectl apply -f runner_deployment.yaml
kubectl -n github-runner rollout status --timeout=15m deployment/github-runner-$GITHUB_RUN_ID
- name: Notify slack on failure
if: failure()
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
uses: voxmedia/github-action-slack-notify-build@3665186a8c1a022b28a1dbe0954e73aa9081ea9e
with:
channel_id: ${{ secrets.SLACK_ALERTS_CHANNEL_ID }}
status: FAILED
color: danger
model_regression_test_gpu:
name: Model Regression Tests - GPU
continue-on-error: true
needs:
- deploy_runner_gpu
- read_test_configuration
env:
# Determine where CUDA and Nvidia libraries are located. TensorFlow looks for libraries in the given paths
LD_LIBRARY_PATH: "/usr/local/cuda/extras/CUPTI/lib64:/usr/local/cuda/lib64:/usr/local/nvidia/lib:/usr/local/nvidia/lib64"
ACCELERATOR_TYPE: "GPU"
GITHUB_ISSUE_TITLE: "Scheduled Model Regression Test Failed"
runs-on: [self-hosted, gpu, "${{ github.run_id }}"]
strategy:
# max-parallel: By default, GitHub will maximize the number of jobs run in parallel depending on the available runners on GitHub-hosted virtual machines.
matrix: ${{fromJson(needs.read_test_configuration.outputs.matrix)}}
steps:
- name: Checkout
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Checkout dataset
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
with:
repository: ${{ secrets.DATASET_REPOSITORY }}
token: ${{ secrets.ML_TEST_SA_PAT }}
path: "dataset"
ref: "main"
- name: Set env variables
id: set_dataset_config_vars
env:
DATASET_NAME: "${{ matrix.dataset }}"
CONFIG_NAME: "${{ matrix.config }}"
run: |-
# determine extra environment variables
# - CONFIG
# - DATASET
# - IS_EXTERNAL
# - EXTERNAL_DATASET_REPOSITORY_BRANCH
# - TRAIN_DIR
# - TEST_DIR
# - DOMAIN_FILE
source <(gomplate -d mapping=./dataset/dataset_config_mapping.json -f .github/templates/configuration_variables.tmpl)
# Not all configurations are available for all datasets.
# The job will fail and the workflow continues, if the configuration file doesn't exist
# for a given dataset
echo "is_dataset_exists=true" >> $GITHUB_OUTPUT
echo "is_config_exists=true" >> $GITHUB_OUTPUT
echo "is_external=${IS_EXTERNAL}" >> $GITHUB_OUTPUT
if [[ "${IS_EXTERNAL}" == "true" ]]; then
echo "DATASET_DIR=dataset_external" >> $GITHUB_ENV
else
echo "DATASET_DIR=dataset" >> $GITHUB_ENV
test -d dataset/$DATASET || (echo "::warning::The ${{ matrix.dataset }} dataset doesn't exist. Skipping the job." \
&& echo "is_config_exists=false" >> $GITHUB_OUTPUT && exit 0)
fi
# Skip job if dataset is Hermit and config is BERT + DIET(seq) + ResponseSelector(t2t) or Sparse + BERT + DIET(seq) + ResponseSelector(t2t)
if [[ "${{ matrix.dataset }}" == "Hermit" && "${{ matrix.config }}" =~ "BERT + DIET(seq) + ResponseSelector(t2t)" ]]; then
echo "::warning::This ${{ matrix.dataset }} dataset / ${{ matrix.config }} config is currently being skipped due to OOM associated with the upgrade to TF 2.6." \
&& echo "is_config_exists=false" >> $GITHUB_OUTPUT && exit 0
fi
# Skip job if a given type is not available for a given dataset
if [[ -z "${DOMAIN_FILE}" && "${{ matrix.type }}" == "core" ]]; then
echo "::warning::The ${{ matrix.dataset }} dataset doesn't include core type. Skipping the job." \
&& echo "is_config_exists=false" >> $GITHUB_OUTPUT && exit 0
fi
test -f dataset/configs/$CONFIG || (echo "::warning::The ${{ matrix.config }} configuration file doesn't exist. Skipping the job." \
&& echo "is_dataset_exists=false" >> $GITHUB_OUTPUT && exit 0)
echo "DATASET=${DATASET}" >> $GITHUB_ENV
echo "CONFIG=${CONFIG}" >> $GITHUB_ENV
echo "DOMAIN_FILE=${DOMAIN_FILE}" >> $GITHUB_ENV
echo "EXTERNAL_DATASET_REPOSITORY_BRANCH=${EXTERNAL_DATASET_REPOSITORY_BRANCH}" >> $GITHUB_ENV
echo "IS_EXTERNAL=${IS_EXTERNAL}" >> $GITHUB_ENV
if [[ -z "${TRAIN_DIR}" ]]; then
echo "TRAIN_DIR=train" >> $GITHUB_ENV
else
echo "TRAIN_DIR=${TRAIN_DIR}" >> $GITHUB_ENV
fi
if [[ -z "${TEST_DIR}" ]]; then
echo "TEST_DIR=test" >> $GITHUB_ENV
else
echo "TEST_DIR=${TEST_DIR}" >> $GITHUB_ENV
fi
HOST_NAME=`hostname`
echo "HOST_NAME=${HOST_NAME}" >> $GITHUB_ENV
- name: Checkout dataset - external
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
if: steps.set_dataset_config_vars.outputs.is_external == 'true'
with:
repository: ${{ env.DATASET }}
token: ${{ secrets.ML_TEST_SA_PAT }}
path: "dataset_external"
ref: ${{ env.EXTERNAL_DATASET_REPOSITORY_BRANCH }}
- name: Set dataset commit
id: set-dataset-commit
working-directory: ${{ env.DATASET_DIR }}
run: |
DATASET_COMMIT=$(git rev-parse HEAD)
echo $DATASET_COMMIT
echo "dataset_commit=$DATASET_COMMIT" >> $GITHUB_OUTPUT
- name: Start Datadog Agent
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
env:
DATASET_NAME: "${{ matrix.dataset }}"
CONFIG: "${{ matrix.config }}"
DATASET_COMMIT: "${{ steps.set-dataset-commit.outputs.dataset_commit }}"
BRANCH: ${{ github.ref }}
GITHUB_SHA: "${{ github.sha }}"
TYPE: "${{ matrix.type }}"
DATASET_REPOSITORY_BRANCH: "main"
INDEX_REPETITION: "${{ matrix.index_repetition }}"
run: |
.github/scripts/start_dd_agent.sh "${{ secrets.DD_API_KEY }}" "${{ env.ACCELERATOR_TYPE }}" ${{ env.NVML_INTERVAL_IN_SEC }}
- name: Set up Python 3.10 🐍
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
with:
python-version: '3.10'
- name: Read Poetry Version 🔢
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |
echo "POETRY_VERSION=$(scripts/poetry-version.sh)" >> $GITHUB_ENV
shell: bash
- name: Install poetry 🦄
uses: Gr1N/setup-poetry@15821dc8a61bc630db542ae4baf6a7c19a994844 # v8
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
with:
poetry-version: ${{ env.POETRY_VERSION }}
- name: Load Poetry Cached Libraries ⬇
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
with:
path: ~/.cache/pypoetry/virtualenvs
key: ${{ runner.os }}-poetry-${{ env.POETRY_VERSION }}-3.9-${{ hashFiles('**/poetry.lock') }}-${{ secrets.POETRY_CACHE_VERSION }}
- name: Install Dependencies 📦
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |
make install-full
poetry run python -m spacy download de_core_news_md
- name: Install datadog-api-client
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: poetry run pip install -U datadog-api-client
- name: Validate that GPUs are working
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |-
poetry run python .github/scripts/validate_gpus.py
- name: Download pretrained models 💪
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |-
poetry run python .github/scripts/download_pretrained.py --config dataset/configs/${CONFIG}
- name: Run test
id: run_test
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
env:
TFHUB_CACHE_DIR: ~/.tfhub_cache/
OMP_NUM_THREADS: 1
run: |-
poetry run rasa --version
export NOW_TRAIN=$(gomplate -i '{{ (time.Now).Format time.RFC3339}}');
cd ${{ github.workspace }}
if [[ "${{ steps.set_dataset_config_vars.outputs.is_external }}" == "true" ]]; then
export DATASET=.
fi
if [[ "${{ matrix.type }}" == "nlu" ]]; then
poetry run rasa train nlu --quiet -u "${DATASET_DIR}/${DATASET}/${TRAIN_DIR}" -c "dataset/configs/${CONFIG}" --out "${DATASET_DIR}/models/${DATASET}/${CONFIG}"
echo "train_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
export NOW_TEST=$(gomplate -i '{{ (time.Now).Format time.RFC3339}}');
poetry run rasa test nlu --quiet -u "${DATASET_DIR}/$DATASET/${TEST_DIR}" -m "${DATASET_DIR}/models/$DATASET/$CONFIG" --out "${{ github.workspace }}/results/$DATASET/$CONFIG"
echo "test_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TEST") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
echo "total_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
elif [[ "${{ matrix.type }}" == "core" ]]; then
poetry run rasa train core --quiet -s ${DATASET_DIR}/$DATASET/$TRAIN_DIR -c dataset/configs/$CONFIG -d ${DATASET_DIR}/${DATASET}/${DOMAIN_FILE}
echo "train_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
export NOW_TEST=$(gomplate -i '{{ (time.Now).Format time.RFC3339}}');
poetry run rasa test core -s "${DATASET_DIR}/${DATASET}/${TEST_DIR}" --out "${{ github.workspace }}/results/${{ matrix.dataset }}/${{ matrix.config }}"
echo "test_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TEST") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
echo "total_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
fi
- name: Generate a JSON file with a report / Publish results to Datadog
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
env:
SUMMARY_FILE: "./report.json"
DATASET_NAME: ${{ matrix.dataset }}
RESULT_DIR: "${{ github.workspace }}/results"
CONFIG: ${{ matrix.config }}
TEST_RUN_TIME: ${{ steps.run_test.outputs.test_run_time }}
TRAIN_RUN_TIME: ${{ steps.run_test.outputs.train_run_time }}
TOTAL_RUN_TIME: ${{ steps.run_test.outputs.total_run_time }}
DATASET_REPOSITORY_BRANCH: "main"
TYPE: ${{ matrix.type }}
INDEX_REPETITION: ${{ matrix.index_repetition }}
DATASET_COMMIT: ${{ steps.set-dataset-commit.outputs.dataset_commit }}
BRANCH: ${{ github.ref }}
PR_ID: "${{ github.event.number }}"
PR_URL: ""
DD_APP_KEY: ${{ secrets.DD_APP_KEY_PERF_TEST }}
DD_API_KEY: ${{ secrets.DD_API_KEY }}
DD_SITE: datadoghq.eu
run: |-
poetry run pip install analytics-python
poetry run python .github/scripts/mr_publish_results.py
cat $SUMMARY_FILE
- name: Upload an artifact with the report
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
with:
name: report-${{ matrix.dataset }}-${{ matrix.config }}-${{ matrix.index_repetition }}
path: report.json
# Prepare diagnostic data for the configs which evaluate dialog policy performance
- name: Prepare diagnostic data
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true' && matrix.type == 'core'
run: |
# Create dummy files to preserve directory structure when uploading artifacts
# See: https://github.com/actions/upload-artifact/issues/174
touch "results/${{ matrix.dataset }}/.keep"
touch "results/${{ matrix.dataset }}/${{ matrix.config }}/.keep"
- name: Upload an artifact with diagnostic data
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true' && matrix.type == 'core'
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
with:
name: diagnostic_data
path: |
results/**/.keep
results/${{ matrix.dataset }}/${{ matrix.config }}/failed_test_stories.yml
results/${{ matrix.dataset }}/${{ matrix.config }}/story_confusion_matrix.png
- name: Stop Datadog Agent
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |
sudo service datadog-agent stop
- name: Check duplicate issue
if: failure() && github.event_name == 'schedule'
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410
id: issue-exists
with:
result-encoding: string
github-token: ${{ github.token }}
script: |
// Get all open issues
const opts = await github.issues.listForRepo.endpoint.merge({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: ${{ env.GITHUB_ISSUE_LABELS }}
});
const issues = await github.paginate(opts)
// Check if issue exist by comparing title and body
for (const issue of issues) {
if (issue.title.includes('${{ env.GITHUB_ISSUE_TITLE }}') &&
issue.body.includes('${{ matrix.dataset }}') &&
issue.body.includes('${{ matrix.config }}')) {
console.log(`Found an exist issue \#${issue.number}. Skip the following steps.`);
return 'true'
}
}
return 'false'
- name: Create GitHub Issue 📬
id: create-issue
if: failure() && steps.issue-exists.outputs.result == 'false' && github.event_name == 'schedule'
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410
with:
# do not use GITHUB_TOKEN here because it wouldn't trigger subsequent workflows
github-token: ${{ secrets.RASABOT_GITHUB_TOKEN }}
script: |
var issue = await github.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '${{ env.GITHUB_ISSUE_TITLE }}',
labels: ${{ env.GITHUB_ISSUE_LABELS }},
body: '*This PR is automatically created by the Scheduled Model Regression Test workflow. Checkout the Github Action Run [here](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}).* <br> --- <br> **Description of Problem:** <br> Scheduled Model Regression Test failed. <br> **Configuration**: `${{ matrix.config }}` <br> **Dataset**: `${{ matrix.dataset}}`'
})
return issue.data.number
- name: Notify Slack of Failure 😱
if: failure() && steps.issue-exists.outputs.result == 'false' && github.event_name == 'schedule'
uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 # v3
with:
status: custom
fields: workflow,job,commit,repo,ref,author,took
custom_payload: |
{
attachments: [{
fallback: 'fallback',
color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning',
title: `${process.env.AS_WORKFLOW}`,
text: 'Scheduled model regression test failed :no_entry:',
fields: [{
title: 'Configuration',
value: '${{ matrix.config }}',
short: false
},
{
title: 'Dataset',
value: '${{ matrix.dataset }}',
short: false
},
{
title: 'GitHub Issue',
value: `https://github.com/${{ github.repository }}/issues/${{ steps.create-issue.outputs.result }}`,
short: false
},
{
title: 'GitHub Action',
value: `https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}`,
short: false
}],
actions: [{
}]
}]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_MODEL_REGRESSION_TEST }}
combine_reports:
name: Combine reports
runs-on: ubuntu-24.04
needs:
- model_regression_test_gpu
if: always() && needs.model_regression_test_gpu.result == 'success'
steps:
- name: Checkout git repository 🕝
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Set up Python 3.10 🐍
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: '3.10'
- name: Get reports
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
with:
path: reports/
- name: Display structure of downloaded files
continue-on-error: true
run: ls -R
working-directory: reports/
- name: Merge all reports
env:
SUMMARY_FILE: "./report.json"
REPORTS_DIR: "reports/"
run: |
python .github/scripts/mr_generate_summary.py
cat $SUMMARY_FILE
- name: Upload an artifact with the overall report
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
with:
name: report.json
path: ./report.json
analyse_performance:
name: Analyse Performance
runs-on: ubuntu-24.04
if: always() && github.event_name == 'schedule'
needs:
- model_regression_test_gpu
- combine_reports
env:
GITHUB_ISSUE_TITLE: "Scheduled Model Regression Test Performance Drops"
steps:
- name: Checkout
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Download report from last on-schedule regression test
run: |
# Get ID of last on-schedule workflow
SCHEDULE_ID=$(curl -X GET -s -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' -H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ github.repository }}/actions/workflows" \
| jq -r '.workflows[] | select(.name == "${{ github.workflow }}") | select(.path | test("schedule")) | .id')
ARTIFACT_URL=$(curl -s -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' -H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ github.repository }}/actions/workflows/${SCHEDULE_ID}/runs?event=schedule&status=completed&branch=main&per_page=1" | jq -r .workflow_runs[0].artifacts_url)
DOWNLOAD_URL=$(curl -s -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' -H "Accept: application/vnd.github.v3+json" "${ARTIFACT_URL}" \
| jq -r '.artifacts[] | select(.name == "report.json") | .archive_download_url')
# Download the artifact
curl -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' -LJO -H "Accept: application/vnd.github.v3+json" $DOWNLOAD_URL
# Unzip and change name
unzip report.json.zip && mv report.json report_main.json
- name: Download the report
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
with:
name: report.json
- name: Download gomplate
run: |-
sudo curl -o /usr/local/bin/gomplate -sSL https://github.com/hairyhenderson/gomplate/releases/download/v3.9.0/gomplate_linux-amd64
sudo chmod +x /usr/local/bin/gomplate
- name: Analyse Performance 🔍
id: performance
run: |
OUTPUT="$(gomplate -d data=report.json -d results_main=report_main.json -f .github/templates/model_regression_test_results.tmpl)"
OUTPUT="${OUTPUT//$'\n'/'%0A'}"
OUTPUT="${OUTPUT//$'\r'/'%0D'}"
OUTPUT="$(echo $OUTPUT | sed 's|`|\\`|g')"
echo "report_description=${OUTPUT}" >> $GITHUB_OUTPUT
IS_DROPPED=false
# Loop through all negative values within parentheses
# Set IS_DROPPED to true if there is any value lower
# than the threshold
for x in $(grep -o '\(-[0-9.]\+\)' <<< $OUTPUT); do
if (( $(bc -l <<< "${{ env.PERFORMANCE_DROP_THRESHOLD }} > $x") )); then
IS_DROPPED=true
echo "The decrease of some test performance is > ${{ env.PERFORMANCE_DROP_THRESHOLD }}. Executing the following steps..."
break
fi
done
echo "is_dropped=$IS_DROPPED" >> $GITHUB_OUTPUT
- name: Check duplicate issue
if: steps.performance.outputs.is_dropped == 'true'
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410
id: issue-exists
with:
result-encoding: string
github-token: ${{ github.token }}
script: |
// Get all open issues based on labels
const opts = await github.issues.listForRepo.endpoint.merge({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: ${{ env.GITHUB_ISSUE_LABELS }}
});
const issues = await github.paginate(opts)
// Check if issue exist by comparing title
for (const issue of issues) {
if (issue.title.includes('${{ env.GITHUB_ISSUE_TITLE }}') ) {
console.log(`Found an exist issue \#${issue.number}. Skip the following steps.`);
return 'true'
}
}
return 'false'
- name: Create GitHub Issue 📬
id: create-issue
if: steps.performance.outputs.is_dropped == 'true' && steps.issue-exists.outputs.result == 'false'
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410
with:
# do not use GITHUB_TOKEN here because it wouldn't trigger subsequent workflows
github-token: ${{ secrets.RASABOT_GITHUB_TOKEN }}
script: |
// Prepare issue body
let issue_body = '*This PR is automatically created by the Scheduled Model Regression Test workflow. Checkout the Github Action Run [here](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}).* <br> --- <br> **Description of Problem:** <br> Some test performance scores **decreased**. Please look at the following table for more details. <br>'
issue_body += `${{ steps.performance.outputs.report_description }}`
// Open issue
var issue = await github.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '${{ env.GITHUB_ISSUE_TITLE }}',
labels: ${{ env.GITHUB_ISSUE_LABELS }},
body: issue_body
})
return issue.data.number
- name: Notify Slack when Performance Drops 💬
if: steps.performance.outputs.is_dropped == 'true' && steps.issue-exists.outputs.result == 'false'
uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 #v3
with:
status: custom
fields: workflow,job,commit,repo,ref,author,took
custom_payload: |
{
attachments: [{
fallback: 'fallback',
color: 'danger',
title: `${process.env.AS_WORKFLOW}`,
text: 'Scheduled model regression test performance drops :chart_with_downwards_trend:',
fields: [{
title: 'GitHub Issue',
value: `https://github.com/${{ github.repository }}/issues/${{ steps.create-issue.outputs.result }}`,
short: false
},
{
title: 'GitHub Action',
value: `https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}`,
short: false
}],
actions: [{
}]
}]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_MODEL_REGRESSION_TEST }}
remove_runner_gpu:
name: Delete Github Runner - GPU
if: always()
needs:
- deploy_runner_gpu
- model_regression_test_gpu
runs-on: ubuntu-24.04
steps:
- name: Setup Python
id: python
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: '3.8'
- name: Export CLOUDSDK_PYTHON env variable
run: |
echo "CLOUDSDK_PYTHON=${{ steps.python.outputs.python-path }}" >> $GITHUB_OUTPUT
export CLOUDSDK_PYTHON=${{ steps.python.outputs.python-path }}
# Setup gcloud auth
- uses: google-github-actions/auth@e8df18b60c5dd38ba618c121b779307266153fbf
with:
service_account: ${{ secrets.GKE_RASA_CI_GPU_SA_NAME_RASA_CI_CD }}
credentials_json: ${{ secrets.GKE_SA_RASA_CI_CD_GPU_RASA_CI_CD }}
# Get the GKE credentials for the cluster
- name: Get GKE Cluster Credentials
uses: google-github-actions/get-gke-credentials@894c221960ab1bc16a69902f29f090638cca753f
with:
cluster_name: ${{ secrets.GKE_GPU_CLUSTER_RASA_CI_CD }}
location: ${{ env.GKE_ZONE }}
project_id: ${{ secrets.GKE_SA_RASA_CI_GPU_PROJECT_RASA_CI_CD }}
- name: Remove Github Runner
run: kubectl -n github-runner delete deployments github-runner-${GITHUB_RUN_ID} --grace-period=30
+923
View File
@@ -0,0 +1,923 @@
# The docs:
# - https://www.notion.so/rasa/The-CI-for-model-regression-tests-aa579d5524a544af992f97d132bcc2de
# - https://www.notion.so/rasa/Datadog-Usage-Documentation-422099c9a3a24f5a99d92d904537dd0b
name: CI - Model Regression
on:
push:
branches:
- "[0-9]+.[0-9]+.x"
tags:
- "**"
pull_request:
types: [opened, synchronize, labeled]
concurrency:
group: ci-model-regression-${{ github.ref }} # branch or tag name
cancel-in-progress: true
env:
GKE_ZONE: us-central1
GCLOUD_VERSION: "318.0.0"
DD_PROFILING_ENABLED: false
TF_FORCE_GPU_ALLOW_GROWTH: true
NVML_INTERVAL_IN_SEC: 1
jobs:
read_test_configuration:
name: Reads tests configuration
if: ${{ github.repository == 'RasaHQ/rasa' && contains(github.event.pull_request.labels.*.name, 'status:model-regression-tests') }}
runs-on: ubuntu-24.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
matrix_length: ${{ steps.set-matrix.outputs.matrix_length }}
configuration_id: ${{ steps.fc_config.outputs.comment-id }}
dataset_branch: ${{ steps.set-dataset-branch.outputs.dataset_branch }}
steps:
- name: Checkout main
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Download gomplate
run: |-
sudo curl -o /usr/local/bin/gomplate -sSL https://github.com/hairyhenderson/gomplate/releases/download/v3.9.0/gomplate_linux-amd64
sudo chmod +x /usr/local/bin/gomplate
- name: Find a comment with configuration
uses: tczekajlo/find-comment@16228d0f2100e06ea9bf8c0e7fe7287b7c6b531d
id: fc_config
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.number }}
body-includes: "^/modeltest"
- run: echo ${{ steps.fc_config.outputs.comment-id }}
# This step has to happen before the other configuration details are read from
# the same PR comment, because we need to check out the correct branch to feed the
# dataset mapping and configs into the 'Read configuration from a PR comment' step
# which creates the experiments matrix
- name: Read dataset branch from a PR comment
if: steps.fc_config.outputs.comment-id != ''
id: set-dataset-branch
run: |-
source <(gomplate -d github=https://api.github.com/repos/${{ github.repository }}/issues/comments/${{ steps.fc_config.outputs.comment-id }} -H 'github=Authorization:token ${{ secrets.GITHUB_TOKEN }}' -f .github/templates/model_regression_test_read_dataset_branch.tmpl)
echo "dataset_branch=${DATASET_BRANCH}" >> $GITHUB_OUTPUT
- name: Checkout dataset
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
with:
repository: ${{ secrets.DATASET_REPOSITORY }}
token: ${{ secrets.ML_TEST_SA_PAT }}
path: "dataset"
ref: ${{ steps.set-dataset-branch.outputs.dataset_branch }}
- name: Render help description from template
id: get_help_description
run: |
OUTPUT=$(gomplate -d mapping=./dataset/dataset_config_mapping.json -f .github/templates/model_regression_test_config_comment.tmpl)
OUTPUT="${OUTPUT//$'\n'/'%0A'}"
OUTPUT="${OUTPUT//$'\r'/'%0D'}"
echo "help_description=$OUTPUT" >> $GITHUB_OUTPUT
- name: Create a comment with help description
uses: RasaHQ/create-comment@da7b2ec20116674919493bb5894eea70fdaa6486
with:
mode: "delete-previous"
id: comment_help_description
github-token: ${{ secrets.GITHUB_TOKEN }}
body: |
${{ steps.get_help_description.outputs.help_description }}
- if: steps.fc_config.outputs.comment-id == ''
run: echo "::error::Cannot find a comment with the configuration"
name: Log a warning message if a configuration cannot be found
- name: Read configuration from a PR comment
if: steps.fc_config.outputs.comment-id != ''
id: set-matrix
run: |-
matrix=$(gomplate -d mapping=./dataset/dataset_config_mapping.json -d github=https://api.github.com/repos/${{ github.repository }}/issues/comments/${{ steps.fc_config.outputs.comment-id }} -H 'github=Authorization:token ${{ secrets.GITHUB_TOKEN }}' -f .github/templates/model_regression_test_config_to_json.tmpl)
if [ $? -ne 0 ]; then
echo "::error::Cannot read config from PR. Please double check your config."
exit 1
fi
matrix_length=$(echo $matrix | jq '.[] | length')
echo "matrix_length=$matrix_length" >> $GITHUB_OUTPUT
echo "matrix=$matrix" >> $GITHUB_OUTPUT
- name: Update the comment with the configuration
uses: peter-evans/create-or-update-comment@3383acd359705b10cb1eeef05c0e88c056ea4666
if: steps.fc_config.outputs.comment-id != ''
with:
comment-id: ${{ steps.fc_config.outputs.comment-id }}
body: |
<!-- comment-id:comment_configuration -->
reactions: eyes
- name: Re-create the comment with the configuration
uses: RasaHQ/create-comment@da7b2ec20116674919493bb5894eea70fdaa6486
if: steps.fc_config.outputs.comment-id != '' && steps.fc_config.outputs.comment-body != ''
with:
mode: "delete-previous"
id: comment_configuration
github-token: ${{ secrets.GITHUB_TOKEN }}
body: ${{ steps.fc_config.outputs.comment-body }}
- name: Find a comment with configuration - update
uses: tczekajlo/find-comment@16228d0f2100e06ea9bf8c0e7fe7287b7c6b531d
id: fc_config_update
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.number }}
body-includes: "^/modeltest"
- name: Add reaction
uses: peter-evans/create-or-update-comment@3383acd359705b10cb1eeef05c0e88c056ea4666
if: steps.fc_config_update.outputs.comment-id != ''
with:
edit-mode: "replace"
comment-id: ${{ steps.fc_config_update.outputs.comment-id }}
reactions: heart, hooray, rocket
- name: Add a comment that the tests are in progress
uses: RasaHQ/create-comment@da7b2ec20116674919493bb5894eea70fdaa6486
if: steps.fc_config_update.outputs.comment-id != ''
with:
mode: "delete-previous"
id: comment_tests_in_progress
github-token: ${{ secrets.GITHUB_TOKEN }}
body: |
The model regression tests have started. It might take a while, please be patient.
As soon as results are ready you'll see a new comment with the results.
Used configuration can be found in [the comment.](https://github.com/${{ github.repository }}/pull/${{ github.event.number}}#issuecomment-${{ steps.fc_config_update.outputs.comment-id }})
deploy_runner_gpu:
name: Deploy Github Runner - GPU
needs: read_test_configuration
runs-on: ubuntu-24.04
if: ${{ contains(github.event.pull_request.labels.*.name, 'runner:gpu') && github.repository == 'RasaHQ/rasa' && contains(github.event.pull_request.labels.*.name, 'status:model-regression-tests') && needs.read_test_configuration.outputs.configuration_id != '' }}
steps:
- name: Checkout
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Download gomplate
run: |-
sudo curl -o /usr/local/bin/gomplate -sSL https://github.com/hairyhenderson/gomplate/releases/download/v3.9.0/gomplate_linux-amd64
sudo chmod +x /usr/local/bin/gomplate
- name: Get TensorFlow version
run: |-
# Read TF version from poetry.lock file
pip install toml
TF_VERSION=$(scripts/read_tensorflow_version.sh)
# Keep the first 3 characters, e.g. we keep 2.3 if TF_VERSION is 2.3.4
TF_VERSION=${TF_VERSION::3}
echo "TensorFlow version: $TF_VERSION"
echo TF_VERSION=$TF_VERSION >> $GITHUB_ENV
# Use compatible CUDA/cuDNN with the given TF version
- name: Prepare GitHub runner image tag
run: |-
GH_RUNNER_IMAGE_TAG=$(jq -r 'if (.config | any(.TF == "${{ env.TF_VERSION }}" )) then (.config[] | select(.TF == "${{ env.TF_VERSION }}") | .IMAGE_TAG) else .default_image_tag end' .github/configs/tf-cuda.json)
echo "GitHub runner image tag for TensorFlow ${{ env.TF_VERSION }} is ${GH_RUNNER_IMAGE_TAG}"
echo GH_RUNNER_IMAGE_TAG=$GH_RUNNER_IMAGE_TAG >> $GITHUB_ENV
num_max_replicas=3
matrix_length=${{ needs.read_test_configuration.outputs.matrix_length }}
if [[ $matrix_length -gt $num_max_replicas ]]; then
NUM_REPLICAS=$num_max_replicas
else
NUM_REPLICAS=$matrix_length
fi
echo NUM_REPLICAS=$NUM_REPLICAS >> $GITHUB_ENV
- name: Send warning if the current TF version does not have CUDA image tags configured
if: env.GH_RUNNER_IMAGE_TAG == 'latest'
env:
TF_CUDA_FILE: ./github/config/tf-cuda.json
run: |-
echo "::warning file=${TF_CUDA_FILE},line=3,col=1,endColumn=3::Missing cuda config for tf ${{ env.TF_VERSION }}. If you are not sure how to config CUDA, please reach out to infrastructure."
- name: Notify slack on tf-cuda config updates
if: env.GH_RUNNER_IMAGE_TAG == 'latest'
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
uses: voxmedia/github-action-slack-notify-build@3665186a8c1a022b28a1dbe0954e73aa9081ea9e
with:
channel_id: ${{ secrets.SLACK_ALERTS_CHANNEL_ID }}
status: WARNING
color: warning
- name: Render deployment template
run: |-
export GH_RUNNER_IMAGE_TAG=${{ env.GH_RUNNER_IMAGE_TAG }}
export GH_RUNNER_IMAGE=${{ secrets.GH_RUNNER_IMAGE }}
gomplate -f .github/runner/github-runner-deployment.yaml.tmpl -o runner_deployment.yaml
# Setup gcloud auth
- uses: google-github-actions/auth@e8df18b60c5dd38ba618c121b779307266153fbf
with:
service_account: ${{ secrets.GKE_RASA_CI_GPU_SA_NAME_RASA_CI_CD }}
credentials_json: ${{ secrets.GKE_SA_RASA_CI_CD_GPU_RASA_CI_CD }}
# Get the GKE credentials for the cluster
- name: Get GKE Cluster Credentials
uses: google-github-actions/get-gke-credentials@894c221960ab1bc16a69902f29f090638cca753f
with:
cluster_name: ${{ secrets.GKE_GPU_CLUSTER_RASA_CI_CD }}
location: ${{ env.GKE_ZONE }}
project_id: ${{ secrets.GKE_SA_RASA_CI_GPU_PROJECT_RASA_CI_CD }}
- name: Deploy Github Runner
run: |-
kubectl apply -f runner_deployment.yaml
kubectl -n github-runner rollout status --timeout=15m deployment/github-runner-$GITHUB_RUN_ID
model_regression_test_gpu:
name: Model Regression Tests - GPU
needs:
- deploy_runner_gpu
- read_test_configuration
env:
# Determine where CUDA and Nvidia libraries are located. TensorFlow looks for libraries in the given paths
LD_LIBRARY_PATH: "/usr/local/cuda/extras/CUPTI/lib64:/usr/local/cuda/lib64:/usr/local/nvidia/lib:/usr/local/nvidia/lib64"
ACCELERATOR_TYPE: "GPU"
runs-on: [self-hosted, gpu, "${{ github.run_id }}"]
strategy:
# max-parallel: By default, GitHub will maximize the number of jobs run in parallel depending on the available runners on GitHub-hosted virtual machines.
matrix: ${{fromJson(needs.read_test_configuration.outputs.matrix)}}
fail-fast: false
if: ${{ contains(github.event.pull_request.labels.*.name, 'runner:gpu') && github.repository == 'RasaHQ/rasa' && contains(github.event.pull_request.labels.*.name, 'status:model-regression-tests') && needs.read_test_configuration.outputs.configuration_id != '' }}
steps:
- name: Checkout
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Checkout dataset
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
with:
repository: ${{ secrets.DATASET_REPOSITORY }}
token: ${{ secrets.ML_TEST_SA_PAT }}
path: "dataset"
ref: ${{ needs.read_test_configuration.outputs.dataset_branch }}
- name: Set env variables
id: set_dataset_config_vars
env:
DATASET_NAME: "${{ matrix.dataset }}"
CONFIG_NAME: "${{ matrix.config }}"
run: |-
# determine extra environment variables
# - CONFIG
# - DATASET
# - IS_EXTERNAL
# - EXTERNAL_DATASET_REPOSITORY_BRANCH
# - TRAIN_DIR
# - TEST_DIR
# - DOMAIN_FILE
source <(gomplate -d mapping=./dataset/dataset_config_mapping.json -f .github/templates/configuration_variables.tmpl)
# Not all configurations are available for all datasets.
# The job will fail and the workflow continues, if the configuration file doesn't exist
# for a given dataset
echo "is_dataset_exists=true" >> $GITHUB_OUTPUT
echo "is_config_exists=true" >> $GITHUB_OUTPUT
echo "is_external=${IS_EXTERNAL}" >> $GITHUB_OUTPUT
# Warn about job if dataset is Hermit and config is BERT + DIET(seq) + ResponseSelector(t2t) or Sparse + BERT + DIET(seq) + ResponseSelector(t2t)
if [[ "${{ matrix.dataset }}" == "Hermit" && "${{ matrix.config }}" =~ "BERT + DIET(seq) + ResponseSelector(t2t)" ]]; then
echo "::warning::This ${{ matrix.dataset }} dataset / ${{ matrix.config }} config is currently being skipped on scheduled tests due to OOM associated with the upgrade to TF 2.6. You may see OOM here."
fi
if [[ "${IS_EXTERNAL}" == "true" ]]; then
echo "DATASET_DIR=dataset_external" >> $GITHUB_ENV
else
echo "DATASET_DIR=dataset" >> $GITHUB_ENV
test -d dataset/$DATASET || (echo "::warning::The ${{ matrix.dataset }} dataset doesn't exist. Skipping the job." \
&& echo "is_config_exists=false" >> $GITHUB_OUTPUT && exit 0)
fi
# Skip job if a given type is not available for a given dataset
if [[ -z "${DOMAIN_FILE}" && "${{ matrix.type }}" == "core" ]]; then
echo "::warning::The ${{ matrix.dataset }} dataset doesn't include core type. Skipping the job." \
&& echo "is_config_exists=false" >> $GITHUB_OUTPUT && exit 0
fi
test -f dataset/configs/$CONFIG || (echo "::warning::The ${{ matrix.config }} configuration file doesn't exist. Skipping the job." \
&& echo "is_dataset_exists=false" >> $GITHUB_OUTPUT && exit 0)
echo "DATASET=${DATASET}" >> $GITHUB_ENV
echo "CONFIG=${CONFIG}" >> $GITHUB_ENV
echo "DOMAIN_FILE=${DOMAIN_FILE}" >> $GITHUB_ENV
echo "EXTERNAL_DATASET_REPOSITORY_BRANCH=${EXTERNAL_DATASET_REPOSITORY_BRANCH}" >> $GITHUB_ENV
echo "IS_EXTERNAL=${IS_EXTERNAL}" >> $GITHUB_ENV
if [[ -z "${TRAIN_DIR}" ]]; then
echo "TRAIN_DIR=train" >> $GITHUB_ENV
else
echo "TRAIN_DIR=${TRAIN_DIR}" >> $GITHUB_ENV
fi
if [[ -z "${TEST_DIR}" ]]; then
echo "TEST_DIR=test" >> $GITHUB_ENV
else
echo "TEST_DIR=${TEST_DIR}" >> $GITHUB_ENV
fi
HOST_NAME=`hostname`
echo "HOST_NAME=${HOST_NAME}" >> $GITHUB_ENV
- name: Checkout dataset - external
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
if: steps.set_dataset_config_vars.outputs.is_external == 'true'
with:
repository: ${{ env.DATASET }}
token: ${{ secrets.ML_TEST_SA_PAT }}
path: "dataset_external"
ref: ${{ env.EXTERNAL_DATASET_REPOSITORY_BRANCH }}
- name: Set dataset commit
id: set-dataset-commit
working-directory: ${{ env.DATASET_DIR }}
run: |
DATASET_COMMIT=$(git rev-parse HEAD)
echo $DATASET_COMMIT
echo "dataset_commit=$DATASET_COMMIT" >> $GITHUB_OUTPUT
- name: Start Datadog Agent
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
env:
DATASET_NAME: "${{ matrix.dataset }}"
CONFIG: "${{ matrix.config }}"
DATASET_COMMIT: "${{ steps.set-dataset-commit.outputs.dataset_commit }}"
BRANCH: ${{ github.head_ref }}
GITHUB_SHA: "${{ github.sha }}"
PR_ID: "${{ github.event.number }}"
TYPE: "${{ matrix.type }}"
DATASET_REPOSITORY_BRANCH: ${{ needs.read_test_configuration.outputs.dataset_branch }}
INDEX_REPETITION: "${{ matrix.index_repetition }}"
run: |
export PR_URL="https://github.com/${GITHUB_REPOSITORY}/pull/${{ github.event.number }}"
.github/scripts/start_dd_agent.sh "${{ secrets.DD_API_KEY }}" "${{ env.ACCELERATOR_TYPE }}" ${{ env.NVML_INTERVAL_IN_SEC }}
- name: Set up Python 3.10 🐍
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
with:
python-version: '3.10'
- name: Read Poetry Version 🔢
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |
echo "POETRY_VERSION=$(scripts/poetry-version.sh)" >> $GITHUB_ENV
shell: bash
- name: Install poetry 🦄
uses: Gr1N/setup-poetry@15821dc8a61bc630db542ae4baf6a7c19a994844 # v8
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
with:
poetry-version: ${{ env.POETRY_VERSION }}
- name: Load Poetry Cached Libraries ⬇
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
with:
path: ~/.cache/pypoetry/virtualenvs
key: ${{ runner.os }}-poetry-${{ env.POETRY_VERSION }}-3.9-${{ hashFiles('**/poetry.lock') }}-${{ secrets.POETRY_CACHE_VERSION }}
- name: Install Dependencies 📦
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |
make install-full
poetry run python -m spacy download de_core_news_md
- name: Install datadog dependencies
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: poetry run pip install -U datadog-api-client ddtrace
- name: Validate that GPUs are working
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |-
poetry run python .github/scripts/validate_gpus.py
- name: Download pretrained models 💪
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |-
poetry run python .github/scripts/download_pretrained.py --config dataset/configs/${CONFIG}
- name: Run test
id: run_test
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
env:
TFHUB_CACHE_DIR: ~/.tfhub_cache/
OMP_NUM_THREADS: 1
run: |-
poetry run rasa --version
export NOW_TRAIN=$(gomplate -i '{{ (time.Now).Format time.RFC3339}}');
cd ${{ github.workspace }}
if [[ "${{ steps.set_dataset_config_vars.outputs.is_external }}" == "true" ]]; then
export DATASET=.
fi
if [[ "${{ matrix.type }}" == "nlu" ]]; then
poetry run ddtrace-run rasa train nlu --quiet -u ${DATASET_DIR}/${DATASET}/${TRAIN_DIR} -c dataset/configs/${CONFIG} --out ${DATASET_DIR}/models/${DATASET}/${CONFIG}
echo "train_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
export NOW_TEST=$(gomplate -i '{{ (time.Now).Format time.RFC3339}}');
poetry run ddtrace-run rasa test nlu --quiet -u ${DATASET_DIR}/$DATASET/${TEST_DIR} -m ${DATASET_DIR}/models/$DATASET/$CONFIG --out ${{ github.workspace }}/results/$DATASET/$CONFIG
echo "test_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TEST") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
echo "total_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
elif [[ "${{ matrix.type }}" == "core" ]]; then
poetry run ddtrace-run rasa train core --quiet -s ${DATASET_DIR}/$DATASET/$TRAIN_DIR -c dataset/configs/$CONFIG -d ${DATASET_DIR}/${DATASET}/${DOMAIN_FILE}
echo "train_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
export NOW_TEST=$(gomplate -i '{{ (time.Now).Format time.RFC3339}}');
poetry run ddtrace-run rasa test core -s ${DATASET_DIR}/${DATASET}/${TEST_DIR} --out ${{ github.workspace }}/results/${{ matrix.dataset }}/${CONFIG}
echo "test_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TEST") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
echo "total_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
fi
- name: Generate a JSON file with a report / Publish results to Datadog
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
env:
SUMMARY_FILE: "./report.json"
DATASET_NAME: ${{ matrix.dataset }}
RESULT_DIR: "${{ github.workspace }}/results"
CONFIG: ${{ matrix.config }}
TEST_RUN_TIME: ${{ steps.run_test.outputs.test_run_time }}
TRAIN_RUN_TIME: ${{ steps.run_test.outputs.train_run_time }}
TOTAL_RUN_TIME: ${{ steps.run_test.outputs.total_run_time }}
DATASET_REPOSITORY_BRANCH: ${{ needs.read_test_configuration.outputs.dataset_branch }}
TYPE: ${{ matrix.type }}
INDEX_REPETITION: ${{ matrix.index_repetition }}
DATASET_COMMIT: ${{ steps.set-dataset-commit.outputs.dataset_commit }}
BRANCH: ${{ github.head_ref }}
GITHUB_SHA: "${{ github.sha }}"
PR_ID: "${{ github.event.number }}"
DD_APP_KEY: ${{ secrets.DD_APP_KEY_PERF_TEST }}
DD_API_KEY: ${{ secrets.DD_API_KEY }}
DD_SITE: datadoghq.eu
run: |-
export PR_URL="https://github.com/${GITHUB_REPOSITORY}/pull/${{ github.event.number }}"
poetry run pip install analytics-python
poetry run python .github/scripts/mr_publish_results.py
cat $SUMMARY_FILE
- name: Upload an artifact with the report
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
with:
name: report-${{ matrix.dataset }}-${{ matrix.config }}-${{ matrix.index_repetition }}
path: report.json
- name: Stop Datadog Agent
if: ${{ always() && steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true' }}
run: |
sudo service datadog-agent stop
model_regression_test_cpu:
name: Model Regression Tests - CPU
needs:
- read_test_configuration
env:
ACCELERATOR_TYPE: "CPU"
runs-on: ubuntu-24.04
strategy:
max-parallel: 3
matrix: ${{fromJson(needs.read_test_configuration.outputs.matrix)}}
fail-fast: false
if: ${{ !contains(github.event.pull_request.labels.*.name, 'runner:gpu') && github.repository == 'RasaHQ/rasa' && contains(github.event.pull_request.labels.*.name, 'status:model-regression-tests') && needs.read_test_configuration.outputs.configuration_id != '' }}
steps:
- name: Checkout
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Checkout dataset
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
with:
repository: ${{ secrets.DATASET_REPOSITORY }}
token: ${{ secrets.ML_TEST_SA_PAT }}
path: "dataset"
ref: ${{ needs.read_test_configuration.outputs.dataset_branch }}
- name: Download gomplate
run: |-
sudo curl -o /usr/local/bin/gomplate -sSL https://github.com/hairyhenderson/gomplate/releases/download/v3.9.0/gomplate_linux-amd64
sudo chmod +x /usr/local/bin/gomplate
- name: Set env variables
id: set_dataset_config_vars
env:
DATASET_NAME: "${{ matrix.dataset }}"
CONFIG_NAME: "${{ matrix.config }}"
run: |-
# determine extra environment variables
# - CONFIG
# - DATASET
# - IS_EXTERNAL
# - EXTERNAL_DATASET_REPOSITORY_BRANCH
# - TRAIN_DIR
# - TEST_DIR
# - DOMAIN_FILE
source <(gomplate -d mapping=./dataset/dataset_config_mapping.json -f .github/templates/configuration_variables.tmpl)
# Not all configurations are available for all datasets.
# The job will fail and the workflow continues, if the configuration file doesn't exist
# for a given dataset
echo "is_dataset_exists=true" >> $GITHUB_OUTPUT
echo "is_config_exists=true" >> $GITHUB_OUTPUT
echo "is_external=${IS_EXTERNAL}" >> $GITHUB_OUTPUT
if [[ "${IS_EXTERNAL}" == "true" ]]; then
echo "DATASET_DIR=dataset_external" >> $GITHUB_ENV
else
echo "DATASET_DIR=dataset" >> $GITHUB_ENV
test -d dataset/$DATASET || (echo "::warning::The ${{ matrix.dataset }} dataset doesn't exist. Skipping the job." \
&& echo "is_config_exists=false" >> $GITHUB_OUTPUT && exit 0)
fi
# Skip job if a given type is not available for a given dataset
if [[ -z "${DOMAIN_FILE}" && "${{ matrix.type }}" == "core" ]]; then
echo "::warning::The ${{ matrix.dataset }} dataset doesn't include core type. Skipping the job." \
&& echo "is_config_exists=false" >> $GITHUB_OUTPUT && exit 0
fi
test -f dataset/configs/$CONFIG || (echo "::warning::The ${{ matrix.config }} configuration file doesn't exist. Skipping the job." \
&& echo "is_dataset_exists=false" >> $GITHUB_OUTPUT && exit 0)
echo "DATASET=${DATASET}" >> $GITHUB_ENV
echo "CONFIG=${CONFIG}" >> $GITHUB_ENV
echo "DOMAIN_FILE=${DOMAIN_FILE}" >> $GITHUB_ENV
echo "EXTERNAL_DATASET_REPOSITORY_BRANCH=${EXTERNAL_DATASET_REPOSITORY_BRANCH}" >> $GITHUB_ENV
echo "IS_EXTERNAL=${IS_EXTERNAL}" >> $GITHUB_ENV
if [[ -z "${TRAIN_DIR}" ]]; then
echo "TRAIN_DIR=train" >> $GITHUB_ENV
else
echo "TRAIN_DIR=${TRAIN_DIR}" >> $GITHUB_ENV
fi
if [[ -z "${TEST_DIR}" ]]; then
echo "TEST_DIR=test" >> $GITHUB_ENV
else
echo "TEST_DIR=${TEST_DIR}" >> $GITHUB_ENV
fi
HOST_NAME=`hostname`
echo "HOST_NAME=${HOST_NAME}" >> $GITHUB_ENV
- name: Checkout dataset - external
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
if: steps.set_dataset_config_vars.outputs.is_external == 'true'
with:
repository: ${{ env.DATASET }}
token: ${{ secrets.ML_TEST_SA_PAT }}
path: "dataset_external"
ref: ${{ env.EXTERNAL_DATASET_REPOSITORY_BRANCH }}
- name: Set dataset commit
id: set-dataset-commit
working-directory: ${{ env.DATASET_DIR }}
run: |
DATASET_COMMIT=$(git rev-parse HEAD)
echo $DATASET_COMMIT
echo "dataset_commit=$DATASET_COMMIT" >> $GITHUB_OUTPUT
- name: Start Datadog Agent
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
env:
DATASET_NAME: "${{ matrix.dataset }}"
CONFIG: "${{ matrix.config }}"
DATASET_COMMIT: "${{ steps.set-dataset-commit.outputs.dataset_commit }}"
BRANCH: ${{ github.head_ref }}
GITHUB_SHA: "${{ github.sha }}"
PR_ID: "${{ github.event.number }}"
TYPE: "${{ matrix.type }}"
DATASET_REPOSITORY_BRANCH: ${{ matrix.dataset_branch }}
INDEX_REPETITION: "${{ matrix.index_repetition }}"
run: |
export PR_URL="https://github.com/${GITHUB_REPOSITORY}/pull/${{ github.event.number }}"
.github/scripts/start_dd_agent.sh "${{ secrets.DD_API_KEY }}" "${{ env.ACCELERATOR_TYPE }}" ${{ env.NVML_INTERVAL_IN_SEC }}
- name: Set up Python 3.10 🐍
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
with:
python-version: '3.10'
- name: Read Poetry Version 🔢
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |
echo "POETRY_VERSION=$(scripts/poetry-version.sh)" >> $GITHUB_ENV
shell: bash
- name: Install poetry 🦄
uses: Gr1N/setup-poetry@15821dc8a61bc630db542ae4baf6a7c19a994844 # v8
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
with:
poetry-version: ${{ env.POETRY_VERSION }}
- name: Load Poetry Cached Libraries ⬇
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
with:
path: ~/.cache/pypoetry/virtualenvs
key: ${{ runner.os }}-poetry-${{ env.POETRY_VERSION }}-3.9-${{ hashFiles('**/poetry.lock') }}-${{ secrets.POETRY_CACHE_VERSION }}
- name: Install Dependencies 📦
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |
make install-full
poetry run python -m spacy download de_core_news_md
- name: Install datadog dependencies
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: poetry run pip install -U datadog-api-client ddtrace
- name: CPU run - Validate that no GPUs are available
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |-
poetry run python .github/scripts/validate_cpu.py
- name: Download pretrained models 💪
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
run: |-
poetry run python .github/scripts/download_pretrained.py --config dataset/configs/${CONFIG}
- name: Run test
id: run_test
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
env:
TFHUB_CACHE_DIR: ~/.tfhub_cache/
OMP_NUM_THREADS: 1
run: |-
poetry run rasa --version
export NOW_TRAIN=$(gomplate -i '{{ (time.Now).Format time.RFC3339}}');
cd ${{ github.workspace }}
if [[ "${{ steps.set_dataset_config_vars.outputs.is_external }}" == "true" ]]; then
export DATASET=.
fi
if [[ "${{ matrix.type }}" == "nlu" ]]; then
poetry run ddtrace-run rasa train nlu --quiet -u ${DATASET_DIR}/${DATASET}/${TRAIN_DIR} -c dataset/configs/${CONFIG} --out ${DATASET_DIR}/models/${DATASET}/${CONFIG}
echo "train_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
export NOW_TEST=$(gomplate -i '{{ (time.Now).Format time.RFC3339}}');
poetry run ddtrace-run rasa test nlu --quiet -u ${DATASET_DIR}/$DATASET/${TEST_DIR} -m ${DATASET_DIR}/models/$DATASET/$CONFIG --out ${{ github.workspace }}/results/$DATASET/$CONFIG
echo "test_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TEST") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
echo "total_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
elif [[ "${{ matrix.type }}" == "core" ]]; then
poetry run ddtrace-run rasa train core --quiet -s ${DATASET_DIR}/$DATASET/$TRAIN_DIR -c dataset/configs/$CONFIG -d ${DATASET_DIR}/${DATASET}/${DOMAIN_FILE}
echo "train_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
export NOW_TEST=$(gomplate -i '{{ (time.Now).Format time.RFC3339}}');
poetry run ddtrace-run rasa test core -s ${DATASET_DIR}/${DATASET}/${TEST_DIR} --out ${{ github.workspace }}/results/${{ matrix.dataset }}/${CONFIG}
echo "test_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TEST") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
echo "total_run_time=$(gomplate -i '{{ $t := time.Parse time.RFC3339 (getenv "NOW_TRAIN") }}{{ (time.Since $t).Round (time.Second 1) }}')" >> $GITHUB_OUTPUT
fi
- name: Generate a JSON file with a report / Publish results to Datadog
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
env:
SUMMARY_FILE: "./report.json"
DATASET_NAME: ${{ matrix.dataset }}
RESULT_DIR: "${{ github.workspace }}/results"
CONFIG: ${{ matrix.config }}
TEST_RUN_TIME: ${{ steps.run_test.outputs.test_run_time }}
TRAIN_RUN_TIME: ${{ steps.run_test.outputs.train_run_time }}
TOTAL_RUN_TIME: ${{ steps.run_test.outputs.total_run_time }}
DATASET_REPOSITORY_BRANCH: ${{ needs.read_test_configuration.outputs.dataset_branch }}
TYPE: ${{ matrix.type }}
INDEX_REPETITION: ${{ matrix.index_repetition }}
DATASET_COMMIT: ${{ steps.set-dataset-commit.outputs.dataset_commit }}
BRANCH: ${{ github.head_ref }}
GITHUB_SHA: "${{ github.sha }}"
PR_ID: "${{ github.event.number }}"
DD_APP_KEY: ${{ secrets.DD_APP_KEY_PERF_TEST }}
DD_API_KEY: ${{ secrets.DD_API_KEY }}
DD_SITE: datadoghq.eu
run: |-
export PR_URL="https://github.com/${GITHUB_REPOSITORY}/pull/${{ github.event.number }}"
poetry run pip install analytics-python
poetry run python .github/scripts/mr_publish_results.py
cat $SUMMARY_FILE
- name: Upload an artifact with the report
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
if: steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true'
with:
name: report-${{ matrix.dataset }}-${{ matrix.config }}-${{ matrix.index_repetition }}
path: report.json
- name: Stop Datadog Agent
if: ${{ always() && steps.set_dataset_config_vars.outputs.is_dataset_exists == 'true' && steps.set_dataset_config_vars.outputs.is_config_exists == 'true' }}
run: |
sudo service datadog-agent stop
combine_reports:
name: Combine reports
runs-on: ubuntu-24.04
needs:
- model_regression_test_cpu
- model_regression_test_gpu
if: ${{ always() && ((needs.model_regression_test_cpu.result != 'skipped') != (needs.model_regression_test_gpu.result != 'skipped')) }}
outputs:
success_status: ${{ steps.set-success-status.outputs.success_status }}
steps:
- name: Set success status
id: set-success-status
run: |-
succeeded=${{ needs.model_regression_test_cpu.result == 'success' || needs.model_regression_test_gpu.result == 'success' }}
if [[ $succeeded == "false" ]]; then
success_status="Failed"
elif [[ $succeeded == "true" ]]; then
success_status="Succeeded"
else
success_status="Unknown"
fi
echo $success_status
echo "success_status=$success_status" >> $GITHUB_OUTPUT
- name: Checkout git repository 🕝
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Set up Python 3.10 🐍
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: '3.10'
- name: Get reports
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
with:
path: reports/
- name: Display structure of downloaded files
continue-on-error: true
run: ls -R
working-directory: reports/
- name: Merge all reports
env:
SUMMARY_FILE: "./report.json"
REPORTS_DIR: "reports/"
run: |
python .github/scripts/mr_generate_summary.py
cat $SUMMARY_FILE
- name: Upload an artifact with the overall report
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
with:
name: report.json
path: ./report.json
set_job_success_status:
name: Set job success status
runs-on: ubuntu-24.04
needs:
- combine_reports
if: ${{ always() && needs.combine_reports.result == 'success' }}
steps:
- name: Set return code
run: |
success_status=${{ needs.combine_reports.outputs.success_status }}
echo "Status: $success_status"
if [[ $success_status == "Succeeded" ]]; then
exit 0
else
exit 1
fi
add_comment_results:
name: Add a comment with the results
runs-on: ubuntu-24.04
needs:
- combine_reports
if: ${{ always() && needs.combine_reports.result == 'success' }}
steps:
- name: Checkout
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Download report from last on-schedule regression test
run: |
# Get ID of last on-schedule workflow
SCHEDULE_ID=$(curl -X GET -s -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' -H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ github.repository }}/actions/workflows" \
| jq -r '.workflows[] | select(.name == "CI - Model Regression on schedule") | select(.path | test("schedule")) | .id')
ARTIFACT_URL=$(curl -s -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' -H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ github.repository }}/actions/workflows/${SCHEDULE_ID}/runs?event=schedule&status=completed&branch=main&per_page=1" | jq -r .workflow_runs[0].artifacts_url)
DOWNLOAD_URL=$(curl -s -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' -H "Accept: application/vnd.github.v3+json" "${ARTIFACT_URL}" \
| jq -r '.artifacts[] | select(.name == "report.json") | .archive_download_url')
# Download the artifact
curl -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' -LJO -H "Accept: application/vnd.github.v3+json" $DOWNLOAD_URL
# Unzip and change name
unzip report.json.zip && mv report.json report_main.json
- name: Download the report
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
with:
name: report.json
- name: Download gomplate
run: |-
sudo curl -o /usr/local/bin/gomplate -sSL https://github.com/hairyhenderson/gomplate/releases/download/v3.9.0/gomplate_linux-amd64
sudo chmod +x /usr/local/bin/gomplate
- name: Render a comment to add
id: get_results
run: |
OUTPUT="$(gomplate -d data=report.json -d results_main=report_main.json -f .github/templates/model_regression_test_results.tmpl)"
OUTPUT="${OUTPUT//$'\n'/'%0A'}"
OUTPUT="${OUTPUT//$'\r'/'%0D'}"
echo "result=$OUTPUT" >> $GITHUB_OUTPUT
# Get time of current commit as start time
TIME_ISO_COMMIT=$(gomplate -d github=https://api.github.com/repos/rasaHQ/rasa/commits/${{ github.sha }} -H 'github=Authorization:token ${{ secrets.GITHUB_TOKEN }}' -i '{{ (ds "github").commit.author.date }}') # Example "2022-02-17T14:06:38Z"
TIME_UNIX_COMMIT=$(date -d "${TIME_ISO_COMMIT}" +%s%3N) # Example: "1645106798"
# Get current time
TIME_ISO_NOW=$(gomplate -i '{{ (time.Now).UTC.Format time.RFC3339}}') # Example: "2022-02-17T14:50:54Z%"
TIME_UNIX_NOW=$(date -d "${TIME_ISO_NOW}" +%s%3N) # Example: "1645118083"
echo "from_ts=$TIME_UNIX_COMMIT" >> $GITHUB_OUTPUT
echo "to_ts=$TIME_UNIX_NOW" >> $GITHUB_OUTPUT
- name: Publish results as a PR comment
uses: marocchino/sticky-pull-request-comment@f61b6cf21ef2fcc468f4345cdfcc9bda741d2343 # v2.6.2
if: ${{ always() }}
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
header: ${{ github.run_id }}
append: true
message: |-
Status of the run: ${{ needs.combine_reports.outputs.success_status }}
Commit: ${{ github.sha }}, [The full report is available as an artifact.](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
[Datadog dashboard link](https://app.datadoghq.eu/dashboard/mf4-2hu-x84?tpl_var_branch_baseline=${{ github.head_ref }}&from_ts=${{ steps.get_results.outputs.from_ts }}&to_ts=${{ steps.get_results.outputs.to_ts }}&live=false)
${{ steps.get_results.outputs.result }}
- name: Remove 'status:model-regression-tests' label
continue-on-error: true
uses: buildsville/add-remove-label@6008d7bd99d3baeb7c04033584e68f8ec80b198b # v1.0
with:
token: ${{secrets.GITHUB_TOKEN}}
label: "status:model-regression-tests"
type: remove
- name: Remove 'runner:gpu' label
continue-on-error: true
uses: buildsville/add-remove-label@6008d7bd99d3baeb7c04033584e68f8ec80b198b # v1.0
with:
token: ${{secrets.GITHUB_TOKEN}}
label: "runner:gpu"
type: remove
remove_runner_gpu:
name: Delete Github Runner - GPU
needs:
- deploy_runner_gpu
- model_regression_test_gpu
runs-on: ubuntu-24.04
if: ${{ always() && needs.deploy_runner_gpu.result != 'skipped' && contains(github.event.pull_request.labels.*.name, 'runner:gpu') && contains(github.event.pull_request.labels.*.name, 'status:model-regression-tests') }}
steps:
# Setup gcloud auth
- uses: google-github-actions/auth@e8df18b60c5dd38ba618c121b779307266153fbf
with:
service_account: ${{ secrets.GKE_RASA_CI_GPU_SA_NAME_RASA_CI_CD }}
credentials_json: ${{ secrets.GKE_SA_RASA_CI_CD_GPU_RASA_CI_CD }}
# Get the GKE credentials for the cluster
- name: Get GKE Cluster Credentials
uses: google-github-actions/get-gke-credentials@894c221960ab1bc16a69902f29f090638cca753f
with:
cluster_name: ${{ secrets.GKE_GPU_CLUSTER_RASA_CI_CD }}
location: ${{ env.GKE_ZONE }}
project_id: ${{ secrets.GKE_SA_RASA_CI_GPU_PROJECT_RASA_CI_CD }}
- name: Remove Github Runner
run: kubectl -n github-runner delete deployments github-runner-${GITHUB_RUN_ID} --grace-period=30
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,18 @@
name: Check if dependencies can be updated and create a pull request with updated ones.
on:
schedule:
# Run at 05:00 on Wednesday
- cron: '0 5 * * 3'
jobs:
update_dependencies:
runs-on: ubuntu-24.04
name: Update dependencies
steps:
- uses: RasaHQ/dependabot-batch-updater@f049cbb0bbd3754bcb5ab154a79f00cd780fc633 # v1.0
with:
repo-token: ${{ secrets.RASABOT_GITHUB_TOKEN }}
repository: RasaHQ/rasa
directory: /
package-manager: pip
batch-size: 5
+325
View File
@@ -0,0 +1,325 @@
name: Publish Documentation
on:
push:
branches:
- "main"
- "documentation"
tags:
- "**"
pull_request:
concurrency:
# group workflow runs based on the branch or the tag ref
group: documentation-${{ github.ref }}
cancel-in-progress: true
# SECRETS
# - GH_DOCS_WRITE_KEY: generated locally, added to github repo (public key)
# `ssh-keygen -t rsa -b 4096 -C "Github CI Docs Key" -N "" -f key`
# - GITHUB_TOKEN: (default, from github actions)
# - NETLIFY_AUTH_TOKEN: an access token to use when authenticating commands on Netlify
# - NETLIFY_SITE_ID: the API ID of the Netlify site for the docs
env:
DOCS_FOLDER: docs
DOCS_BRANCH: documentation
IS_TAG_BUILD: ${{ startsWith(github.event.ref, 'refs/tags') }}
IS_MAIN_BRANCH: ${{ github.ref == 'refs/heads/main' }}
jobs:
changes:
name: Check for file changes
runs-on: ubuntu-24.04
# don't run this for pull requests of forks
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'RasaHQ/rasa'
outputs:
# Both of the outputs below are strings but only one exists at any given time
backend: ${{ steps.changed-files.outputs.backend || steps.run-all.outputs.backend }}
docker: ${{ steps.changed-files.outputs.docker || steps.run-all.outputs.docker }}
docs: ${{ steps.changed-files.outputs.docs || steps.run-all.outputs.docs }}
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50
# Run the normal filters if the all-tests-required label is not set
id: changed-files
if: contains(github.event.pull_request.labels.*.name, 'status:all-tests-required') == false
with:
token: ${{ secrets.GITHUB_TOKEN }}
filters: .github/change_filters.yml
- name: Set all filters to true if all tests are required
# Set all filters to true if the all-tests-required label is set
# Bypasses all the change filters in change_filters.yml and forces all outputs to true
id: run-all
if: contains(github.event.pull_request.labels.*.name, 'status:all-tests-required')
run: |
echo "backend=true" >> $GITHUB_OUTPUT
echo "docker=true" >> $GITHUB_OUTPUT
echo "docs=true" >> $GITHUB_OUTPUT
evaluate_release_tag:
name: Evaluate release tag
runs-on: ubuntu-24.04
# don't run this for main branches of forks and on documentation branch
if: github.repository == 'RasaHQ/rasa' && github.ref != 'refs/heads/documentation' && github.event_name != 'pull_request'
outputs:
build_docs: ${{ steps.check_tag.outputs.build_docs }}
steps:
- name: Checkout git repository 🕝
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Install version library
run: |
python3 -m pip install pep440_version_utils
- name: Check if tag version is equal or higher than the latest tagged Rasa version
id: check_tag
if: env.IS_TAG_BUILD == 'true' || env.IS_MAIN_BRANCH == 'true'
run: |
if [[ "${IS_MAIN_BRANCH}" == "true" ]]; then
echo "Main branch: setting build_docs to true."
echo "build_docs=true" >> $GITHUB_OUTPUT
else
# Get latest tagged Rasa version
git describe --tags --match="3.6.[0-9]*" --abbrev=0 HEAD
# Fetch branch history
TAG_NAME=${GITHUB_REF#refs/tags/}
git fetch --prune --unshallow
python scripts/evaluate_release_tag.py $TAG_NAME
exit_status=$?
if [[ ${exit_status} -eq 0 ]]; then
echo "Setting build_docs to true."
echo "build_docs=true" >> $GITHUB_OUTPUT
else
echo "Setting build_docs to false."
echo "build_docs=false" >> $GITHUB_OUTPUT
fi
fi
prebuild_docs:
name: Prebuild Docs
runs-on: ubuntu-24.04
needs: [evaluate_release_tag]
# don't run this for main branches of forks, would fail anyways
if: github.repository == 'RasaHQ/rasa' && needs.evaluate_release_tag.outputs.build_docs == 'true' && github.ref != 'refs/heads/documentation' && github.event_name != 'pull_request'
steps:
- name: Checkout git repository 🕝
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Set up Python 3.10 🐍
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: '3.10'
- name: Set up Node 12.x 🦙
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
with:
node-version: "12.x"
- name: Read Poetry Version 🔢
run: |
echo "POETRY_VERSION=$(scripts/poetry-version.sh)" >> $GITHUB_ENV
shell: bash
- name: Install poetry 🦄
uses: Gr1N/setup-poetry@15821dc8a61bc630db542ae4baf6a7c19a994844 # v8
with:
poetry-version: ${{ env.POETRY_VERSION }}
- name: Load Poetry Cached Libraries ⬇
id: cache-poetry
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: .venv
key: ${{ runner.os }}-poetry-${{ env.POETRY_VERSION }}-3.9-non-full-${{ hashFiles('**/poetry.lock') }}-${{ secrets.POETRY_CACHE_VERSION }}
restore-keys: ${{ runner.os }}-poetry-3.9-non-full
- name: Clear Poetry cache
if: steps.cache-poetry.outputs.cache-hit == 'true'
run: rm -r .venv
- name: Create virtual environment
if: steps.cache-poetry.outputs.cache-hit != 'true'
run: python -m venv create .venv
- name: Set up virtual environment
run: poetry config virtualenvs.in-project true
- name: Load Yarn Cached Packages ⬇
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: docs/node_modules
key: ${{ runner.os }}-yarn-12.x-${{ hashFiles('docs/yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-12.x
- name: Install Dependencies 📦
run: make install install-docs
- name: Pre-build Docs 🧶
run: make prepare-docs
- name: Push docs to documentation branch 🏃‍♀️
env:
GH_DOCS_WRITE_KEY: ${{ secrets.GH_DOCS_WRITE_KEY }}
TMP_DOCS_FOLDER: /tmp/documentation-${{ github.run_id }}
TMP_SSH_KEY_PATH: /tmp/docs_key
run: |
eval "$(ssh-agent -s)"; touch $TMP_SSH_KEY_PATH; chmod 0600 $TMP_SSH_KEY_PATH
echo "$GH_DOCS_WRITE_KEY" > $TMP_SSH_KEY_PATH
ssh-add $TMP_SSH_KEY_PATH
git config --global user.email "builds@github-ci.com"
git config --global user.name "GitHub CI"
git remote set-url --push origin "git@github.com:${{github.repository}}"
./scripts/push_docs_to_branch.sh
- name: Notify slack on failure
if: failure()
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
uses: voxmedia/github-action-slack-notify-build@3665186a8c1a022b28a1dbe0954e73aa9081ea9e # v1.6.0
with:
channel_id: ${{ secrets.SLACK_ALERTS_CHANNEL_ID }}
status: FAILED
color: warning
preview_docs:
name: Preview Docs
runs-on: ubuntu-24.04
needs: [changes]
# don't run this for pull requests from forks
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'RasaHQ/rasa'
steps:
- name: Checkout git repository 🕝
if: needs.changes.outputs.docs == 'true'
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Set up Python 3.10 🐍
if: needs.changes.outputs.docs == 'true'
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: '3.10'
- name: Set up Node 12.x 🦙
if: needs.changes.outputs.docs == 'true'
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
with:
node-version: "12.x"
- name: Read Poetry Version 🔢
if: needs.changes.outputs.docs == 'true'
run: |
echo "POETRY_VERSION=$(scripts/poetry-version.sh)" >> $GITHUB_ENV
shell: bash
- name: Install poetry 🦄
if: needs.changes.outputs.docs == 'true'
uses: Gr1N/setup-poetry@15821dc8a61bc630db542ae4baf6a7c19a994844 # v8
with:
poetry-version: ${{ env.POETRY_VERSION }}
- name: Load Poetry Cached Libraries ⬇
id: cache-poetry
if: needs.changes.outputs.docs == 'true'
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: .venv
key: ${{ runner.os }}-poetry-${{ env.POETRY_VERSION }}-3.9-non-full-${{ hashFiles('**/poetry.lock') }}-${{ secrets.POETRY_CACHE_VERSION }}
restore-keys: ${{ runner.os }}-poetry-3.9-non-full
- name: Clear Poetry cache
if: steps.cache-poetry.outputs.cache-hit == 'true' && needs.changes.outputs.docs == 'true' && contains(github.event.pull_request.labels.*.name, 'tools:clear-poetry-cache-preview-docs')
run: rm -r .venv
- name: Create virtual environment
if: (steps.cache-poetry.outputs.cache-hit != 'true' || contains(github.event.pull_request.labels.*.name, 'tools:clear-poetry-cache-preview-docs')) && needs.changes.outputs.docs == 'true'
run: python -m venv create .venv
- name: Set up virtual environment
if: needs.changes.outputs.docs == 'true'
run: poetry config virtualenvs.in-project true
- name: Load Yarn Cached Packages ⬇
if: needs.changes.outputs.docs == 'true'
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: docs/node_modules
key: ${{ runner.os }}-yarn-12.x-${{ hashFiles('docs/yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-12.x
- name: Install Dependencies 📦
if: needs.changes.outputs.docs == 'true'
run: make install install-docs
- name: Pre-build Docs 🧶
if: needs.changes.outputs.docs == 'true'
run: make prepare-docs
- name: Preview draft build 🔬
if: needs.changes.outputs.docs == 'true'
id: preview_draft_build
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
DOCS_SITE_BASE_URL: /docs/rasa
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
run: |
make preview-docs
DEPLOY_URL="https://$PULL_REQUEST_NUMBER--rasahq-docs-rasa-v2.netlify.app${DOCS_SITE_BASE_URL}"
echo "preview_url=$DEPLOY_URL" >> $GITHUB_OUTPUT
- name: Create a comment with help description
if: needs.changes.outputs.docs == 'true'
uses: RasaHQ/create-comment@da7b2ec20116674919493bb5894eea70fdaa6486
with:
mode: "delete-previous"
id: comment_docs_previews
github-token: ${{ secrets.GITHUB_TOKEN }}
body: |
🚀 A preview of the docs have been deployed at the following URL: ${{ steps.preview_draft_build.outputs.preview_url }}
publish_docs:
name: Publish Docs
runs-on: ubuntu-24.04
# don't run this for main branches of forks; only run on documentation branch
if: github.repository == 'RasaHQ/rasa' && github.ref == 'refs/heads/documentation'
steps:
- name: Checkout git repository 🕝
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Set up Node 12.x 🦙
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
with:
node-version: "12.x"
- name: Load Yarn Cached Packages ⬇
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: docs/node_modules
key: ${{ runner.os }}-yarn-12.x-${{ hashFiles('docs/yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-12.x
- name: Install Dependencies 📦
run: make install-docs
- name: Publish production build ✅
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
run: make publish-docs
- name: Notify slack on failure
if: failure()
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
uses: voxmedia/github-action-slack-notify-build@3665186a8c1a022b28a1dbe0954e73aa9081ea9e # v1.6.0
with:
channel_id: ${{ secrets.SLACK_ALERTS_CHANNEL_ID }}
status: FAILED
color: warning
+178
View File
@@ -0,0 +1,178 @@
name: Nightly Builds
on:
schedule:
# Runs every weekday at 1am
- cron: 0 1 * * 1-5
workflow_dispatch:
jobs:
run_script_and_tag_nightly_release:
name: Run release script and tag a new nightly release
runs-on: ubuntu-24.04
outputs:
tag_name: ${{ steps.set_tagname.outputs.tag_name }}
steps:
- name: Checkout git repository 🕝
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Python module
run: |
python3 -m pip install pluggy
python3 -m pip install ruamel.yaml
- name: Compose tag name
id: set_tagname
run: |
DATE=$(date +'%Y%m%d')
# Find latest rasa-oss version
echo "Trying to find the latest rasa-oss version..."
LATEST_RASA_MINOR=$(python -c "import sys; import os; sys.path.append('${{ github.workspace }}/rasa'); from rasa.version import __version__; print(__version__)")
echo "Current RASA version: ${LATEST_RASA_MINOR}"
LATEST_NIGHTLY_VERSION=$(echo ${LATEST_RASA_MINOR})
echo "Composing nightly build tag name..."
GH_TAG=${LATEST_NIGHTLY_VERSION}.dev${DATE}
echo "New nightly release version: ${GH_TAG}"
echo "tag_name=${GH_TAG}" >> $GITHUB_OUTPUT
- name: Tag latest main commit as nightly
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git tag -a ${{ steps.set_tagname.outputs.tag_name }} -m "This is an internal development build"
git push origin ${{ steps.set_tagname.outputs.tag_name }} --tags
deploy:
name: Deploy to PyPI
runs-on: ubuntu-24.04
# deploy will only be run when there is a tag available
needs: run_script_and_tag_nightly_release # only run after all other stages succeeded
steps:
- name: Checkout git repository 🕝
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Set up Python 3.9 🐍
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: 3.9
- name: Read Poetry Version 🔢
run: |
echo "POETRY_VERSION=$(scripts/poetry-version.sh)" >> $GITHUB_ENV
shell: bash
- name: Install poetry 🦄
uses: Gr1N/setup-poetry@15821dc8a61bc630db542ae4baf6a7c19a994844 # v8
with:
poetry-version: ${{ env.POETRY_VERSION }}
- name: Copy Segment write key to the package
env:
RASA_TELEMETRY_WRITE_KEY: ${{ secrets.RASA_OSS_TELEMETRY_WRITE_KEY }}
RASA_EXCEPTION_WRITE_KEY: ${{ secrets.RASA_OSS_EXCEPTION_WRITE_KEY }}
run: |
./scripts/write_keys_file.sh
- name: Update version (nightly releases) 🚀
run: |
poetry run pip install toml pep440_version_utils
poetry run python ./scripts/prepare_nightly_release.py --next_version "${{ needs.run_script_and_tag_nightly_release.outputs.tag_name }}"
- name: Build ⚒️ Distributions
run: |
poetry build
# Authenticate and push to the release registry
- id: 'auth-release'
name: Authenticate with gcloud for release registry 🎫
uses: 'google-github-actions/auth@e8df18b60c5dd38ba618c121b779307266153fbf'
with:
credentials_json: '${{ secrets.RASA_OSS_RELEASE_ACCOUNT_KEY }}'
- name: 'Set up Cloud SDK'
uses: 'google-github-actions/setup-gcloud@62d4898025f6041e16b1068643bfc5a696863587'
- name: Release via GCP Artifact Registry
run: |
pip install keyring
pip install keyrings.google-artifactregistry-auth
pip install twine
gcloud artifacts print-settings python --project=rasa-releases --repository=rasa --location=europe-west3 > ~/.pypirc
twine upload --verbose --repository-url https://europe-west3-python.pkg.dev/rasa-releases/rasa/ ${{ format('{0}/dist/*', github.workspace) }}
docker:
name: Build Docker
runs-on: ubuntu-24.04
needs: run_script_and_tag_nightly_release
env:
GCLOUD_VERSION: "297.0.1"
# Registry used to store Docker images used for release purposes
DEV_REGISTRY: "europe-west3-docker.pkg.dev/rasa-ci-cd/rasa"
IMAGE_TAG: ${{ needs.run_script_and_tag_nightly_release.outputs.tag_name }}
steps:
- name: Checkout git repository 🕝
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Free disk space
# tries to make sure we do not run out of disk space, see
# https://github.community/t5/GitHub-Actions/BUG-Strange-quot-No-space-left-on-device-quot-IOExceptions-on/td-p/46101
run: |
sudo swapoff -a
sudo rm -f /swapfile
sudo apt clean
docker rmi $(docker image ls -aq)
df -h
- name: Read Poetry Version 🔢
run: |
echo "POETRY_VERSION=$(scripts/poetry-version.sh)" >> $GITHUB_ENV
shell: bash
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c
id: buildx
with:
version: v0.5.1
driver: docker
- name: Copy Segment write key to the package
env:
RASA_TELEMETRY_WRITE_KEY: ${{ secrets.RASA_OSS_TELEMETRY_WRITE_KEY }}
RASA_EXCEPTION_WRITE_KEY: ${{ secrets.RASA_OSS_EXCEPTION_WRITE_KEY }}
run: |
./scripts/write_keys_file.sh
- name: Build Docker image
run: |
docker build . -t rasa/rasa:base-localdev -f docker/Dockerfile.base
docker build . -t rasa/rasa:base-builder-localdev -f docker/Dockerfile.base-builder --build-arg IMAGE_BASE_NAME=rasa/rasa --build-arg POETRY_VERSION=${{ env.POETRY_VERSION }}
docker build . -t rasa/rasa:base-poetry -f docker/Dockerfile.base-poetry --build-arg IMAGE_BASE_NAME=rasa/rasa --build-arg BASE_IMAGE_HASH=localdev
docker build . -t rasa/rasa:${IMAGE_TAG} -f Dockerfile --build-arg IMAGE_BASE_NAME=rasa/rasa --build-arg BASE_IMAGE_HASH=localdev --build-arg BASE_BUILDER_IMAGE_HASH=localdev
docker tag rasa/rasa:${IMAGE_TAG} ${{env.DEV_REGISTRY}}/rasa:${IMAGE_TAG}
# Authenticate and push to the release registry
- id: 'auth-dev'
name: Authenticate with gcloud for dev registry 🎫
uses: 'google-github-actions/auth@e8df18b60c5dd38ba618c121b779307266153fbf'
with:
credentials_json: '${{ secrets.RASA_OSS_RELEASE_ACCOUNT_KEY }}'
- name: Authenticate docker for dev registry 🎫
run: |
# Set up docker to authenticate via gcloud command-line tool.
gcloud auth configure-docker europe-west3-docker.pkg.dev
- name: Push image to release registry
run: |
docker push ${{env.DEV_REGISTRY}}/rasa:${IMAGE_TAG}
@@ -0,0 +1,48 @@
# This is a installation test that we run daily. We attempt to install Rasa
# on Ubuntu, Mac and Windows and try to run `rasa init`. The goal here is to
# catch installation issues in an automated way.
name: Cron Test to Check Pip Installation
on:
schedule:
- cron: "0 0 * * *"
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
[ubuntu-24.04, ubuntu-18.04, macos-latest, windows-2019, windows-2022]
python-version: [3.8, 3.9, '3.10']
fail-fast: false
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: ${{ matrix.python-version }}
- name: Try to install Rasa.
run: |
python -m pip install rasa
- name: Try to install Rasa[full].
run: |
python -m pip install rasa[full]
- name: Try to run Rasa.
run: |
python -m rasa --version
# Must create a folder first
mkdir rasa-demo
# Next we try to init.
python -m rasa init --init-dir rasa-demo --no-prompt
- name: Notify slack on failure
if: failure()
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
uses: voxmedia/github-action-slack-notify-build@3665186a8c1a022b28a1dbe0954e73aa9081ea9e
with:
channel_id: ${{ secrets.SLACK_ALERTS_CHANNEL_ID }}
status: FAILED
color: danger
+131
View File
@@ -0,0 +1,131 @@
name: Security Scans
on:
pull_request:
types: [opened, synchronize, labeled]
concurrency:
group: security-scans-${{ github.head_ref }} # head branch name
cancel-in-progress: true
jobs:
changes:
name: Check for file changes
runs-on: ubuntu-24.04
outputs:
backend: ${{ steps.filter.outputs.backend }}
docker: ${{ steps.filter.outputs.docker }}
docs: ${{ steps.filter.outputs.docs }}
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50
id: filter
with:
token: ${{ secrets.GITHUB_TOKEN }}
filters: .github/change_filters.yml
trivy:
name: Detecting hardcoded secrets
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
with:
# Fetch all history for all tags and branches
fetch-depth: '0'
- name: Run Trivy vulnerability scanner
id: trivy
uses: aquasecurity/trivy-action@e5f43133f6e8736992c9f3c1b3296e24b37e17f2
continue-on-error: true
with:
format: 'table'
scan-type: 'fs'
exit-code: '1'
scanners: 'secret'
- name: Alert on secret finding
if: steps.trivy.outcome == 'failure'
uses: slackapi/slack-github-action@007b2c3c751a190b6f0f040e47ed024deaa72844
with:
payload: |
{
"text": "*A secret was detected in a GitHub commit in the repo ${{ github.repository }}.*\n${{ github.event.pull_request.html_url || github.event.head_commit.url }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*A secret was detected in a GitHub commit in the repo ${{ github.repository }}.*\n${{ github.event.pull_request.html_url || github.event.head_commit.url }}"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CODESECURITY_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
- name: Fail build if a secret is found
if: steps.trivy.outcome == 'failure'
run: |
echo "=========================================================="
echo "| This build has failed because Trivy detected a secret. |"
echo "=========================================================="
echo "1. Check the step 'Run Trivy vulnerability scanner' for output to help you find the secret."
echo "2. If the finding is a false positive, add it as an entry to trivy-secret.yaml in the root of the repo to suppress the finding."
echo "3. If the finding is valid, the security team can help advise your next steps."
exit 1
bandit:
name: Detect python security issues
runs-on: ubuntu-24.04
needs: [changes]
steps:
- name: Checkout git repository 🕝
if: needs.changes.outputs.backend == 'true'
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- name: Set up Python 3.10 🐍
if: needs.changes.outputs.backend == 'true'
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
with:
python-version: '3.10'
- name: Read Poetry Version 🔢
if: needs.changes.outputs.backend == 'true'
run: |
echo "POETRY_VERSION=$(scripts/poetry-version.sh)" >> $GITHUB_ENV
shell: bash
- name: Install poetry 🦄
if: needs.changes.outputs.backend == 'true'
uses: Gr1N/setup-poetry@15821dc8a61bc630db542ae4baf6a7c19a994844 # v8
with:
poetry-version: ${{ env.POETRY_VERSION }}
- name: Load Poetry Cached Libraries ⬇
id: cache-poetry
if: needs.changes.outputs.backend == 'true'
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: .venv
key: ${{ runner.os }}-poetry-${{ env.POETRY_VERSION }}-3.9-${{ hashFiles('**/poetry.lock') }}-${{ secrets.POETRY_CACHE_VERSION }}
restore-keys: ${{ runner.os }}-poetry-3.9
- name: Clear Poetry cache
if: steps.cache-poetry.outputs.cache-hit == 'true' && needs.changes.outputs.backend == 'true' && contains(github.event.pull_request.labels.*.name, 'tools:clear-poetry-cache-security-scans')
run: rm -r .venv
- name: Create virtual environment
if: (steps.cache-poetry.outputs.cache-hit != 'true' || contains(github.event.pull_request.labels.*.name, 'tools:clear-poetry-cache-security-scans')) && needs.changes.outputs.backend == 'true'
run: python -m venv create .venv
- name: Set up virtual environment
if: needs.changes.outputs.backend == 'true'
run: poetry config virtualenvs.in-project true
- name: Install Dependencies (Linux) 📦
if: needs.changes.outputs.backend == 'true'
run: make install
- name: Run Bandit 🔪
if: needs.changes.outputs.backend == 'true'
run: make lint-security
+33
View File
@@ -0,0 +1,33 @@
# Name of this GitHub Actions workflow.
name: Semgrep
on:
# Scan mainline branches and report all findings:
push:
branches:
- main
# Scan changed files in PRs (diff-aware scanning):
pull_request:
jobs:
semgrep:
# User-definable name of this GitHub Actions job:
name: Semgrep Workflow Security Scan
# If you are self-hosting, change the following `runs-on` value:
runs-on: ubuntu-24.04
container:
# A Docker image with Semgrep installed. Do not change this.
image: returntocorp/semgrep@sha256:37736e4992c539f760e36e14d48924bd9fa70d0abbde39a6d86d93f66a1affd4
# To skip any PR created by dependabot to avoid permission issues:
if: (github.actor != 'dependabot[bot]')
steps:
# Fetch project source with GitHub Actions Checkout.
- uses: actions/checkout@v3
# Run the "semgrep ci" command on the command line of the docker image.
- run: semgrep ci
env:
# Add the rules that Semgrep uses by setting the SEMGREP_RULES environment variable.
SEMGREP_RULES: p/github-actions
+21
View File
@@ -0,0 +1,21 @@
name: Typo CI
on:
push:
branches-ignore:
- main
jobs:
spellcheck:
name: Typo CI (GitHub Action)
runs-on: ubuntu-24.04
timeout-minutes: 4
if: "!contains(github.event.head_commit.message, '[ci skip]')"
steps:
- name: TypoCheck
uses: typoci/spellcheck-action@a63b1430c8f0ceed9fd0bd0f3ad8f7466e6c695d # v1.1.0
# with:
# A license can be purchased via:
# https://gumroad.com/l/MvvBE
# typo_ci_license_key: ${{ secrets.TYPO_CI_LICENSE_KEY }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+91
View File
@@ -0,0 +1,91 @@
*~
*pyc
*.DS_Store
*.egg
*.eggs
*.egg-info
*.log
*.pyc
*.sass-cache
*build/
*dat
.env
venv
.pytest_cache/
.ipynb_checkpoints
.ruby-version
.tox
.mypy_cache/
dist/
pip-wheel-metadata
server/
scala/
mongodb/
.cache/
build/
*.egg-info/
jnk/
logs/
tmp/
profile.*
*.sqlite
lastmile_ai/learn/plots/
*npy
*#
/config.json
*log.json
.coverage
.coveralls.yml
.idea/
.venv/
*.iml
out/
.vscode/
tmp_training_data.json
.DS_Store
models/
.mypy_cache/
*.tar.gz
secrets.tar
.pytest_cache
test_download.zip
bower_components/
build/lib/
/models/
node_modules/
npm-debug.log
examples/moodbot/py3/
.python-version
tokens.dat
graph.png
graph.html
story_graph.html
story_graph.dot
debug.md
examples/moodbot/*.png
examples/moodbot/errors.json
examples/formbot/models*
examples/concertbot/models*
examples/moodbot/models*
examples/e2ebot/results/*
failed_stories.md
errors.json
pip-wheel-metadata/*
events.db
events.db-shm
events.db-wal
rasa.db
rasa.db-shm
rasa.db-wal
*.swp
*.coverage*
env
.dir-locals.el
.history
rasa/segment_key
rasa/keys
.rasa
/results/
# Local Netlify folder
.netlify
rasa.code-workspace
+3
View File
@@ -0,0 +1,3 @@
whitelist:
- status:ready-to-merge
method: merge
+19
View File
@@ -0,0 +1,19 @@
repos:
- repo: https://github.com/ambv/black
rev: 22.10.0
hooks:
- id: black
args: [--line-length=88]
- repo: https://github.com/thlorenz/doctoc
rev: v2.1.0
hooks:
- id: doctoc
files: "CONTRIBUTING.md"
- repo: local
hooks:
- id: docstring-check
name: docstring-check
entry: bash -c 'make lint-docstrings'
language: system
types: [python]
pass_filenames: false
+209
View File
@@ -0,0 +1,209 @@
# This is a sample .typo-ci.yml file, it's used to configure how Typo CI will behave.
# Add it to the root of your project and push it to github.
---
# What language dictionaries should it use? Currently Typo CI supports:
# de
# en
# en_GB
# es
# fr
# it
# pt
# pt_BR
dictionaries:
- en
# # Any files/folders we should ignore?
excluded_files:
- "*.py"
- "*.css"
- "*.scss"
- "*.yml"
- "*.yaml"
- "*.html"
- "*.json"
- "*.lock"
- "*.js"
- "*.jsx"
- "*.ts"
- "*.tsx"
- "*.md"
- "CHANGELOG.mdx"
- "CODE_OF_CONDUCT.md"
- "CONTRIBUTING.md"
- "Dockerfile"
- "LICENSE.txt"
- "Makefile"
- "NOTICE"
- "README.md"
- "cloudbuild.yaml"
- "pyproject.toml"
- "secrets.tar.enc"
- "setup.cfg"
- ".codeclimate.yml"
- ".coveragerc"
- ".deepsource.toml"
- ".dockerignore"
- ".env"
- ".git"
- ".gitattributes"
- ".gitignore"
- ".pre-commit-config.yaml"
- ".typo-ci.yml"
- ".github/**/*"
- "binder/**/*"
- "data/**/*"
- "docker/**/*"
- "examples/**/*"
- "rasa/**/*"
- "scripts/**/*"
- "tests/**/*"
# # Any typos we should ignore?
excluded_words:
- analytics
- asyncio
- bot
- bot's
- cdd
- CDD
- cmdline
- conveRT
- ConveRTFeaturizer
- ConveRTTokenizer
- crfsuite
- custom-nlg-service
- daksh
- db's
- deque
- docusaurus
- non-latin
- deduplicate
- deduplication
- donath
- matplotlib
- extractor
- fbmessenger
- featurization
- featurize
- featurized
- featurizer
- featurizers
- featurizes
- featurizing
- forni
- gzip
- gzipped
- hftransformersnlp
- initializer
- instaclient
- jwt
- jwt's
- jupyter
- jupyterhub
- karpathy
- keras
- knowledgebase
- knowledgebasebot
- linenos
- luis
- matmul
- mattermost
- memoization
- miniconda
- mitie
- mitiefeaturizer
- mitie's
- mitienlp
- dataset
- mongod
- mrkdown
- mrkdwn
- myio
- mymodelname
- myuser
- numpy
- networkx
- nlu
- nlu's
- perceptron
- pika
- pika's
- jieba
- pretrained
- prototyper
- pycodestyle
- pykwalify
- pymessenger
- pyobject
- python-engineio
- pre
- customizable
- quickstart
- rasa
- rasa's
- readthedocs
- regularizer
- repo
- rst
- sanic
- sanitization
- scipy
- sklearn
- socketio
- spacy
- spacyfeaturizer
- spacynlp
- ish
- spaCy
- spaCy's
- README
- crf
- backends
- whitespaced
- ngram
- subsampled
- testagent
- tokenize
- tokenized
- tokenization
- tokenizer
- tokenizers
- tokenizing
- typoci
- unfeaturized
- unschedule
- wsgi
- ruamel
- prototyper
- hallo
- crypto
- regexes
- walkthroughs
- webexteams
- venv
- regexfeaturizer
- crfentityextractor
- Comerica
- entitysynonymmapper
- memoizationpolicy
- NLG
- nlg
- Juste
- Tanja
- Vova
- rustup
- rustup-init
- rustc
- conftest
- winpty
- pii-management
- anonymization
- anonymized
- dslim
- pluggy
- HookimplMarker
- hookimpl
spellcheck_filenames: false
+5641
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
/docs/docs/prototype-an-assistant.mdx @RasaHQ/atom-squad
/.github/workflows/ @RasaHQ/infrastructure-squad
/rasa/ @RasaHQ/dev-tribe-engineers
+46
View File
@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at tom@rasa.ai or alan@rasa.ai. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
+203
View File
@@ -0,0 +1,203 @@
<div class="toc">
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [How to open a GitHub issue & file a bug report](#how-to-open-a-github-issue--file-a-bug-report)
- [Working on a new feature or filing a bug report](#working-on-a-new-feature-or-filing-a-bug-report)
- [Working on an existing feature](#working-on-an-existing-feature)
- [How to open a GitHub Pull Request](#how-to-open-a-github-pull-request)
- [What is a Pull Request (PR)?](#what-is-a-pull-request-pr)
- [What to know before opening a PR](#what-to-know-before-opening-a-pr)
- [Opening issues before PRs](#opening-issues-before-prs)
- [Draft PRs](#draft-prs)
- [PRs should be a reasonable length](#prs-should-be-a-reasonable-length)
- [Code style](#code-style)
- [Formatting and Type Checking](#formatting-and-type-checking)
- [How to open a PR and contribute code to Rasa Open Source](#how-to-open-a-pr-and-contribute-code-to-rasa-open-source)
- [1. Forking the Rasa Repository](#1-forking-the-rasa-repository)
- [2. Cloning the Forked Repository Locally](#2-cloning-the-forked-repository-locally)
- [3. Update your Forked Repository](#3-update-your-forked-repository)
- [4. Implement your code contribution](#4-implement-your-code-contribution)
- [5. Push changes to your forked repository on GitHub](#5-push-changes-to-your-forked-repository-on-github)
- [6. Opening the Pull Request on Rasa Open Source](#6-opening-the-pull-request-on-rasa-open-source)
- [7. Signing the Contributor Licence Agreement (CLA)](#7-signing-the-contributor-licence-agreement-cla)
- [8. Merging your PR and the final steps of your contribution](#8-merging-your-pr-and-the-final-steps-of-your-contribution)
- [9. Share your contributions with the world!](#9-share-your-contributions-with-the-world)
- [10. Non-code contributions](#10-non-code-contributions)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
</div>
---
## How to open a GitHub issue & file a bug report
### Working on a new feature or fixing a bug
If you would like to add a new feature or fix an existing bug, we prefer that you open a new issue on the Rasa repository before creating a pull request.
Its important to note that when opening an issue, you should first do a quick search of existing issues to make sure your suggestion hasnt already been added as an issue.
If your issue doesnt already exist, and youre ready to create a new one, make sure to state what you would like to implement, improve or bugfix. We have provided templates to make this process easier for you.
**To open a Github issue, go to the RasaHQ repository, select “Issues”, “New Issue” then “Feature Request” or “Bug Report” and fill out the template.**
![](https://www.rasa.com/assets/img/contributor-guidelines/opening-new-issue.png)
The Rasa team will then get in touch with you to discuss if the proposed feature aligns with the company's roadmap, and we will guide you along the way in shaping the proposed feature so that it could be merged to the Rasa codebase.
### Working on an existing feature
If you want to contribute code, but don't know what to work on, check out the Rasa contributors board to find existing open issues.
The issues are handpicked by the Rasa team to have labels which correspond to the difficulty/estimated time needed to resolve the issue.
**To work on an existing issue, go to the contributor project board, add a comment stating you would like to work on it and include any solutions you may already have in mind.**
![](https://www.rasa.com/assets/img/contributor-guidelines/exiting-issue-sara.png)
Someone from Rasa will then assign that issue to you and help you along the way.
---
## How to open a GitHub Pull Request
### What is a Pull Request (PR)?
This is how the GitHub team defines a PR:
> “Pull requests let you tell others about changes youve pushed to a branch in a repository on GitHub. Once a pull request is opened, you can discuss and review the potential changes with collaborators and add follow-up commits before your changes are merged into the base branch.”
This process is used by both Rasa team members and Rasa contributors to make changes and improvements to Rasa Open Source.
### What to know before opening a PR
#### Opening issues before PRs
We usually recommend opening an issue before a pull request if there isnt already an issue for the problem youd like to solve. This helps facilitate a discussion before deciding on an implementation. See How to open a GitHub issue & file a bug report.
#### Draft PRs
If you're ready to get some quick initial feedback from the Rasa team, you can create a draft pull request.
#### PRs should be a reasonable length
If your PR is greater than 500 lines, please consider splitting it into multiple smaller contributions.
#### Code style
To ensure a standardized code style we recommend using formatter black. To ensure our type annotations are correct we also suggest using the type checker `mypy`.
#### Formatting and Type Checking
If you want to automatically format your code on every commit, you can use pre-commit. Just install it via `pip install pre-commit` and execute `pre-commit install` in the root folder. This will add a hook to the repository, which reformats files on every commit.
If you want to set it up manually, install black via `pip install -r requirements-dev.txt.` To reformat files execute `make formatter`.
If you want to check types on the codebase, install `mypy` using `poetry install`. To check the types execute `make types`.
The CI/CD tests that we run can be found in the [continous-integration.yml](https://github.com/RasaHQ/rasa/blob/main/.github/workflows/continous-integration.yml) file.
---
## How to open a PR and contribute code to Rasa Open Source
#### 1. Forking the Rasa Repository
Head to Rasa repository and click Fork. Forking a repository creates you a copy of the project which you can edit and use to propose changes to the original project.
![](https://www.rasa.com/assets/img/contributor-guidelines/fork.png)
Once you fork it, a copy of the Rasa repository will appear inside your GitHub repository list.
#### 2. Cloning the Forked Repository Locally
To make changes to your copy of the Rasa repository, clone the repository on your local machine. To do that, run the following command in your terminal:
```
git clone https://github.com/your_github_username/rasa.git
```
The link to the repository can be found after clicking Clone or download button as shown in the image below:
![](https://www.rasa.com/assets/img/contributor-guidelines/clone.png)
Note: this assumes you have git installed on your local machine. If not, check out the [following guide](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) to learn how to install it.
#### 3. Update your Forked Repository
Before you make any changes to your cloned repository, make sure you have the latest version of the original Rasa repository. To do that, run the following commands in your terminal:
```
cd rasa
git remote add upstream git://github.com/RasaHQ/rasa.git
git pull upstream main
```
This will update the local copy of the Rasa repository to the latest version.
#### 4. Implement your code contribution
At this point, you are good to make changes to the files in the local directory of your project.
Alternatively, you can create a new branch which will contain the implementation of your contribution. To do that, run:
```
git checkout -b name-of-your-new-branch
```
#### 5. Push changes to your forked repository on GitHub
Once you are happy with the changes you made in the local files, push them to the forked repository on GitHub. To do that, run the following commands:
```
git add .
git commit -m fixed a bug
git push origin name-of-your-new-branch
```
This will create a new branch on your forked Rasa repository, and now youre ready to create a Pull Request with your proposed changes!
#### 6. Opening the Pull Request on Rasa Open Source
Head to the forked repository and click on a _Compare & pull_ request button.
![](https://www.rasa.com/assets/img/contributor-guidelines/openpr-1.png)
This will open a window where you can choose the repository and branch you would like to propose your changes to, as well as specific details of your contribution. In the top panel menu choose the following details:
- Base repository: `RasaHQ/rasa`
- Base branch: `main`
- Head repository: `your-github-username/rasa`
- Head branch: `name-of-your-new-branch`
![](https://www.rasa.com/assets/img/contributor-guidelines/openpr-2.png)
Next, make sure to update the pull request card with as many details about your contribution as possible. _Proposed changes_ section should contain the details of what has been fixed/implemented, and Status should reflect the status of your contributions. Any reasonable change (not like a typo) should include a changelog entry, a bug fix should have a test, a new feature should have documentation, etc.
If you are ready to get feedback on your contribution from the Rasa team, tick the _made PR ready for code review_ and _allow edits from maintainers_ box.
Once you are happy with everything, click the _Create pull request_ button. This will create a Pull Request with your proposed changes.
![](https://www.rasa.com/assets/img/contributor-guidelines/openpr-3.png)
#### 7. Signing the Contributor Licence Agreement (CLA)
To merge your contributions to the Rasa codebase, you will have to sign a Contributor License Agreement (CLA).
It is necessary for us to know that you agree for your code to be included into the Rasa codebase and allow us to use it in our later releases. You can find a detailed Rasa Contributor Licence Agreement [here](https://cla-assistant.io/RasaHQ/rasa).
#### 8. Merging your PR and the final steps of your contribution
Once you sign the CLA, a member from the Rasa team will get in touch with you with the feedback on your contribution. In some cases, contributions are accepted right away, but often, you may be asked to make some edits/improvements. Dont worry if you are asked to change something - its a completely normal part of software development.
If you have been requested to make changes to your contribution, head back to the local copy of your repository on your machine, implement the changes and push them to your contribution branch by repeating instructions from step 5. Your pull request will automatically be updated with the changes you pushed. Once you've implemented all of the suggested changes, tag the person who first reviewed your contribution by mentioning them in the comments of your PR to ask them to take another look.
Finally, if your contribution is accepted, the Rasa team member will merge it to the Rasa codebase.
#### 9. Share your contributions with the world!
Contributing to open source can take a lot of time and effort, so you should be proud of the great work you have done!
Let the world know that you have become a contributor to the Rasa open source project by posting about it on your social media (make sure to tag @RasaHQ as well), mention the contribution on your CV and get ready to get some really cool [Rasa contributor swag](https://blog.rasa.com/announcing-the-rasa-contributor-program/)!
#### 10. Non-code contributions
Contributing doesnt start and end with code. You can support the project by planning community events, creating tutorials, helping fellow community members find answers to their questions or translating documentation and news. Every contribution matters! You can find more details [on our website](https://rasa.com/community/contribute/).
+48
View File
@@ -0,0 +1,48 @@
# The default Docker image
ARG IMAGE_BASE_NAME
ARG BASE_IMAGE_HASH
ARG BASE_BUILDER_IMAGE_HASH
FROM ${IMAGE_BASE_NAME}:base-builder-${BASE_BUILDER_IMAGE_HASH} as builder
# copy files
COPY . /build/
# change working directory
WORKDIR /build
# install dependencies
RUN python -m venv /opt/venv && \
. /opt/venv/bin/activate && \
pip install --no-cache-dir -U "pip==22.*" -U "wheel>0.38.0" && \
poetry install --no-dev --no-root --no-interaction && \
poetry build -f wheel -n && \
pip install --no-deps dist/*.whl && \
rm -rf dist *.egg-info
# start a new build stage
FROM ${IMAGE_BASE_NAME}:base-${BASE_IMAGE_HASH} as runner
# copy everything from /opt
COPY --from=builder /opt/venv /opt/venv
# make sure we use the virtualenv
ENV PATH="/opt/venv/bin:$PATH"
# set HOME environment variable
ENV HOME=/app
# update permissions & change user to not run as root
WORKDIR /app
RUN chgrp -R 0 /app && chmod -R g=u /app && chmod o+wr /app
USER 1001
# create a volume for temporary data
VOLUME /tmp
# change shell
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# the entry point
EXPOSE 5005
ENTRYPOINT ["rasa"]
CMD ["--help"]
+201
View File
@@ -0,0 +1,201 @@
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 2022 Rasa Technologies GmbH
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.
+290
View File
@@ -0,0 +1,290 @@
.PHONY: clean test lint init docs format formatter build-docker build-docker-full build-docker-mitie-en build-docker-spacy-en build-docker-spacy-de
JOBS ?= 1
INTEGRATION_TEST_FOLDER = tests/integration_tests/
INTEGRATION_TEST_PYTEST_MARKERS ?= "sequential or broker or ((not sequential) and (not broker))"
PLATFORM ?= "linux/amd64"
help:
@echo "make"
@echo " clean"
@echo " Remove Python/build artifacts."
@echo " install"
@echo " Install rasa."
@echo " install-full"
@echo " Install rasa with all extras (transformers, tensorflow_text, spacy, jieba)."
@echo " formatter"
@echo " Apply black formatting to code."
@echo " lint"
@echo " Lint code with ruff, and check if black formatter should be applied."
@echo " lint-docstrings"
@echo " Check docstring conventions in changed files."
@echo " types"
@echo " Check for type errors using mypy."
@echo " static-checks"
@echo " Run all python static checks."
@echo " prepare-tests-ubuntu"
@echo " Install system requirements for running tests on Ubuntu and Debian based systems."
@echo " prepare-tests-macos"
@echo " Install system requirements for running tests on macOS."
@echo " prepare-tests-windows"
@echo " Install system requirements for running tests on Windows."
@echo " prepare-spacy"
@echo " Download models needed for spacy tests."
@echo " prepare-mitie"
@echo " Download the standard english mitie model."
@echo " prepare-transformers"
@echo " Download all models needed for testing LanguageModelFeaturizer."
@echo " test"
@echo " Run pytest on tests/."
@echo " Use the JOBS environment variable to configure number of workers (default: 1)."
@echo " test-integration"
@echo " Run integration tests using pytest."
@echo " Use the JOBS environment variable to configure number of workers (default: 1)."
@echo " livedocs"
@echo " Build the docs locally."
@echo " release"
@echo " Prepare a release."
@echo " build-docker"
@echo " Build Rasa Open Source Docker image."
@echo " run-integration-containers"
@echo " Run the integration test containers."
@echo " stop-integration-containers"
@echo " Stop the integration test containers."
clean:
find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +
rm -rf build/
rm -rf .mypy_cache/
rm -rf dist/
rm -rf docs/build
rm -rf docs/.docusaurus
install:
poetry run python -m pip install -U pip
poetry install
install-mitie:
poetry run python -m pip install -U pip
poetry run python -m pip install -U git+https://github.com/tmbo/MITIE.git#egg=mitie
install-full: install-mitie
poetry install -E full
install-docs:
cd docs/ && yarn install
formatter:
poetry run black rasa tests
format: formatter
lint:
# Ignore docstring errors when running on the entire project
poetry run ruff check rasa tests --ignore D
poetry run black --check rasa tests
make lint-docstrings
# Compare against `main` if no branch was provided
BRANCH ?= main
lint-docstrings:
./scripts/lint_python_docstrings.sh $(BRANCH)
lint-changelog:
./scripts/lint_changelog_files.sh
lint-security:
poetry run bandit -ll -ii -r --config pyproject.toml rasa/*
types:
poetry run mypy rasa
static-checks: lint lint-security types
prepare-spacy:
poetry run python -m spacy download en_core_web_md
poetry run python -m spacy download de_core_news_sm
prepare-mitie:
wget --progress=dot:giga -N -P data/ https://github.com/mit-nlp/MITIE/releases/download/v0.4/MITIE-models-v0.2.tar.bz2
ifeq ($(OS),Windows_NT)
7z x data/MITIE-models-v0.2.tar.bz2 -bb3
7z x MITIE-models-v0.2.tar -bb3
cp MITIE-models/english/total_word_feature_extractor.dat data/
rm -r MITIE-models
rm MITIE-models-v0.2.tar
else
tar -xvjf data/MITIE-models-v0.2.tar.bz2 --strip-components 2 -C data/ MITIE-models/english/total_word_feature_extractor.dat
endif
rm data/MITIE*.bz2
prepare-transformers:
while read -r MODEL; do poetry run python scripts/download_transformer_model.py $$MODEL ; done < data/test/hf_transformers_models.txt
if ! [ $(CI) ]; then poetry run python scripts/download_transformer_model.py rasa/LaBSE; fi
prepare-tests-macos:
brew install wget graphviz || true
prepare-tests-ubuntu:
sudo apt-get update && sudo apt-get -y install graphviz graphviz-dev python3-tk
prepare-tests-windows:
choco install wget graphviz
# GitHub Action has pre-installed a helper function for installing Chocolatey packages
# It will retry the installation 5 times if it fails
# See: https://github.com/actions/virtual-environments/blob/main/images/win/scripts/ImageHelpers/ChocoHelpers.ps1
prepare-tests-windows-gha:
powershell -command "Install-ChocoPackage wget graphviz"
test: clean
# OMP_NUM_THREADS can improve overall performance using one thread by process (on tensorflow), avoiding overload
# TF_CPP_MIN_LOG_LEVEL=2 sets C code log level for tensorflow to error suppressing lower log events
OMP_NUM_THREADS=1 TF_CPP_MIN_LOG_LEVEL=2 poetry run pytest tests -n $(JOBS) --dist loadscope --cov rasa --ignore $(INTEGRATION_TEST_FOLDER)
test-integration:
# OMP_NUM_THREADS can improve overall performance using one thread by process (on tensorflow), avoiding overload
# TF_CPP_MIN_LOG_LEVEL=2 sets C code log level for tensorflow to error suppressing lower log events
ifeq (,$(wildcard tests_deployment/.env))
OMP_NUM_THREADS=1 TF_CPP_MIN_LOG_LEVEL=2 poetry run pytest $(INTEGRATION_TEST_FOLDER) -n $(JOBS) -m $(INTEGRATION_TEST_PYTEST_MARKERS) --dist loadgroup
else
set -o allexport; source tests_deployment/.env && OMP_NUM_THREADS=1 TF_CPP_MIN_LOG_LEVEL=2 poetry run pytest $(INTEGRATION_TEST_FOLDER) -n $(JOBS) -m $(INTEGRATION_TEST_PYTEST_MARKERS) --dist loadgroup && set +o allexport
endif
test-cli: PYTEST_MARKER=category_cli and (not flaky)
test-cli: DD_ARGS := $(or $(DD_ARGS),)
test-cli: test-marker
test-core-featurizers: PYTEST_MARKER=category_core_featurizers and (not flaky)
test-core-featurizers: DD_ARGS := $(or $(DD_ARGS),)
test-core-featurizers: test-marker
test-policies: PYTEST_MARKER=category_policies and (not flaky)
test-policies: DD_ARGS := $(or $(DD_ARGS),)
test-policies: test-marker
test-nlu-featurizers: PYTEST_MARKER=category_nlu_featurizers and (not flaky)
test-nlu-featurizers: DD_ARGS := $(or $(DD_ARGS),)
test-nlu-featurizers: prepare-spacy prepare-mitie prepare-transformers test-marker
test-nlu-predictors: PYTEST_MARKER=category_nlu_predictors and (not flaky)
test-nlu-predictors: DD_ARGS := $(or $(DD_ARGS),)
test-nlu-predictors: prepare-spacy prepare-mitie test-marker
test-full-model-training: PYTEST_MARKER=category_full_model_training and (not flaky)
test-full-model-training: DD_ARGS := $(or $(DD_ARGS),)
test-full-model-training: prepare-spacy prepare-mitie prepare-transformers test-marker
test-other-unit-tests: PYTEST_MARKER=category_other_unit_tests and (not flaky)
test-other-unit-tests: DD_ARGS := $(or $(DD_ARGS),)
test-other-unit-tests: prepare-spacy prepare-mitie test-marker
test-performance: PYTEST_MARKER=category_performance and (not flaky)
test-performance: DD_ARGS := $(or $(DD_ARGS),)
test-performance: test-marker
test-flaky: PYTEST_MARKER=flaky
test-flaky: DD_ARGS := $(or $(DD_ARGS),)
test-flaky: prepare-spacy prepare-mitie test-marker
test-gh-actions:
OMP_NUM_THREADS=1 TF_CPP_MIN_LOG_LEVEL=2 poetry run pytest .github/tests --cov .github/scripts
test-marker: clean
# OMP_NUM_THREADS can improve overall performance using one thread by process (on tensorflow), avoiding overload
# TF_CPP_MIN_LOG_LEVEL=2 sets C code log level for tensorflow to error suppressing lower log events
TRANSFORMERS_OFFLINE=1 OMP_NUM_THREADS=1 TF_CPP_MIN_LOG_LEVEL=2 poetry run pytest tests -n $(JOBS) --dist loadscope -m "$(PYTEST_MARKER)" --cov rasa --ignore $(INTEGRATION_TEST_FOLDER) $(DD_ARGS)
generate-pending-changelog:
poetry run python -c "from scripts import release; release.generate_changelog('major.minor.patch')"
cleanup-generated-changelog:
# this is a helper to cleanup your git status locally after running "make test-docs"
# it's not run on CI at the moment
git status --porcelain | sed -n '/^D */s///p' | xargs git reset HEAD
git reset HEAD CHANGELOG.mdx
git ls-files --deleted | xargs git checkout
git checkout CHANGELOG.mdx
test-docs: generate-pending-changelog docs
poetry run pytest tests/docs/*
lint-docs: generate-pending-changelog docs
cd docs/ && yarn mdx-lint
prepare-docs:
cd docs/ && poetry run yarn pre-build
docs: prepare-docs
cd docs/ && yarn build
livedocs:
cd docs/ && poetry run yarn start
preview-docs:
cd docs/ && yarn build && yarn deploy-preview --alias=${PULL_REQUEST_NUMBER} --message="Preview for Pull Request #${PULL_REQUEST_NUMBER}"
publish-docs:
cd docs/ && yarn build && yarn deploy
release:
poetry run python scripts/release.py
build-docker:
export IMAGE_NAME=rasa && \
docker buildx use default && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-poetry && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-builder && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl default
build-docker-full:
export IMAGE_NAME=rasa && \
docker buildx use default && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-images && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-builder && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl full
build-docker-mitie-en:
export IMAGE_NAME=rasa && \
docker buildx use default && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-images && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-builder && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl mitie-en
build-docker-spacy-en:
export IMAGE_NAME=rasa && \
docker buildx use default && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-poetry && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-builder && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl spacy-en
build-docker-spacy-de:
export IMAGE_NAME=rasa && \
docker buildx use default && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-poetry && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-builder && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl spacy-de
build-docker-spacy-it:
export IMAGE_NAME=rasa && \
docker buildx use default && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-poetry && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl base-builder && \
docker buildx bake --set default.platform=${PLATFORM} -f docker/docker-bake.hcl spacy-it
build-tests-deployment-env: ## Create environment files (.env) for docker-compose.
cd tests_deployment && \
test -f .env || cat .env.example >> .env
run-integration-containers: build-tests-deployment-env ## Run the integration test containers.
cd tests_deployment && \
docker-compose -f docker-compose.integration.yml up &
stop-integration-containers: ## Stop the integration test containers.
cd tests_deployment && \
docker-compose -f docker-compose.integration.yml down
+5
View File
@@ -0,0 +1,5 @@
Rasa Technologies GmbH
Copyright 2016-2022 Rasa Technologies GmbH
This product includes software from spaCy (https://github.com/explosion/spaCy),
under the MIT License (see: rasa.nlu.extractors.crf_entity_extractor).
+28
View File
@@ -0,0 +1,28 @@
<!-- Principles for Building Ethical Conversational Assistants -->
When you create a conversational assistant, you are responsible for its impact on the people that it talks to.
Therefore, you should consider how users might perceive the assistants statements, and how a conversation might affect their lives.
This is not always straightforward, as you typically have little to no knowledge about the background of your users.
Thus, we created this guide to help you avoid the worst outcomes.
It is in the best interest of all conversational assistant creators that the public perceives these assistants as helpful and friendly.
Beyond this, it is also in the best interest of all members of society (including creators) that conversational assistants are not used for harassment or manipulation. Aside from being unethical, such use cases would create a lasting reluctance of users to engage with conversational assistants.
The following four key points should help you use this technology wisely. Please note, however, that these guidelines are only a first step, and you should use your own judgement as well.
## 1. **A conversational assistant should not cause users harm**.
Even though a conversational assistant only exists in the digital world, it can still inflict harm on users simply by communicating with them in a certain way. For example, assistants are often used as information sources or decision guides. If the information that the assistant provides is inaccurate or misleading, users may end up making poor (or even dangerous) decisions based on their interaction with your assistant.
## 2. **A conversational assistant should not encourage or normalize harmful behaviour from users**.
Although users have complete freedom in what they can communicate to a conversational assistants, these assistants are designed to only follow pre-defined stories. In doing so, a conversational assistant should not try to provoke the user into engaging in harmful behaviour. If for any reason the user decides to engage in this behaviour anyway, the assistant should politely refuse to participate. In other words, treating such behaviour as normal or acceptable should be avoided. Trying to argue with the user will very rarely lead to useful results.
## 3. **A conversational assistant should always identify itself as one**.
When asked questions such as “Are you a bot?” or “Are you a human?”, a bot should always inform the user that it is indeed an assistant, and not a human. Impostor bots (algorithms that pose as humans) are a major piece of platform manipulation techniques, and this creates a lot of mistrust. Instead of misleading users, we should build assistants that truly support them, thereby enabling a larger fraction of work to be done by conversational assistants in the long-term (as users become more accustomed to them). This does not mean that conversational assistants cant be human-like.
## 4. **A conversational assistant should provide users a way to prove its identity**.
When an assistant is designed to communicate with users while representing a company, organization, etc., it is important to allow users to verify that this representation has been previously authorized. Its possible to use already existing technologies to do this: for example, by integrating a conversational assistant to a website served using HTTPS, the content of the site (and therefore the assistant itself) will be guaranteed to be legitimate by a trusted certificate authority. Another example would be to have the conversational assistant use a “verified” social media account.
+134
View File
@@ -0,0 +1,134 @@
<h1 align="center">Rasa Open Source</h1>
<div align="center">
[![Join the Agent Engineering Community](https://img.shields.io/badge/Community-Join%20the%20Discussion-blueviolet)](https://info.rasa.com/community?utm_source=github&utm_medium=website&utm_campaign=)
[![Try Hello Rasa](https://img.shields.io/badge/Playground-Try%20Hello%20Rasa-ff69b4)](https://hello.rasa.ai/?utm_source=github&utm_medium=website&utm_campaign=)
[![PyPI version](https://badge.fury.io/py/rasa.svg)](https://badge.fury.io/py/rasa)
[![Supported Python Versions](https://img.shields.io/pypi/pyversions/rasa.svg)](https://pypi.python.org/pypi/rasa)
[![Build Status](https://github.com/RasaHQ/rasa/workflows/Continuous%20Integration/badge.svg)](https://github.com/RasaHQ/rasa/actions)
[![Documentation Status](https://img.shields.io/badge/docs-stable-brightgreen.svg)](https://rasa.com/docs)
</div>
<br />
<div align="center">
<h3>🚧 <b>Note: Maintenance Mode</b> 🚧</h3>
<p>
Rasa Open Source is currently in maintenance mode.
<br />
The future of building AI agents with Rasa is <b>Hello Rasa</b> and <b>CALM</b>.
</p>
</div>
<hr />
## 🚀 The Future of Rasa: Hello Rasa
**Building reliable AI agents just got easier.**
[**Hello Rasa**](https://hello.rasa.ai/?utm_source=github&utm_medium=website&utm_campaign=) is our new interactive playground for prototyping AI agents. It combines LLM fluency with the reliability of business logic using our **CALM** (Conversational AI with Language Models) engine.
### Why switch to Hello Rasa?
* **No setup required:** Open the playground, pick a template (Banking, Telecom, Support), and start building in your browser.
* **No NLU training:** We have moved beyond intents. The LLM handles dialogue understanding while you define the business flows.
* **Built-in copilot:** A specialized AI assistant helps you generate code, debug flows, and expand your agent instantly.
* **Production ready:** Hello Rasa is not just a toy. Export your agent to the Rasa Platform when you are ready to scale.
### Core concepts
* **CALM:** Combines LLM flexibility with strict business logic. The LLM understands the user; the code enforces the rules.
* **Flows:** Describe logical steps (e.g., collect money, transfer funds) rather than rigid dialogue trees.
* **Inspector:** See real-time decision-making. No black boxes.
👉 **[Start building for free at Hello Rasa](https://hello.rasa.ai/?utm_source=github&utm_medium=website&utm_campaign=)**
---
## 🧠 Join the Agent Engineering Community
We are building a home for people shipping real-world AI agents.
Agent Engineering is evolving faster than any single framework. This is a vendor-neutral space to discuss architectures, memory, orchestration, and safety with builders across the industry.
### What you get:
* **Network:** Meet engineers building production agents
* **Learn:** Discuss practical patterns, not just theory
* **Access:** Direct influence on the Hello Rasa roadmap and early access to features
| Channel | Purpose |
| :--- | :--- |
| **#agent-design** | Architectures, reasoning, memory, testing |
| **#showcase** | Show your builds, demos, and repos |
| **#ask-anything** | Debugging and workflow questions |
👉 **[Join the Community](https://info.rasa.com/community?utm_source=github&utm_medium=website&utm_campaign=)**
---
<br>
<br>
# Rasa Open Source (Legacy)
> **Note:** The documentation and installation instructions below apply to the classic Rasa Open Source framework. For the latest CALM-based experience, see the [Hello Rasa](#-the-future-of-rasa-hello-rasa) section above.
Rasa is an open source machine learning framework for automating text and voice-based conversations. With Rasa, you can build contextual assistants on:
- Facebook Messenger
- Slack
- Google Hangouts
- Webex Teams
- Microsoft Bot Framework
- Rocket.Chat
- Mattermost
- Telegram
- Twilio
- Your own custom conversational channels
Rasa helps you build contextual assistants that can handle layered conversations with lots of back-and-forth.
### 📚 Resources
- 🤓 [Read the docs](https://rasa.com/docs/rasa/)
- 😁 [Install Rasa](https://rasa.com/docs/rasa/installation/environment-set-up)
- 🚀 [Learn all about Conversational AI](https://learning.rasa.com/)
- 🏢 [Explore the enterprise platform](https://rasa.com/product/rasa-platform/)
## Development Internals & Contributing
We are happy to receive contributions. Please review our [Contribution Guidelines](CONTRIBUTING.md) before getting started.
### Installation for Development
Rasa uses **Poetry** for packaging and dependency management.
1. **Install Poetry**: Follow the [official guide](https://python-poetry.org/docs/#installation).
2. **Build from source**:
```bash
make install
```
*Note for macOS users*: If you run into compiler issues, try `export SYSTEM_VERSION_COMPAT=1` before installation.
### Running Tests
Make sure you have development requirements installed:
```bash
make prepare-tests-ubuntu # Ubuntu/Debian
make prepare-tests-macos # macOS
make test # Run tests
```
### Releases
Rasa follows Semantic Versioning.
* **Major**: Incompatible API changes
* **Minor**: Backward-compatible functionality
* **Patch**: Backward-compatible bug fixes
For full details on our release cadence and maintenance policy, visit our [Product Release and Maintenance Policy](https://rasa.com/rasa-product-release-and-maintenance-policy/).
## License
Licensed under the Apache License, Version 2.0. Copyright 2022 Rasa Technologies GmbH. [Copy of the license](https://www.google.com/search?q=LICENSE.txt).
+7
View File
@@ -0,0 +1,7 @@
# WeHub 来源说明
- 原始项目:`RasaHQ/rasa`
- 原始仓库:https://github.com/RasaHQ/rasa
- 导入方式:上游默认分支的最新快照
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
+1
View File
@@ -0,0 +1 @@
poetry run python -m spacy download en
+36
View File
@@ -0,0 +1,36 @@
This directory contains "newsfragments" which are short files that contain a small
**Markdown**-formatted text that will be added to the next `CHANGELOG`.
The `CHANGELOG` will be read by **users**, so this description should be aimed
to Rasa OSS users.
Make sure to use full sentences in the **past or present tense** and use
punctuation, examples:
Slots will be correctly interpolated if there are lists in custom response templates.
Previously this resulted in no interpolation.
Each file should be named like `<ISSUE>.<TYPE>.md`, where
`<ISSUE>` is an issue / PR number, and `<TYPE>` is one of:
* `feature`: new user facing features, like new command-line options and new behavior.
* `improvement`: improvement of existing functionality, usually without requiring user intervention.
* `bugfix`: fixes a reported bug or security vulnerability.
* `doc`: documentation improvement, like rewording an entire section or adding missing docs.
* `removal`: feature deprecation or feature removal.
* `misc`: fixing a small typo or internal change, will not be included in the changelog.
So for example: `123.feature.md`, `456.bugfix.md`.
If your change fixes an issue, use the issue number here. If there is no issue,
then after you submit the PR with your changes and get the PR number, you can add a
changelog using that PR number instead.
If you are not sure what issue type to use, don't hesitate to ask in your PR.
`towncrier` preserves multiple paragraphs and formatting (code blocks, lists,
and so on), but for entries other than `features` it is usually better to stick
to a single paragraph to keep it concise. You can install `towncrier` and then
run `towncrier --draft` if you want to get a preview of how your change will look
in the final release notes.
+12
View File
@@ -0,0 +1,12 @@
{# Based on https://github.com/hawkowl/towncrier/blob/master/src/towncrier/templates/default.rst #}
{% if top_line %}{{ top_line }} {{ top_underline * ((top_line)|length)}} {% elif versiondata.name %}{{ versiondata.name }} {{ versiondata.version }} ({{ versiondata.date }}) {{ top_underline * ((versiondata.name + versiondata.version + versiondata.date)|length + 4)}}{% else %}{{ versiondata.version }} ({{ versiondata.date }}) {{ top_underline * ((versiondata.version + versiondata.date)|length + 3)}}{% endif %}{% for section in sections %}{% if section %}{{section}}{% endif %}{% if sections[section] %}{% for category, val in definitions.items() if category in sections[section] %}
{{ "### " + definitions[category]['name'] }}
{% if definitions[category]['showcontent'] %}{% for text, values in sections[section][category]|dictsort(by='value') %}{% set issue_joiner = joiner(', ') %}- {% for value in values|sort %}{{ issue_joiner() }}{{ value }}{% endfor %}: {{ text }}
{% endfor %}{% else %}- {{ sections[section][category]['']|sort|join(', ') }}{% endif %}{% if sections[section][category]|length == 0 %} No significant changes.
{% else %}{% endif %}{% endfor %}{% else %}
No significant changes.
{% endif %}{% endfor %}
+6
View File
@@ -0,0 +1,6 @@
timeout: "20m"
steps:
- name: 'gcr.io/cloud-builders/docker'
id: 'docker-build'
args: ['build', '--file', './docker/Dockerfile_full', '-t', '$_IMAGE_REPO:$TAG_NAME', '.']
images: [ '$_IMAGE_REPO:$TAG_NAME' ]
+12
View File
@@ -0,0 +1,12 @@
These are some example training data files for a simple bot in the restaurant domain.
They are in the format of the services rasa NLU can emulate, e.g. when you download an export
of your app from one of these services it should look like one of these files.
[examples/rasa](examples/rasa): examples in the native rasa NLU format
[examples/luis](examples/luis): in LUIS format
[examples/wit](examples/wit): in wit format
[examples/api](examples/api): this is a dir and in Dialogflow format
@@ -0,0 +1,24 @@
assistant_id: example_featurizers_bot
language: "en"
pipeline:
- name: ConveRTTokenizer
- name: ConveRTFeaturizer
alias: "convert"
- name: RegexFeaturizer
alias: "regex"
- name: LexicalSyntacticFeaturizer
alias: "lexical-syntactic"
- name: CountVectorsFeaturizer
alias: "cvf-word"
- name: CountVectorsFeaturizer
alias: "cvf-char"
analyzer: "char_wb"
min_ngram: 1
max_ngram: 4
- name: DIETClassifier
epochs: 100
- name: EntitySynonymMapper
- name: ResponseSelector
featurizers: ["convert", "cvf-word"]
epochs: 100
+17
View File
@@ -0,0 +1,17 @@
assistant_id: default_config_bot
language: "fr" # your two-letter language code
pipeline:
- name: WhitespaceTokenizer
- name: RegexFeaturizer
- name: LexicalSyntacticFeaturizer
- name: CountVectorsFeaturizer
- name: CountVectorsFeaturizer
analyzer: "char_wb"
min_ngram: 1
max_ngram: 4
- name: DIETClassifier
epochs: 100
- name: EntitySynonymMapper
- name: ResponseSelector
epochs: 100
@@ -0,0 +1,18 @@
assistant_id: default_en_bot
language: "en"
pipeline:
- name: ConveRTTokenizer
- name: ConveRTFeaturizer
- name: RegexFeaturizer
- name: LexicalSyntacticFeaturizer
- name: CountVectorsFeaturizer
- name: CountVectorsFeaturizer
analyzer: "char_wb"
min_ngram: 1
max_ngram: 4
- name: DIETClassifier
epochs: 100
- name: EntitySynonymMapper
- name: ResponseSelector
epochs: 100
@@ -0,0 +1,19 @@
assistant_id: default_spacy_bot
language: "fr" # your two-letter language code
pipeline:
- name: SpacyNLP
- name: SpacyTokenizer
- name: SpacyFeaturizer
- name: RegexFeaturizer
- name: LexicalSyntacticFeaturizer
- name: CountVectorsFeaturizer
- name: CountVectorsFeaturizer
analyzer: "char_wb"
min_ngram: 1
max_ngram: 4
- name: DIETClassifier
epochs: 100
- name: EntitySynonymMapper
- name: ResponseSelector
epochs: 100
@@ -0,0 +1,12 @@
recipe: default.v1
assistant_id: example_bot
language: en
pipeline:
# will be selected by the Suggested Config feature
policies:
- name: MemoizationPolicy
- name: TEDPolicy
max_history: 5
epochs: 10
@@ -0,0 +1,30 @@
recipe: default.v1
assistant_id: example_bot
language: en
pipeline:
# # No configuration for the NLU pipeline was provided. The following default pipeline was used to train your model.
# # If you'd like to customize it, uncomment and adjust the pipeline.
# # See https://rasa.com/docs/rasa/tuning-your-model for more information.
# - name: WhitespaceTokenizer
# - name: RegexFeaturizer
# - name: LexicalSyntacticFeaturizer
# - name: CountVectorsFeaturizer
# - name: CountVectorsFeaturizer
# analyzer: char_wb
# min_ngram: 1
# max_ngram: 4
# - name: DIETClassifier
# epochs: 100
# - name: EntitySynonymMapper
# - name: ResponseSelector
# epochs: 100
# - name: FallbackClassifier
# threshold: 0.3
# ambiguity_threshold: 0.1
policies:
- name: MemoizationPolicy
- name: TEDPolicy
max_history: 5
epochs: 10
@@ -0,0 +1,7 @@
assistant_id: example_convert_bot
language: "en"
pipeline:
- name: "ConveRTTokenizer"
- name: "ConveRTFeaturizer"
- name: "DIETClassifier"
@@ -0,0 +1,12 @@
assistant_id: example_mitie_bot
language: "en"
pipeline:
- name: "MitieNLP"
model: "data/total_word_feature_extractor.dat"
- name: "MitieTokenizer"
- name: "MitieEntityExtractor"
- name: "EntitySynonymMapper"
- name: "RegexFeaturizer"
- name: "MitieFeaturizer"
- name: "SklearnIntentClassifier"
@@ -0,0 +1,11 @@
assistant_id: example_mitie_bot
language: "en"
pipeline:
- name: "MitieNLP"
model: "data/total_word_feature_extractor.dat"
- name: "MitieTokenizer"
- name: "MitieEntityExtractor"
- name: "EntitySynonymMapper"
- name: "RegexFeaturizer"
- name: "MitieIntentClassifier"
@@ -0,0 +1,13 @@
assistant_id: example_spacy_bot
language: "en"
pipeline:
- name: "SpacyNLP"
model: "en_core_web_md"
- name: "SpacyTokenizer"
- name: "SpacyFeaturizer"
- name: "RegexFeaturizer"
- name: "CRFEntityExtractor"
- name: "EntitySynonymMapper"
- name: "SklearnIntentClassifier"
@@ -0,0 +1,14 @@
assistant_id: example_supervised_bot
language: "en"
pipeline:
- name: "WhitespaceTokenizer"
- name: "RegexFeaturizer"
- name: "CRFEntityExtractor"
- name: "EntitySynonymMapper"
- name: "CountVectorsFeaturizer"
- name: "CountVectorsFeaturizer"
analyzer: "char_wb"
min_ngram: 1
max_ngram: 4
- name: "DIETClassifier"
+54
View File
@@ -0,0 +1,54 @@
{
"description": "",
"language": "en",
"shortDescription": "",
"examples": "",
"linkToDocs": "",
"disableInteractionLogs": false,
"disableStackdriverLogs": true,
"googleAssistant": {
"googleAssistantCompatible": false,
"project": "rasanlu-development",
"welcomeIntentSignInRequired": false,
"startIntents": [],
"systemIntents": [],
"endIntentIds": [],
"oAuthLinking": {
"required": false,
"providerId": "",
"authorizationUrl": "",
"tokenUrl": "",
"scopes": "",
"privacyPolicyUrl": "",
"grantType": "AUTH_CODE_GRANT"
},
"voiceType": "MALE_1",
"capabilities": [],
"env": "",
"protocolVersion": "V2",
"autoPreviewEnabled": false,
"isDeviceAgent": false
},
"defaultTimezone": "Asia/Hong_Kong",
"webhook": {
"url": "",
"username": "",
"headers": {},
"available": false,
"useForDomains": false,
"cloudFunctionsEnabled": false,
"cloudFunctionsInitialized": false
},
"isPrivate": true,
"mlMinConfidence": 0.3,
"supportedLanguages": [
"es"
],
"enableOnePlatformApi": true,
"onePlatformApiVersion": "v2",
"analyzeQueryTextSentiment": false,
"enabledKnowledgeBaseNames": [],
"knowledgeServiceConfidenceAdjustment": 0.0,
"dialogBuilderMode": false,
"baseActionPackagesUrl": ""
}
@@ -0,0 +1,9 @@
{
"id": "11c77228-4a02-4db8-a398-b286fe8098d2",
"name": "cuisine",
"isOverridable": true,
"isEnum": false,
"isRegexp": false,
"automatedExpansion": false,
"allowFuzzyExtraction": false
}
@@ -0,0 +1,23 @@
[
{
"value": "mexican",
"synonyms": [
"mexican",
"mexico"
]
},
{
"value": "chinese",
"synonyms": [
"chinese",
"china"
]
},
{
"value": "indian",
"synonyms": [
"indian",
"india"
]
}
]
@@ -0,0 +1,25 @@
[
{
"value": "mexicano",
"synonyms": [
"mexicano",
"mexicana",
"méxico"
]
},
{
"value": "chino",
"synonyms": [
"chino",
"china",
"chinos"
]
},
{
"value": "indio",
"synonyms": [
"indio",
"india"
]
}
]
@@ -0,0 +1,9 @@
{
"id": "fc93d510-e240-4b71-bafe-7dd7a3303e79",
"name": "flightNumber",
"isOverridable": true,
"isEnum": false,
"isRegexp": true,
"automatedExpansion": false,
"allowFuzzyExtraction": false
}
@@ -0,0 +1,8 @@
[
{
"value": "flight [A-Z]{2} [0-9]{4}",
"synonyms": [
"flight [A-Z]{2} [0-9]{4}"
]
}
]
@@ -0,0 +1,9 @@
{
"id": "8ee88034-01d3-49d4-bb58-531a705b963b",
"name": "location",
"isOverridable": true,
"isEnum": false,
"isRegexp": false,
"automatedExpansion": false,
"allowFuzzyExtraction": false
}
@@ -0,0 +1,26 @@
[
{
"value": "centre",
"synonyms": [
"centre"
]
},
{
"value": "west",
"synonyms": [
"west"
]
},
{
"value": "central",
"synonyms": [
"central"
]
},
{
"value": "north",
"synonyms": [
"north"
]
}
]
@@ -0,0 +1,29 @@
[
{
"value": "centro",
"synonyms": [
"centro",
"centrar"
]
},
{
"value": "oeste",
"synonyms": [
"oeste",
"occidente"
]
},
{
"value": "central",
"synonyms": [
"central",
"céntrico"
]
},
{
"value": "norte",
"synonyms": [
"norte"
]
}
]
@@ -0,0 +1,60 @@
{
"id": "27b800fb-3b69-4723-932d-ca53eb849138",
"name": "Default Fallback Intent",
"auto": true,
"contexts": [],
"responses": [
{
"resetContexts": false,
"action": "input.unknown",
"affectedContexts": [],
"parameters": [],
"messages": [
{
"type": "0",
"title": "",
"textToSpeech": "",
"lang": "es",
"speech": [
"Ups, no he entendido a que te refieres.",
"¿Podrías repetirlo, por favor?",
"¿Disculpa?",
"¿Decías?",
"¿Cómo?"
],
"condition": ""
},
{
"type": "0",
"title": "",
"textToSpeech": "",
"lang": "en",
"speech": [
"I didn\u0027t get that. Can you say it again?",
"I missed what you said. Say it again?",
"Sorry, could you say that again?",
"Sorry, can you say that again?",
"Can you say that again?",
"Sorry, I didn\u0027t get that.",
"Sorry, what was that?",
"One more time?",
"What was that?",
"Say that again?",
"I didn\u0027t get that.",
"I missed that."
],
"condition": ""
}
],
"speech": []
}
],
"priority": 500000,
"webhookUsed": false,
"webhookForSlotFilling": false,
"fallbackIntent": true,
"events": [],
"conditionalResponses": [],
"condition": "",
"conditionalFollowupEvents": []
}

Some files were not shown because too many files have changed in this diff Show More