-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
IL-421 classification user journey with Docker, Kubernetes setup
* feat: WIP Classification runs as container on localhost - Enhance use case Jupyter Notebook to include guidance for TASK: IL-421 * WIP: Add classificationservice FastAPI setup and Dockerfile TASK: IL-421 * IL-421 expose docker port to localhost * IL-421 kubernetes yaml * IL-421 Kubernetes notes --------- Co-authored-by: Florian Schepers <[email protected]> Co-authored-by: FelixFehse <[email protected]>
- Loading branch information
1 parent
f8bb381
commit efd20a8
Showing
5 changed files
with
215 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
FROM ubuntu:latest as builder | ||
|
||
RUN apt-get update && apt-get upgrade -y \ | ||
&& apt-get install -y python3 python3-pip python3-venv git | ||
|
||
RUN mkdir /app | ||
COPY requirements.txt /app/requirements.txt | ||
|
||
RUN python3 -m venv /app/venv | ||
ENV PATH="/app/venv/bin:$PATH" | ||
|
||
RUN pip install --upgrade pip | ||
RUN --mount=type=secret,id=GITHUB_TOKEN \ | ||
GITHUB_TOKEN=$(cat /run/secrets/GITHUB_TOKEN) \ | ||
pip install -r /app/requirements.txt | ||
|
||
|
||
FROM ubuntu:latest as runtime | ||
|
||
# Delete apt package lists immediately to save ~45MB. This has to be done in the same RUN command, | ||
# otherwise the data is already persisted in another layer. | ||
RUN apt-get update && apt-get upgrade -y \ | ||
&& apt-get install -y python3 \ | ||
&& rm -r /var/lib/apt/lists/* | ||
|
||
COPY --from=builder /app /app | ||
COPY main.py /app/main.py | ||
|
||
ENV PATH="/app/venv/bin:$PATH" | ||
WORKDIR /app | ||
ENTRYPOINT [ "hypercorn", "main:app", "--bind", "0.0.0.0:80", "--access-logfile", "-", "--access-logformat", "%(h)s %(l)s %(l)s %(t)s \"%(r)s\" %(s)s %(b)s %(L)s \"%(f)s\" \"%(a)s\""] |
23 changes: 23 additions & 0 deletions
23
src/examples/issue_classification_user_journey/classification_deployment.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: banana | ||
spec: | ||
replicas: 1 | ||
selector: | ||
matchLabels: | ||
app: banana | ||
template: | ||
metadata: | ||
labels: | ||
app: banana | ||
spec: | ||
containers: | ||
- env: | ||
- name: AA_TOKEN | ||
valueFrom: | ||
secretKeyRef: | ||
key: AA_TOKEN | ||
name: aa-token | ||
image: classification-service:local | ||
name: banana |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import http | ||
import os | ||
from http import HTTPStatus | ||
from typing import Annotated, Sequence | ||
|
||
from aleph_alpha_client import Client | ||
from dotenv import load_dotenv | ||
from fastapi import Depends, FastAPI, HTTPException, Request, Response | ||
from fastapi.datastructures import URL | ||
|
||
from intelligence_layer.connectors import AlephAlphaClientProtocol | ||
from intelligence_layer.core import LuminousControlModel, NoOpTracer, Task | ||
from intelligence_layer.use_cases import ( | ||
ClassifyInput, | ||
PromptBasedClassify, | ||
SingleLabelClassifyOutput, | ||
) | ||
|
||
# Minimal FastAPI app ########################################################## | ||
|
||
app = FastAPI() | ||
|
||
|
||
@app.get("/") | ||
def root() -> Response: | ||
return Response(content="Classification Service", status_code=HTTPStatus.OK) | ||
|
||
|
||
# Authentication ############################################################### | ||
|
||
|
||
class AuthService: | ||
def is_valid_token(self, token: str, permissions: Sequence[str], url: URL) -> bool: | ||
# Add your authentication logic here | ||
print(f"Checking permission for route: {url.path}") | ||
return True | ||
|
||
|
||
class PermissionChecker: | ||
def __init__(self, permissions: Sequence[str] = []): | ||
self.permissions = permissions | ||
|
||
def __call__( | ||
self, | ||
request: Request, | ||
auth_service: Annotated[AuthService, Depends(AuthService)], | ||
) -> None: | ||
token = request.headers.get("Authorization") or "" | ||
try: | ||
if not auth_service.is_valid_token(token, self.permissions, request.url): | ||
raise HTTPException(HTTPStatus.UNAUTHORIZED) | ||
except RuntimeError: | ||
raise HTTPException(HTTPStatus.INTERNAL_SERVER_ERROR) | ||
|
||
|
||
permission_checker_for_user = PermissionChecker(["User"]) | ||
|
||
|
||
# Intelligence Layer Task ###################################################### | ||
|
||
PROMPT = """Identify the department that would be responsible for handling the given request. | ||
Reply with only the department name.""" | ||
|
||
load_dotenv() | ||
|
||
|
||
def client() -> Client: | ||
return Client( | ||
token=os.environ["AA_TOKEN"], | ||
host=os.getenv("AA_CLIENT_BASE_URL", "https://api.aleph-alpha.com"), | ||
) | ||
|
||
|
||
def default_model( | ||
app_client: Annotated[AlephAlphaClientProtocol, Depends(client)], | ||
) -> LuminousControlModel: | ||
return LuminousControlModel("luminous-supreme-control", client=app_client) | ||
|
||
|
||
def classification_task( | ||
model: Annotated[LuminousControlModel, Depends(default_model)], | ||
) -> PromptBasedClassify: | ||
return PromptBasedClassify(instruction=PROMPT, model=model) | ||
|
||
|
||
@app.post( | ||
"/classify", | ||
# dependencies=[Depends(PermissionChecker(["User"]))], | ||
status_code=http.HTTPStatus.OK, | ||
) | ||
def classification_task_route( | ||
input: ClassifyInput, | ||
task: Annotated[ | ||
Task[ClassifyInput, SingleLabelClassifyOutput], Depends(classification_task) | ||
], | ||
) -> SingleLabelClassifyOutput: | ||
return task.run(input, NoOpTracer()) |
Binary file not shown.