Skip to content

Basic Streaming and In-Memory Guard Support #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
c25810c
start lite build
CalebCourier Apr 15, 2024
24867fa
litellm support
CalebCourier Apr 16, 2024
17fe0d7
streaming support
CalebCourier Apr 17, 2024
f58b0ca
update lock file
CalebCourier Apr 17, 2024
71f533e
add valid length validator
CalebCourier Apr 17, 2024
afbd0d7
register hub validators on startup
CalebCourier Apr 18, 2024
5d20925
send back new field for validated stream errors
CalebCourier Apr 18, 2024
0aff6b8
add some simple validators
CalebCourier Apr 18, 2024
fb4934c
disable otel on streaming
CalebCourier Apr 18, 2024
c80914a
custom installs for validators
CalebCourier Apr 18, 2024
4c02184
point competitor_check to frontend_demo branch
CalebCourier Apr 18, 2024
9798ac5
turn off oss metrics
CalebCourier Apr 18, 2024
194b67e
dont send tracer to guard
CalebCourier Apr 18, 2024
792a7dd
no max request
CalebCourier Apr 18, 2024
212f35d
remove all telemetry from validate
CalebCourier Apr 18, 2024
af24df3
try printing response status
CalebCourier Apr 18, 2024
c06bde0
add many_shot_jailbreak to custom install
CalebCourier Apr 18, 2024
60257bd
add api-spec download to build scripts
zsimjee Apr 18, 2024
bada0a0
update jailbreak repo to clean
CalebCourier Apr 18, 2024
e1c46e7
more limit removals
CalebCourier Apr 18, 2024
8b0c363
log for every error
CalebCourier Apr 18, 2024
39525fe
fix error handling
CalebCourier Apr 19, 2024
7203a60
lite image changes
zsimjee Apr 19, 2024
c275813
lite build updates, default embed func
CalebCourier May 3, 2024
bc12034
Update how to run
zsimjee May 20, 2024
eb71536
update guardrails branch
CalebCourier May 24, 2024
a70dc92
merge main
CalebCourier May 30, 2024
67af5f6
lint fix
CalebCourier May 30, 2024
33d43ca
install dev dependencies before running qa
CalebCourier May 30, 2024
c5cf785
In memory guard client (#34)
nichwch May 31, 2024
2367430
update guardrails branch
CalebCourier May 31, 2024
b8f9699
lint fixes, start test fixes
CalebCourier May 31, 2024
a0325b5
start fixing tests
CalebCourier May 31, 2024
5b7ba42
fix tets
CalebCourier May 31, 2024
fc72222
setup api spec
CalebCourier May 31, 2024
ceb47a0
local imports
CalebCourier May 31, 2024
bdd3fd0
rename test file, use venv in qa
CalebCourier May 31, 2024
47ec637
split qa steps, empty config, include sample config
CalebCourier May 31, 2024
c9a557f
add test coverage for memory guard
nichwch Jun 3, 2024
13b437e
lint
nichwch Jun 4, 2024
6c61c1d
Merge pull request #42 from guardrails-ai/nichwch/guard-coverage
nichwch Jun 4, 2024
81e4245
ignore empty num_reask
CalebCourier Jun 4, 2024
46575ec
Update readme with dev instructions, add compose file for infra, upda…
CalebCourier Jun 4, 2024
34e3078
drop test coverage for now; all tests will be re-written as part of s…
CalebCourier Jun 4, 2024
21104a0
make otel checks negative since otel env var is negative
CalebCourier Jun 4, 2024
15eded7
default open api key to env var
CalebCourier Jun 5, 2024
c8e0ad5
remove print statements
CalebCourier Jun 5, 2024
fbc37d5
auto format
CalebCourier Jun 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 12 additions & 21 deletions .github/workflows/pr_qa.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,18 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v4
- name: Quality Checks
- name: Install Dependencies
run: |
python -m pip install --upgrade pip;
python -m venv ./.venv
source ./.venv/bin/activate
make install-lock;
opentelemetry-bootstrap -a install;
make qa;

##
## NOTE:
## The below checks for a file named .version-change-type that is used to automatically increment the version number during publish flows.
## It also checks for changes in a file called RELEASENOTES.md that are used to auto-maintain a rolling CHANGELOG.
## This is commented out for now until we finalize what the publish/release flow will look like.
##
make install-dev;

# changeType=$(<.version-change-type)
# if [ -z "$changeType" ];
# then
# echo "missing file .version-change-type!"
# exit 1
# fi
# echo "Checking for release notes..."
# git fetch origin main ${{ github.event.pull_request.base.sha }};
# diff=$(git diff -U0 ${{ github.event.pull_request.base.sha }} ${{ github.sha }} RELEASENOTES.md);
# if [ -z "$diff" ]; then echo "Missing release notes! exiting..."; exit 1; fi
curl https://raw.githubusercontent.com/guardrails-ai/guardrails-api-client/main/service-specs/guardrails-service-spec.yml -o ./open-api-spec.yml
npx @redocly/cli bundle --dereferenced --output ./open-api-spec.json --ext json ./open-api-spec.yml

- name: Run Quality Checks
run: |
source ./.venv/bin/activate

make qa;
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ opentelemetry-lambda-layer
open-api-spec.json
open-api-spec.yml
.python-version
requirements-lock-old.txt
requirements-lock-old.txt
models
2 changes: 1 addition & 1 deletion Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ COPY . .

EXPOSE 8000

CMD opentelemetry-instrument gunicorn --bind 0.0.0.0:8000 --timeout=90 --threads=10 "app:create_app()"
CMD gunicorn --bind 0.0.0.0:8000 --timeout=90 --threads=10 "app:create_app()"
2 changes: 1 addition & 1 deletion Dockerfile.heavy
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ COPY . .

EXPOSE 8000

CMD opentelemetry-instrument gunicorn --bind 0.0.0.0:8000 --timeout=90 --threads=10 "app:create_app()"
CMD gunicorn --bind 0.0.0.0:8000 --timeout=90 --threads=10 "app:create_app()"
# CMD gunicorn --forwarded-allow-ips="*" --bind 0.0.0.0:8000 --timeout=60 --threads=10 "app:create_app()"
55 changes: 55 additions & 0 deletions Dockerfile.lite
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
FROM public.ecr.aws/docker/library/python:3.11.6-slim

ARG GITHUB_TOKEN
ARG HF_TOKEN

COPY .guardrailsrc /root/.guardrailsrc

# COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.7.1 /lambda-adapter /opt/extensions/lambda-adapter
# COPY ./opentelemetry-lambda-layer /opt

# Create app directory
WORKDIR /app

# check the version
RUN python3 --version
# start the virtual environment
RUN python3 -m venv /opt/venv

# Enable venv
ENV PATH="/opt/venv/bin:$PATH"

# Install git and curl
RUN apt-get update
RUN apt-get install -y git curl gcc jq

# Copy the requirements file
COPY requirements*.txt .

RUN curl https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem -o ./global-bundle.pem

# Install app dependencies
RUN pip install -r requirements-lock.txt

# Download punkt data
RUN python -m nltk.downloader -d /opt/nltk_data punkt

# RUN guardrails hub install hub://guardrails/profanity_free
RUN guardrails hub install hub://guardrails/valid_length
RUN guardrails hub install hub://guardrails/lowercase
RUN guardrails hub install hub://guardrails/regex_match

COPY ./custom-install ./custom-install

RUN python ./custom-install/install.py

# Freeze dependencies
RUN pip freeze > requirements-lock.txt

# Copy the whole folder inside the Image filesystem
COPY . .

EXPOSE 8000

CMD gunicorn --bind 0.0.0.0:8000 --timeout=90 --threads=10 --limit-request-line=0 --limit-request-fields=1000 --limit-request-field_size=0 "app:create_app()"
# CMD gunicorn --forwarded-allow-ips="*" --bind 0.0.0.0:8000 --timeout=60 --threads=10 "app:create_app()"
2 changes: 1 addition & 1 deletion Dockerfile.prod
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ COPY . .

EXPOSE 8000

CMD opentelemetry-instrument gunicorn --bind 0.0.0.0:8000 --timeout=5 --threads=10 "app:create_app()"
CMD gunicorn --bind 0.0.0.0:8000 --timeout=5 --threads=10 "app:create_app()"
# CMD gunicorn --forwarded-allow-ips="*" --bind 0.0.0.0:8000 --timeout=60 --threads=10 "app:create_app()"
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# Installs production dependencies
install:
pip install -r requirements.txt;
# This is a workaround because of this issue: https://github.com/open-telemetry/opentelemetry-python-contrib/issues/2053
pip uninstall aiohttp -y
pip install opentelemetry-distro
opentelemetry-bootstrap -a install
pip install aiohttp

# Installs development dependencies
install-dev:
Expand Down Expand Up @@ -53,7 +57,7 @@ source:
source ./.venv/bin/activate

test:
python3 -m pytest ./tests
pytest ./tests

test-cov:
coverage run --source=./src -m pytest ./tests
Expand Down
21 changes: 16 additions & 5 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from werkzeug.middleware.proxy_fix import ProxyFix
from urllib.parse import urlparse
from guardrails import configure_logging
# from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from src.clients.postgres_client import postgres_is_enabled
from src.otel import otel_is_enabled, initialize


class ReverseProxied(object):
Expand All @@ -19,6 +21,11 @@ def __call__(self, environ, start_response):


def create_app():
if os.environ.get("APP_ENVIRONMENT") != "production":
from dotenv import load_dotenv

load_dotenv()

app = Flask(__name__)

app.config["APPLICATION_ROOT"] = "/"
Expand All @@ -31,12 +38,16 @@ def create_app():
guardrails_log_level = os.environ.get("GUARDRAILS_LOG_LEVEL", "INFO")
configure_logging(log_level=guardrails_log_level)

# FlaskInstrumentor().instrument_app(app)
if otel_is_enabled():
FlaskInstrumentor().instrument_app(app)
initialize()

from src.clients.postgres_client import PostgresClient
# if no pg_host is set, don't set up postgres
if postgres_is_enabled():
from src.clients.postgres_client import PostgresClient

pg_client = PostgresClient()
pg_client.initialize(app)
pg_client = PostgresClient()
pg_client.initialize(app)

from src.blueprints.root import root_bp
from src.blueprints.guards import guards_bp
Expand Down
11 changes: 11 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'''
All guards defined here will be initialized, if and only if
the application is using in memory guards.

The application will use in memory guards if pg_host is left
undefined. Otherwise, a postgres instance will be started
and guards will be persisted into postgres. In that case,
these guards will not be initialized.
'''

from guardrails import Guard
113 changes: 113 additions & 0 deletions custom-install/install.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import os
import sys
import logging
import json
from typing import Any, Dict
from rich.console import Console
from guardrails.cli.hub.install import (
get_site_packages_location,
install_hub_module,
run_post_install,
add_to_hub_inits
)
from guardrails.cli.server.module_manifest import ModuleManifest
from string import Template

console = Console()

os.environ[
"COLOREDLOGS_LEVEL_STYLES"
] = "spam=white,faint;success=green,bold;debug=magenta;verbose=blue;notice=cyan,bold;warning=yellow;error=red;critical=background=red" # noqa
LEVELS = {
"SPAM": 5,
"VERBOSE": 15,
"NOTICE": 25,
"SUCCESS": 35,
}
for key in LEVELS:
logging.addLevelName(LEVELS.get(key), key) # type: ignore
logger = logging.getLogger("custom-install")


def load_manifest(fileName: str) -> Dict[str, Any]:
with open(f"custom-install/manifests/{fileName}") as manifest_file:
content = manifest_file.read()
return json.loads(content)

custom_manifests = {
"guardrails/provenance_llm": load_manifest("provenance-llm.json"),
"guardrails/detect_pii": load_manifest("detect-pii.json"),
"guardrails/competitor_check": load_manifest("competitor-check.json"),
"guardrails/many_shot_jailbreak": load_manifest("jailbreak.json"),
"tryolabs/restricttotopic": load_manifest("restrict-to-topic.json"),
}

def get_validator_manifest(module_name) -> ModuleManifest:
manifest = custom_manifests.get(module_name, {})
return ModuleManifest.from_dict(manifest)

def custom_install(package_uri: str):
"""Install a validator from the Hub."""
if not package_uri.startswith("hub://"):
logger.error("Invalid URI!")
sys.exit(1)

console.print(f"\nInstalling {package_uri}...\n")
logger.log(
level=LEVELS.get("SPAM"), msg=f"Installing {package_uri}..." # type: ignore
)

# Validation
module_name = package_uri.replace("hub://", "")

# Prep
with console.status("Fetching manifest", spinner="bouncingBar"):
module_manifest = get_validator_manifest(module_name)
site_packages = get_site_packages_location()

# Install
with console.status("Downloading dependencies", spinner="bouncingBar"):
install_hub_module(module_manifest, site_packages)

# Post-install
with console.status("Running post-install setup", spinner="bouncingBar"):
run_post_install(module_manifest, site_packages)
add_to_hub_inits(module_manifest, site_packages)

success_message_cli = Template(
"""✅Successfully installed ${module_name}!

[bold]Import validator:[/bold]
from guardrails.hub import ${export}

[bold]Get more info:[/bold]
https://hub.guardrailsai.com/validator/${id}
"""
).safe_substitute(
module_name=package_uri,
id=module_manifest.id,
export=module_manifest.exports[0],
)
success_message_logger = Template(
"""✅Successfully installed ${module_name}!

Import validator:
from guardrails.hub import ${export}

Get more info:
https://hub.guardrailsai.com/validator/${id}
"""
).safe_substitute(
module_name=package_uri,
id=module_manifest.id,
export=module_manifest.exports[0],
)
console.print(success_message_cli) # type: ignore
logger.log(level=LEVELS.get("SPAM"), msg=success_message_logger) # type: ignore


# custom_install("hub://guardrails/provenance_llm")
custom_install("hub://tryolabs/restricttotopic")
# custom_install("hub://guardrails/detect_pii")
# custom_install("hub://guardrails/competitor_check")
# custom_install("hub://guardrails/many_shot_jailbreak")
46 changes: 46 additions & 0 deletions custom-install/manifests/competitor-check.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "Competitor Check",
"author": {
"name": "Guardrails AI",
"email": "contact@guardrailsai.com"
},
"maintainers": [{
"name": "Karan Acharya",
"email": "karan@guardrailsai.com"
}],
"repository": {
"url": "https://github.com/guardrails-ai/competitor_check.git",
"branch": "frontend_demo"
},
"index": "./__init__.py",
"exports": [
"CompetitorCheck"
],
"tags": {
"language": [
"en"
],
"certification": [
"Guardrails Certified"
],
"contentType": [
"string"
],
"infrastructureRequirements": [
"ML"
],
"riskCategory": [
"Brand risk"
],
"useCases": [
"Chatbots",
"Customer Support"
]
},
"id": "guardrails/competitor_check",
"namespace": "guardrails",
"packageName": "competitor_check",
"moduleName": "validator",
"requiresAuth": false,
"postInstall": "post-install.py"
}
Loading
Loading