Add fastapi deployment

Signed-off-by: András Schmelczer <andras@schmelczer.dev>
This commit is contained in:
Andras Schmelczer 2022-04-06 19:01:34 +02:00
parent 3c1b02855a
commit bf019cc5a7
16 changed files with 83 additions and 13 deletions

View file

@ -1,11 +1,14 @@
{ {
"cSpell.words": [ "cSpell.words": [
"boto",
"botocore", "botocore",
"pydantic", "pydantic",
"pyplot", "pyplot",
"sklearn", "sklearn",
"starlette",
"Tfidf", "Tfidf",
"tinydb", "tinydb",
"uvicorn",
"Vectorizer", "Vectorizer",
"xmargin" "xmargin"
], ],

View file

@ -4,9 +4,11 @@ from random import shuffle
from devtools import debug from devtools import debug
from predict_domain import predict_domain from predict_domain import predict_domain
from good_ai import process_batch from good_ai import process_batch, serve
if __name__ == "__main__": if __name__ == "__main__":
serve(predict_domain)
with open(".cache/ss-data-0/s2-corpus-1583.json") as f: with open(".cache/ss-data-0/s2-corpus-1583.json") as f:
raw = json.load(f) raw = json.load(f)

View file

@ -1,3 +1,3 @@
from .deploy import process_batch from .deploy import process_batch, serve
from .models import save_model, use_model from .models import save_model, use_model
from .set_default_config import set_default_config, set_default_config_if_uninitialized from .set_default_config import set_default_config

View file

@ -0,0 +1,14 @@
import logging
import os
logger = logging.getLogger("good_ai")
PRODUCTION_KEY = "production"
environment = os.environ.get("ENVIRONMENT", PRODUCTION_KEY).lower()
is_production = environment == PRODUCTION_KEY
if is_production:
logger.info("Running in production mode ✅")
else:
logger.warn("Running in development mode ‼️")

View file

@ -1 +1,2 @@
from .process_batch import process_batch from .process_batch import process_batch
from .serve import serve

View file

@ -3,7 +3,8 @@ from typing import Any, Callable, Iterable, Optional, Sequence
from good_ai.utilities.parallel_map import parallel_map from good_ai.utilities.parallel_map import parallel_map
from ..set_default_config import set_default_config_if_uninitialized from ..set_default_config import set_default_config_if_uninitialized
from ..tracing import Trace, TracingContext from ..tracing import TracingContext
from ..views import Trace
def process_batch( def process_batch(

View file

@ -1 +1,47 @@
from typing import Any, Callable
import uvicorn
from fastapi import FastAPI, status
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.responses import RedirectResponse
from starlette.responses import HTMLResponse
from typing_extensions import Never
from ..set_default_config import set_default_config_if_uninitialized
from ..tracing import TracingContext
from ..views import HealthCheckResponse, Trace
def serve(
function: Callable[..., Any],
) -> Never:
set_default_config_if_uninitialized()
app = FastAPI(
title=function.__name__.capitalize().replace("_", " "),
description=f"REST API wrapper for interacting with the {function.__name__} function.",
docs_url=None,
redoc_url=None,
)
@app.get("/", include_in_schema=False)
def redirect_to_docs() -> RedirectResponse:
return RedirectResponse("/docs")
@app.get("/docs", include_in_schema=False)
def custom_swagger_ui_html() -> HTMLResponse:
return get_swagger_ui_html(openapi_url="openapi.json", title=app.title)
@app.get("/health", status_code=status.HTTP_200_OK)
def check_health() -> HealthCheckResponse:
return HealthCheckResponse(is_healthy=True)
@app.post("/score", status_code=status.HTTP_200_OK, response_model=Trace)
def process(input: Any) -> Trace:
with TracingContext() as t:
t.log_input(input)
result = function(input)
output = t.log_output(result)
return output
uvicorn.run(app, host="0.0.0.0", port=5050)

View file

@ -1,7 +1,8 @@
from functools import wraps from functools import wraps
from typing import Any, Callable, Literal, Union from typing import Any, Callable, Literal, Union
from ..tracing import Model, TracingContext from ..tracing import TracingContext
from ..views import Model
from .load_model import load_model from .load_model import load_model

View file

@ -33,7 +33,7 @@ def set_default_config(
_initialized = True _initialized = True
logger.info(f"Defaults: configured ✅") logger.info("Defaults: configured ✅")
def _initialize_large_file(s3_config: Path) -> None: def _initialize_large_file(s3_config: Path) -> None:

View file

@ -1,4 +1,2 @@
from .model import Model
from .persistence import MongoDbDriver, PersistenceDriver, TinyDbDriver from .persistence import MongoDbDriver, PersistenceDriver, TinyDbDriver
from .trace import Trace
from .tracing_context import TracingContext from .tracing_context import TracingContext

View file

@ -5,13 +5,11 @@ from datetime import datetime
from types import TracebackType from types import TracebackType
from typing import Any, DefaultDict, List, Optional, Type from typing import Any, DefaultDict, List, Optional, Type
from ..views import Model, Trace
from .persistence import PersistenceDriver from .persistence import PersistenceDriver
logger = logging.getLogger("good_ai") logger = logging.getLogger("good_ai")
from .model import Model
from .trace import Trace
class TracingContext: class TracingContext:
persistence_driver: PersistenceDriver persistence_driver: PersistenceDriver

View file

@ -0,0 +1,3 @@
from .health_check_response import HealthCheckResponse
from .model import Model
from .trace import Trace

View file

@ -0,0 +1,5 @@
from pydantic import BaseModel
class HealthCheckResponse(BaseModel):
is_healthy: bool

View file

@ -96,7 +96,6 @@ class LargeFile:
credentials.default_section credentials.default_section
cls.configure_credentials(**credentials[credentials.default_section]) cls.configure_credentials(**credentials[credentials.default_section])
@classmethod @classmethod
def configure_credentials( def configure_credentials(
cls, cls,
@ -114,7 +113,6 @@ class LargeFile:
cls.bucket_name = large_files_bucket_name cls.bucket_name = large_files_bucket_name
cls.endpoint_url = aws_endpoint_url cls.endpoint_url = aws_endpoint_url
def __enter__(self) -> IO: def __enter__(self) -> IO:
self._file: IO[Any] = ( self._file: IO[Any] = (
tempfile.NamedTemporaryFile( tempfile.NamedTemporaryFile(