Skip to content

Commit

Permalink
Merge pull request #50 from guardrails-ai/get-history
Browse files Browse the repository at this point in the history
GET history endpoint
  • Loading branch information
CalebCourier authored Jun 24, 2024
2 parents 65efea5 + 278b912 commit fbcb8b6
Show file tree
Hide file tree
Showing 12 changed files with 155 additions and 81 deletions.
5 changes: 0 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ jobs:
pip install build;
continue-on-error: false

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20

- name: Build the module
env:
PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ install:

# Installs development dependencies
install-dev:
pip install .[dev];
pip install ".[dev]";

lock:
pip freeze --exclude guardrails-api-client > requirements-lock.txt
Expand Down
2 changes: 1 addition & 1 deletion guardrails_api/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.0.0"
__version__ = "0.0.0a0"
11 changes: 10 additions & 1 deletion guardrails_api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from guardrails_api.clients.postgres_client import postgres_is_enabled
from guardrails_api.otel import otel_is_disabled, initialize
from guardrails_api.clients.cache_client import CacheClient


# TODO: Move this to a separate file
Expand Down Expand Up @@ -46,7 +47,7 @@ def register_config(config: Optional[str] = None):
SourceFileLoader("config", config_file_path).load_module()


def create_app(env: Optional[str] = None, config: Optional[str] = None):
def create_app(env: Optional[str] = None, config: Optional[str] = None, port: Optional[int] = None):
if os.environ.get("APP_ENVIRONMENT") != "production":
from dotenv import load_dotenv

Expand All @@ -55,6 +56,11 @@ def create_app(env: Optional[str] = None, config: Optional[str] = None):
env_file_path = os.path.abspath(env_file)
load_dotenv(env_file_path)

set_port = port or os.environ.get("PORT", 8000)
host = os.environ.get("HOST", "http://localhost")
self_endpoint = os.environ.get("SELF_ENDPOINT", f"{host}:{set_port}")
os.environ["SELF_ENDPOINT"] = self_endpoint

register_config(config)

app = Flask(__name__)
Expand All @@ -80,6 +86,9 @@ def create_app(env: Optional[str] = None, config: Optional[str] = None):

pg_client = PostgresClient()
pg_client.initialize(app)

cache_client = CacheClient()
cache_client.initialize(app)

from guardrails_api.blueprints.root import root_bp
from guardrails_api.blueprints.guards import guards_bp
Expand Down
15 changes: 15 additions & 0 deletions guardrails_api/blueprints/guards.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from opentelemetry.trace import Span
from guardrails_api_client import Guard as GuardStruct
from guardrails_api.classes.http_error import HttpError
from guardrails_api.clients.cache_client import CacheClient
from guardrails_api.clients.memory_guard_client import MemoryGuardClient
from guardrails_api.clients.pg_guard_client import PGGuardClient
from guardrails_api.clients.postgres_client import postgres_is_enabled
Expand All @@ -34,6 +35,8 @@
is_guard = isinstance(export, Guard)
if is_guard:
guard_client.create_guard(export)

cache_client = CacheClient()


@guards_bp.route("/", methods=["GET", "POST"])
Expand Down Expand Up @@ -308,4 +311,16 @@ def validate_streamer(guard_iter):
# prompt_params=prompt_params,
# result=result
# )
serialized_history = [
call.to_dict() for call in guard.history
]
cache_key = f"{guard.name}-{result.call_id}"
cache_client.set(cache_key, serialized_history, 300)
return result.to_dict()

