Skip to content

Commit

Permalink
containerizing socket
Browse files Browse the repository at this point in the history
working ecs/fargate for CLM

more
  • Loading branch information
hume-brian committed Jul 30, 2024
1 parent 4793e6f commit 2a816cf
Show file tree
Hide file tree
Showing 13 changed files with 425 additions and 39 deletions.
2 changes: 2 additions & 0 deletions evi-modal-clm/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cdk*
.venv*
33 changes: 33 additions & 0 deletions evi-modal-clm/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Use the official Python base image
FROM --platform=linux/amd64 python:3.11-slim

# Install Poetry
RUN python3 -m venv .venv
RUN . .venv/bin/activate

RUN pip install --upgrade pip
RUN pip install poetry

# Add Poetry to PATH
ENV PATH="$HOME/.local/bin:${PATH}"

# Set the working directory in the container
WORKDIR /app

# Copy only the poetry files first to leverage Docker cache
COPY pyproject.toml poetry.lock ./

# Install dependencies
RUN poetry install --no-root --no-dev

# Copy the rest of the application code into the container
COPY . .

# Install the application
RUN poetry install --no-dev

# Expose the port the app runs on
EXPOSE 8000

# Command to run the application
CMD ["poetry", "run", "fastapi", "run", "app.py"]
37 changes: 0 additions & 37 deletions evi-modal-clm/main.py → evi-modal-clm/agent.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
from modal import Image, App, asgi_app
import re
import json

# Define a list of reflections to mirror the user's input
reflections = {
Expand Down Expand Up @@ -344,38 +342,3 @@ def eliza_response(user_input):
response = responses[0].format(*[reflect(g) for g in match.groups()])
return response
return "I see. Please tell me more."


# ------- MODAL --------
# deploy with `poetry run python -m modal deploy main.py`

app = App("hume-eliza")
app.image = Image.debian_slim().pip_install("fastapi", "websockets")


@app.function()
@asgi_app()
def endpoint():
from fastapi import FastAPI, WebSocket

app = FastAPI()

@app.websocket("/ws")
async def websocket_handler(websocket: WebSocket) -> None:
await websocket.accept()
while True:
data = await websocket.receive_text()

hume_payload = json.loads(data)
last_message = hume_payload["messages"][-1]["message"]["content"]

user_text = last_message.split("{")[0] or ""

await websocket.send_text(
json.dumps(
{"type": "assistant_input", "text": eliza_response(user_text)}
)
)
await websocket.send_text(json.dumps({"type": "assistant_end"}))

return app
26 changes: 26 additions & 0 deletions evi-modal-clm/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import json
from agent import eliza_response

from fastapi import FastAPI, WebSocket

eliza_app = FastAPI()

@eliza_app.get("/")
async def root():
return {"message": "Hello World"}

@eliza_app.websocket("/ws")
async def websocket_handler(websocket: WebSocket) -> None:
await websocket.accept()
while True:
data = await websocket.receive_text()

hume_payload = json.loads(data)
last_message = hume_payload["messages"][-1]["message"]["content"]

user_text = last_message.split("{")[0] or ""

await websocket.send_text(
json.dumps({"type": "assistant_input", "text": eliza_response(user_text)})
)
await websocket.send_text(json.dumps({"type": "assistant_end"}))
17 changes: 17 additions & 0 deletions evi-modal-clm/cdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# AWS CDK Definition for EVI CLM

This is the AWS CDK definition for the EVI CLM. It defines the infrastructure for the EVI CLM as a ECS Fargate service.

## Prerequisites

1. Install Docker.
2. Install the AWS CDK CLI. You can find instructions [here](https://docs.aws.amazon.com/cdk/latest/guide/work-with-cdk-python.html).
3. Create a virtual environment and install the required dependencies.
4. Configure your AWS credentials.
5. Install the AWS CLI.
6. Run `aws configure` to configure your AWS CLI.
7. Run `cdk bootstrap` to create the required resources in your AWS account.
8. Run 'cdk synth' to generate the CloudFormation template.
9. Run 'cdk deploy' to deploy the stack.

It will output the load balancer URL. You can access the CLM via `ws://<load_balancer_url>/ws`.
25 changes: 25 additions & 0 deletions evi-modal-clm/cdk/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
import os

import aws_cdk as cdk

from cdk.eliza_stack import ElizaStack


app = cdk.App()
ElizaStack(
app,
"ElizaStack",
# If you don't specify 'env', this stack will be environment-agnostic.
# Account/Region-dependent features and context lookups will not work,
# but a single synthesized template can be deployed anywhere.
# Uncomment the next line to specialize this stack for the AWS Account
# and Region that are implied by the current CLI configuration.
# env=cdk.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION')),
# Uncomment the next line if you know exactly what Account and Region you
# want to deploy the stack to. */
# env=cdk.Environment(account='123456789012', region='us-east-1'),
# For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html
)

app.synth()
70 changes: 70 additions & 0 deletions evi-modal-clm/cdk/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"app": "python3 app.py",
"watch": {
"include": [
"**"
],
"exclude": [
"README.md",
"cdk*.json",
"requirements*.txt",
"source.bat",
"**/__init__.py",
"**/__pycache__",
"tests"
]
},
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
],
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
"@aws-cdk/aws-iam:minimizePolicies": true,
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
"@aws-cdk/core:enablePartitionLiterals": true,
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/aws-route53-patters:useCertificate": true,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
"@aws-cdk/aws-redshift:columnId": true,
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
"@aws-cdk/aws-kms:aliasNameRef": true,
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
"@aws-cdk/aws-stepfunctions-tasks:ecsReduceRunTaskPermissions": true
}
}
Empty file.
38 changes: 38 additions & 0 deletions evi-modal-clm/cdk/cdk/eliza_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import aws_cdk as cdk
from aws_cdk import aws_ec2 as ec2
from aws_cdk import aws_ecs as ecs
from aws_cdk import aws_ecs_patterns as ecs_patterns
from aws_cdk.aws_ecr_assets import DockerImageAsset
import os


class ElizaStack(cdk.Stack):
# https://medium.com/@jolodev/demystifying-aws-cdks-ecs-pattern-e58315972544
def __init__(self, scope: cdk.App, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)

image = DockerImageAsset(
self,
"BackendImage",
directory=os.path.join(os.path.dirname(__file__), "..", ".."),
)

vpc = ec2.Vpc(self, "ApplicationVpc", max_azs=2)

cluster = ecs.Cluster(self, "Cluster", vpc=vpc)

ecs_patterns.ApplicationLoadBalancedFargateService(
self,
"ApplicationFargateService",
cluster=cluster,
cpu=256,
desired_count=1,
task_image_options={
"image": ecs.ContainerImage.from_docker_image_asset(image),
"container_port": 8000,
},
memory_limit_mib=512,
public_load_balancer=True,
)

cdk.CfnOutput(self, "LoadBalancerDNS", value=cluster.cluster_name)
2 changes: 2 additions & 0 deletions evi-modal-clm/cdk/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
aws-cdk-lib==2.150.0
constructs>=10.0.0,<11.0.0
15 changes: 15 additions & 0 deletions evi-modal-clm/modal_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from modal import Image, App, asgi_app
from app import eliza_app

# ------- MODAL --------
# deploy with `poetry run python -m modal deploy modal_app.py`


app = App("hume-eliza")
app.image = Image.debian_slim().pip_install("fastapi", "websockets")


@app.function()
@asgi_app()
def endpoint():
return eliza_app
Loading

0 comments on commit 2a816cf

Please sign in to comment.