Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
secrets
secrets
secrets.json
.vscode
65 changes: 64 additions & 1 deletion .github/workflows/github_cd.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Upload Python Package
name: Continuous Deployment Workflow

on:
release:
Expand Down Expand Up @@ -28,6 +28,7 @@ jobs:
with:
name: release-dists
path: dist/

pypi-publish:
runs-on: ubuntu-latest
needs:
Expand All @@ -45,3 +46,65 @@ jobs:
path: dist/
- name: Publish release distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

upload-docker-images:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.12
uses: actions/setup-python@v3
with:
python-version: "3.12"
- name: Install Hatch
run: |
python -m pip install --upgrade pip
pip install Hatch
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4.1.0
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Build Docker images
run: |
# Get the latest commit hash
GIT_COMMIT=$(git rev-parse --short HEAD)
# Define public ECR repository URL
PUBLIC_ECR_URL=public.ecr.aws/e7b5q5z5/nam685
# LangGraph API server
langgraph build -t chatbot -c langgraph.json
docker tag chatbot:latest $PUBLIC_ECR_URL/chatbot:$GIT_COMMIT
# API
docker build -t chatbot-api -f api/Dockerfile .
docker tag chatbot-api:latest $PUBLIC_ECR_URL/chatbot-api:$GIT_COMMIT
# UI
docker build -t chatbot-ui -f ui/Dockerfile ./ui
docker tag chatbot-ui:latest $PUBLIC_ECR_URL/chatbot-ui:$GIT_COMMIT
- name: Log in to Amazon ECR
run: |
aws ecr-public get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin ublic.ecr.aws
- name: Push Docker images to ECR
run: |
PUBLIC_ECR_URL=public.ecr.aws/e7b5q5z5/nam685
docker push $PUBLIC_ECR_URL/chatbot:$GIT_COMMIT
docker push $PUBLIC_ECR_URL/chatbot-api:$GIT_COMMIT
docker push $PUBLIC_ECR_URL/chatbot-ui:$GIT_COMMIT

deploy-ecs-by-cloudformation:
runs-on: ubuntu-latest
needs:
- upload-docker-images
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4.1.0
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Deploy CloudFormation stack
uses: aws-actions/aws-cloudformation-github-deploy@v1
with:
name: chatbot-ecs
template: ecs-infrastructure.yaml
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ __pycache__/
.ruff_cache
.langgraph_api
dist
ui/node_modules
ui/node_modules
secrets.json
deployment-steps.md
2 changes: 1 addition & 1 deletion api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.12
FROM python:3.12-alpine

WORKDIR /code
COPY ./pyproject.toml /code/pyproject.toml
Expand Down
20 changes: 20 additions & 0 deletions api/healthcheck.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import os
import urllib.request


def health_check():
port = os.getenv("CONTAINER_PORT", "8080")
url = f"http://localhost:{port}/health"
try:
with urllib.request.urlopen(url) as response:
status_code = response.getcode()
body = response.read().decode()
print(f"Status code: {status_code}")
print(f"Response body: {body}")
except Exception as e:
print(f"Health check failed: {e}")
exit(1)


if __name__ == "__main__":
health_check()
6 changes: 3 additions & 3 deletions api/main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

Expand All @@ -6,9 +8,7 @@
app = FastAPI()

origins = [
"http://127.0.0.1:3000",
"http://localhost:3000",
"http://ui:3000",
os.getenv("UI_URL", "http://127.0.0.1:3000"),
]

app.add_middleware(
Expand Down
10 changes: 9 additions & 1 deletion api/routers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from typing import Any

from fastapi import APIRouter
Expand All @@ -6,7 +7,9 @@
from .models import ChatMessage, HumanReview, Thread

router = APIRouter()
langgraph_client = get_client(url="http://langgraph-api:8000")
langgraph_client = get_client(
url=os.getenv("LANGGRAPH_API_URI", "http://langgraph-api:8000")
)


def parse_ai_response(
Expand Down Expand Up @@ -34,6 +37,11 @@ async def read_main() -> dict:
return {"msg": "Hello! Welcome to the LangGraph Chat API"}


@router.get("/health")
async def health_check() -> dict:
return {"status": "ok"}


@router.get("/chat")
async def list_chat_threads() -> list[Thread]:
threads_data = await langgraph_client.threads.search(
Expand Down
33 changes: 32 additions & 1 deletion compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,46 @@ services:
env_file:
- .env
environment:
CONTAINER_PORT: 8000
REDIS_URI: redis://langgraph-redis:6379
POSTGRES_URI: postgres://postgres:postgres@langgraph-postgres:5432/postgres?sslmode=disable
healthcheck:
test: [ "CMD", "python", "src/chatbot/healthcheck.py" ]
interval: 10s
timeout: 1s
retries: 5
start_period: 10s
api:
image: chatbot-api:latest
ports:
- "8080:8080"
environment:
CONTAINER_PORT: 8080
UI_URL: http://localhost:3000
LANGGRAPH_API_URI: http://langgraph-api:8000
depends_on:
langgraph-api:
condition: service_healthy
healthcheck:
test: [ "CMD", "python", "api/healthcheck.py" ]
start_period: 3s
timeout: 1s
retries: 5
interval: 5s
ui:
image: chatbot-ui:latest
ports:
- "3000:3000"
environment:
- HOSTNAME=0.0.0.0
HOSTNAME: 0.0.0.0
CONTAINER_PORT: 3000
API_URL: http://localhost:8080
depends_on:
api:
condition: service_healthy
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:3000/health" ]
start_period: 3s
timeout: 1s
retries: 5
interval: 5s
Loading