@guards_bp.route("/<guard_name>/history/<call_id>", methods=["GET"])
@handle_error
def guard_history(guard_name: str, call_id: str):
if request.method == "GET":
cache_key = f"{guard_name}-{call_id}"
return cache_client.get(cache_key)
22 changes: 16 additions & 6 deletions guardrails_api/cli/start.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,22 @@ def start(
env: Optional[str] = typer.Option(
default="",
help="An env file to load environment variables from.",
prompt=".env file (optional)",
),
config: Optional[str] = typer.Option(
default="",
help="A config file to load Guards from.",
prompt="config file (optional)",
),
timeout: Optional[int] = typer.Option(
default=5,
help="Gunicorn worker timeout.",
),
threads: Optional[int] = typer.Option(
default=10,
help="Number of Gunicorn worker threads.",
),
port: Optional[int] = typer.Option(
default=8000,
help="The port to run the server on.",
),
):
# TODO: If these are empty,
Expand All @@ -43,8 +53,8 @@ def start(
config = config or None

options = {
"bind": "0.0.0.0:8000",
"timeout": 5,
"threads": 10,
"bind": f"0.0.0.0:{port}",
"timeout": timeout,
"threads": threads,
}
StandaloneApplication(create_app(env, config), options).run()
StandaloneApplication(create_app(env, config, port), options).run()
34 changes: 34 additions & 0 deletions guardrails_api/clients/cache_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from flask_caching import Cache


# TODO: Add option to connect to Redis or MemCached backend with environment variables
class CacheClient:
_instance = None

def __new__(cls):
if cls._instance is None:
cls._instance = super(CacheClient, cls).__new__(cls)
return cls._instance


def initialize(self, app):
self.cache = Cache(
app,
config={
"CACHE_TYPE": "SimpleCache",
"CACHE_DEFAULT_TIMEOUT": 300,
"CACHE_THRESHOLD": 50
}
)

def get(self, key):
return self.cache.get(key)

def set(self, key, value, ttl):
self.cache.set(key, value, timeout=ttl)

def delete(self, key):
self.cache.delete(key)

def clear(self):
self.cache.clear()
3 changes: 2 additions & 1 deletion guardrails_api/default.env
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ PYTHONUNBUFFERED=1
LOGLEVEL="INFO"
GUARDRAILS_LOG_LEVEL="INFO"
GUARDRAILS_PROCESS_COUNT=1
SELF_ENDPOINT=http://localhost:8000
HOST=http://localhost
PORT=8000
OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ readme = "README.md"
keywords = ["Guardrails", "Guardrails AI", "Guardrails API", "Guardrails API"]
requires-python = ">= 3.8.1"
dependencies = [
"guardrails-ai@git+https://github.com/guardrails-ai/guardrails.git@core-schema-impl",
"guardrails-ai>=0.5.0a2",
"flask>=3.0.3,<4",
"Flask-SQLAlchemy>=3.1.1,<4",
"Flask-Caching>=2.3.0,<3",
"Werkzeug>=3.0.3,<4",
"jsonschema>=4.22.0,<5",
"referencing>=0.35.1,<1",
Expand Down
113 changes: 53 additions & 60 deletions requirements-lock.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,96 +2,84 @@ aiohttp==3.9.5
aiosignal==1.3.1
annotated-types==0.7.0
anyio==4.4.0
asgiref==3.8.1
arrow==1.3.0
attrs==23.2.0
blinker==1.8.2
boto3==1.34.115
botocore==1.34.115
certifi==2024.2.2
boto3==1.34.132
botocore==1.34.132
cachelib==0.9.0
certifi==2024.6.2
cffi==1.16.0
charset-normalizer==3.3.2
click==8.1.7
colorama==0.4.6
coloredlogs==15.0.1
cryptography==42.0.7
cryptography==42.0.8
Deprecated==1.2.14
distro==1.9.0
faiss-cpu==1.8.0
filelock==3.14.0
Faker==25.9.1
filelock==3.15.4
Flask==3.0.3
Flask-Caching==2.3.0
Flask-Cors==4.0.1
Flask-SQLAlchemy==3.1.1
fqdn==1.5.1
frozenlist==1.4.1
fsspec==2024.5.0
googleapis-common-protos==1.63.0
fsspec==2024.6.0
googleapis-common-protos==1.63.2
griffe==0.36.9
grpcio==1.64.0
guardrails-ai @ git+https://github.com/guardrails-ai/guardrails.git@fd77007dfe823f8cb32cd314b78e5f63aea71e9a
grpcio==1.64.1
guardrails-ai==0.5.0a2
guardrails-api @ file:///Users/calebcourier/Projects/gr-mono/guardrails-cdk/guardrails-api
guardrails-api-client==0.3.8
gunicorn==22.0.0
h11==0.14.0
httpcore==1.0.5
httpx==0.27.0
huggingface-hub==0.23.2
huggingface-hub==0.23.4
humanfriendly==10.0
idna==3.7
importlib-metadata==7.0.0
ijson==3.3.0
importlib_metadata==7.1.0
isoduration==20.11.0
itsdangerous==2.2.0
Jinja2==3.1.4
jmespath==1.0.1
joblib==1.4.2
jsonpatch==1.33
jsonpointer==2.4
jsonpointer==3.0.0
jsonref==1.1.0
jsonschema==4.22.0
jsonschema-specifications==2023.12.1
jwt==1.3.1
langchain-core==0.1.52
langsmith==0.1.65
litellm==1.39.3
langchain-core==0.2.9
langsmith==0.1.82
litellm==1.40.25
lxml==4.9.4
markdown-it-py==3.0.0
MarkupSafe==2.1.5
mdurl==0.1.2
multidict==6.0.5
nltk==3.8.1
numpy==1.26.4
openai==1.30.5
opentelemetry-api==1.24.0
opentelemetry-distro==0.45b0
opentelemetry-exporter-otlp-proto-common==1.24.0
opentelemetry-exporter-otlp-proto-grpc==1.24.0
opentelemetry-exporter-otlp-proto-http==1.24.0
opentelemetry-instrumentation==0.45b0
opentelemetry-instrumentation-asgi==0.45b0
opentelemetry-instrumentation-asyncio==0.45b0
opentelemetry-instrumentation-aws-lambda==0.45b0
opentelemetry-instrumentation-boto3sqs==0.45b0
opentelemetry-instrumentation-botocore==0.45b0
opentelemetry-instrumentation-dbapi==0.45b0
opentelemetry-instrumentation-flask==0.45b0
opentelemetry-instrumentation-grpc==0.45b0
opentelemetry-instrumentation-httpx==0.45b0
opentelemetry-instrumentation-jinja2==0.45b0
opentelemetry-instrumentation-logging==0.45b0
opentelemetry-instrumentation-requests==0.45b0
opentelemetry-instrumentation-sqlalchemy==0.45b0
opentelemetry-instrumentation-sqlite3==0.45b0
opentelemetry-instrumentation-tortoiseorm==0.45b0
opentelemetry-instrumentation-urllib==0.45b0
opentelemetry-instrumentation-urllib3==0.45b0
opentelemetry-instrumentation-wsgi==0.45b0
opentelemetry-propagator-aws-xray==1.0.1
opentelemetry-proto==1.24.0
opentelemetry-sdk==1.24.0
opentelemetry-semantic-conventions==0.45b0
opentelemetry-test-utils==0.45b0
opentelemetry-util-http==0.45b0
orjson==3.10.3
packaging==23.2
openai==1.35.3
opentelemetry-api==1.25.0
opentelemetry-exporter-otlp-proto-common==1.25.0
opentelemetry-exporter-otlp-proto-grpc==1.25.0
opentelemetry-exporter-otlp-proto-http==1.25.0
opentelemetry-instrumentation==0.46b0
opentelemetry-instrumentation-flask==0.46b0
opentelemetry-instrumentation-wsgi==0.46b0
opentelemetry-proto==1.25.0
opentelemetry-sdk==1.25.0
opentelemetry-semantic-conventions==0.46b0
opentelemetry-util-http==0.46b0
orjson==3.10.5
packaging==24.1
protobuf==4.25.3
psycopg2-binary==2.9.9
pycparser==2.22
pydantic==2.7.2
pydantic_core==2.18.3
pydantic==2.7.4
pydantic_core==2.18.4
pydash==7.0.7
Pygments==2.18.0
python-dateutil==2.9.0.post0
Expand All @@ -100,23 +88,28 @@ PyYAML==6.0.1
referencing==0.35.1
regex==2023.12.25
requests==2.32.3
rfc3339-validator==0.1.4
rfc3987==1.3.8
rich==13.7.1
rpds-py==0.18.1
rstr==3.2.2
s3transfer==0.10.1
setuptools==70.0.0
s3transfer==0.10.2
setuptools==70.1.0
shellingham==1.5.4
six==1.16.0
sniffio==1.3.1
SQLAlchemy==2.0.30
tenacity==8.3.0
SQLAlchemy==2.0.31
tenacity==8.4.2
tiktoken==0.7.0
tokenizers==0.19.1
tqdm==4.66.4
typer==0.9.4
typing_extensions==4.12.0
urllib3==2.2.1
types-python-dateutil==2.9.0.20240316
typing_extensions==4.12.2
uri-template==1.3.0
urllib3==2.2.2
webcolors==24.6.0
Werkzeug==3.0.3
wrapt==1.16.0
yarl==1.9.4
zipp==3.19.0
zipp==3.19.2
Loading

0 comments on commit fbcb8b6

Please sign in to comment.