Skip to content

Commit f93d91d

Browse files
authored
Merge pull request #265 from FullStackWithLawrence/next
add real-time 24-hour weather forecast to lambda_openai_function
2 parents a7519cc + f601c64 commit f93d91d

File tree

24 files changed

+427
-38
lines changed

24 files changed

+427
-38
lines changed

.github/actions/tests/python/action.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ inputs:
2727
description: "The Pinecone environment"
2828
required: true
2929
type: string
30+
google-maps-api-key:
31+
description: "Google Maps API key"
32+
required: true
33+
type: string
3034

3135
runs:
3236
using: "composite"
@@ -93,6 +97,7 @@ runs:
9397
shell: bash
9498
run: |
9599
touch ./.env
100+
echo "GOOGLE_MAPS_API_KEY=${{ env.GOOGLE_MAPS_API_KEY }}" >> ./.env
96101
echo "OPENAI_API_ORGANIZATION=${{ env.OPENAI_API_ORGANIZATION }}" >> ./.env
97102
echo "OPENAI_API_KEY=${{ env.OPENAI_API_KEY }}" >> ./.env
98103
echo "PINECONE_API_KEY=${{ env.PINECONE_API_KEY }}" >> ./.env
@@ -103,6 +108,7 @@ runs:
103108
OPENAI_API_KEY: ${{ inputs.openai-api-key }}
104109
PINECONE_API_KEY: ${{ inputs.pinecone-api-key }}
105110
PINECONE_ENVIRONMENT: ${{ inputs.pinecone-environment }}
111+
GOOGLE_MAPS_API_KEY: ${{ inputs.google-maps-api-key }}
106112

107113
- name: Run Python unit tests
108114
shell: bash

.github/workflows/runTests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ jobs:
3232
uses: ./.github/actions/tests/python
3333
with:
3434
python-version: "${{ env.python-version}}"
35+
google-api-key: "${{ secrets.GOOGLE_API_KEY }}"
3536
openai-api-organization: "${{ secrets.OPENAI_API_ORGANIZATION }}"
3637
openai-api-key: "${{ secrets.OPENAI_API_KEY }}"
3738
pinecone-api-key: "${{ secrets.PINECONE_API_KEY }}"

.github/workflows/testsPython.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jobs:
3838
uses: ./.github/actions/tests/python
3939
with:
4040
python-version: "${{ env.python-version}}"
41+
google-maps-api-key: "${{ secrets.GOOGLE_MAPS_API_KEY }}"
4142
openai-api-organization: "${{ secrets.OPENAI_API_ORGANIZATION }}"
4243
openai-api-key: "${{ secrets.OPENAI_API_KEY }}"
4344
pinecone-api-key: "${{ secrets.PINECONE_API_KEY }}"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ lambda_dist_pkg
1515
*.zip
1616
__pycache__
1717
.pytest_cache
18+
.cache.sqlite
1819

1920
# Python
2021
venv

CHANGELOG.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
11
# [0.10.0](https://github.com/FullStackWithLawrence/aws-openai/compare/v0.9.1...v0.10.0) (2024-01-23)
22

3-
43
### Bug Fixes
54

6-
* add handling for legacy native openai api responses ([b5de30c](https://github.com/FullStackWithLawrence/aws-openai/commit/b5de30cbbfebed2ca50189063b80f16a92b9b49e))
7-
5+
- add handling for legacy native openai api responses ([b5de30c](https://github.com/FullStackWithLawrence/aws-openai/commit/b5de30cbbfebed2ca50189063b80f16a92b9b49e))
86

97
### Features
108

11-
* add openai-function-calling app ([9033b6d](https://github.com/FullStackWithLawrence/aws-openai/commit/9033b6dd02fea818588ae9d926ded4cbf34411eb))
12-
* code lambda_handler() to process tool_call(s) returned by openai api ([f4b076c](https://github.com/FullStackWithLawrence/aws-openai/commit/f4b076cff230fee81faf8d0858baf409f0b9ada2))
13-
* convert urls in response text to links and add styling ([031eac7](https://github.com/FullStackWithLawrence/aws-openai/commit/031eac772627f13636501071ea212c0210476a95))
14-
* create new layer_nlp lambda layer ([1c11515](https://github.com/FullStackWithLawrence/aws-openai/commit/1c115155252b954189418c9415aae7912d633b3d))
15-
* scaffold a lambda that uses an openai function ([b6a5cc2](https://github.com/FullStackWithLawrence/aws-openai/commit/b6a5cc280fe57637e2cdf6ba869cc8760bc49d4e))
9+
- add openai-function-calling app ([9033b6d](https://github.com/FullStackWithLawrence/aws-openai/commit/9033b6dd02fea818588ae9d926ded4cbf34411eb))
10+
- code lambda_handler() to process tool_call(s) returned by openai api ([f4b076c](https://github.com/FullStackWithLawrence/aws-openai/commit/f4b076cff230fee81faf8d0858baf409f0b9ada2))
11+
- convert urls in response text to links and add styling ([031eac7](https://github.com/FullStackWithLawrence/aws-openai/commit/031eac772627f13636501071ea212c0210476a95))
12+
- create new layer_nlp lambda layer ([1c11515](https://github.com/FullStackWithLawrence/aws-openai/commit/1c115155252b954189418c9415aae7912d633b3d))
13+
- scaffold a lambda that uses an openai function ([b6a5cc2](https://github.com/FullStackWithLawrence/aws-openai/commit/b6a5cc280fe57637e2cdf6ba869cc8760bc49d4e))
1614

1715
## [0.9.1](https://github.com/FullStackWithLawrence/aws-openai/compare/v0.9.0...v0.9.1) (2024-01-20)
1816

19-
2017
### Bug Fixes
2118

22-
* force a new release ([a069aae](https://github.com/FullStackWithLawrence/aws-openai/commit/a069aae8d6d0959cbc74334f0ebdf0105d55c3a8))
23-
* force a new release ([a2daf8a](https://github.com/FullStackWithLawrence/aws-openai/commit/a2daf8a58be94cbd6769c1ba7dedab5e18ef3fc1))
19+
- force a new release ([a069aae](https://github.com/FullStackWithLawrence/aws-openai/commit/a069aae8d6d0959cbc74334f0ebdf0105d55c3a8))
20+
- force a new release ([a2daf8a](https://github.com/FullStackWithLawrence/aws-openai/commit/a2daf8a58be94cbd6769c1ba7dedab5e18ef3fc1))
2421

2522
## [0.9.0](https://github.com/FullStackWithLawrence/aws-openai/compare/v0.8.2...v0.9.0) (2023-12-30)
2623

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ PIP := $(PYTHON) -m pip
1414
ifneq ("$(wildcard .env)","")
1515
include .env
1616
else
17-
$(shell echo -e "OPENAI_API_ORGANIZATION=PLEASE-ADD-ME\nOPENAI_API_KEY=PLEASE-ADD-ME\nPINECONE_API_KEY=PLEASE-ADD-ME\nPINECONE_ENVIRONMENT=gcp-starter\nDEBUG_MODE=True\n" >> .env)
17+
$(shell echo -e "OPENAI_API_ORGANIZATION=PLEASE-ADD-ME\nOPENAI_API_KEY=PLEASE-ADD-ME\nPINECONE_API_KEY=PLEASE-ADD-ME\nPINECONE_ENVIRONMENT=gcp-starter\nGOOGLE_MAPS_API_KEY=PLEASE-ADD-ME\nDEBUG_MODE=True\n" >> .env)
1818
endif
1919

2020
.PHONY: analyze pre-commit api-init api-activate api-lint api-clean api-test client-init client-lint client-update client-run client-build client-release

api/postman/OpenAI.postman_collection.json

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101
],
102102
"body": {
103103
"mode": "raw",
104-
"raw": "{\n \"model\": \"gpt-3.5-turbo\",\n \"end_point\": \"ChatCompletion\",\n \"temperature\": 0.5,\n \"max_tokens\": 256,\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"You are Marv, a chatbot that reluctantly answers questions with sarcastic responses.\"\n },\n {\n \"role\": \"user\",\n \"content\": \"Marv, I'd like to introduce you to all the nice YouTube viewers.\"\n }\n ],\n \"chat_history\": [\n {\n \"message\": \"Hello, I'm Marv, a sarcastic chatbot.\",\n \"direction\": \"incoming\",\n \"sentTime\": \"11/16/2023, 5:53:32 PM\",\n \"sender\": \"system\"\n }\n ]\n}",
104+
"raw": "{\n \"model\": \"gpt-3.5-turbo\",\n \"end_point\": \"ChatCompletion\",\n \"temperature\": 0.5,\n \"max_tokens\": 256,\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"You are a helpful chatbot\"\n },\n {\n \"role\": \"user\",\n \"content\": \"Should i use AWS Lambda to implement my OpenAI API microservice?\"\n }\n ],\n \"chat_history\": [\n {\n \"message\": \"Hello, How can I help you?\",\n \"direction\": \"incoming\",\n \"sentTime\": \"11/16/2023, 5:53:32 PM\",\n \"sender\": \"system\"\n }\n ]\n}",
105105
"options": {
106106
"raw": {
107107
"language": "json"
@@ -116,6 +116,34 @@
116116
},
117117
"response": []
118118
},
119+
{
120+
"name": "openai_function_passthrough",
121+
"request": {
122+
"method": "POST",
123+
"header": [
124+
{
125+
"key": "x-api-key",
126+
"value": "{{api_key}}",
127+
"type": "text"
128+
}
129+
],
130+
"body": {
131+
"mode": "raw",
132+
"raw": "{\n \"model\": \"gpt-3.5-turbo\",\n \"end_point\": \"ChatCompletion\",\n \"temperature\": 0.5,\n \"max_tokens\": 256,\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"You are a helpful chatbot\"\n },\n {\n \"role\": \"user\",\n \"content\": \"does lawrence mcdaniel teach at UBC?\"\n }\n ],\n \"chat_history\": [\n {\n \"message\": \"Hello, How can I help you?\",\n \"direction\": \"incoming\",\n \"sentTime\": \"11/16/2023, 5:53:32 PM\",\n \"sender\": \"system\"\n }\n ]\n}",
133+
"options": {
134+
"raw": {
135+
"language": "json"
136+
}
137+
}
138+
},
139+
"url": {
140+
"raw": "{{base_url}}/openai_function_passthrough",
141+
"host": ["{{base_url}}"],
142+
"path": ["openai_function_passthrough"]
143+
}
144+
},
145+
"response": []
146+
},
119147
{
120148
"name": "langchain-passthrough",
121149
"request": {
@@ -1371,6 +1399,118 @@
13711399
}
13721400
},
13731401
"response": []
1402+
},
1403+
{
1404+
"name": "example-31-openai-function-calling",
1405+
"event": [
1406+
{
1407+
"listen": "prerequest",
1408+
"script": {
1409+
"exec": [""],
1410+
"type": "text/javascript"
1411+
}
1412+
}
1413+
],
1414+
"request": {
1415+
"method": "POST",
1416+
"header": [
1417+
{
1418+
"key": "x-api-key",
1419+
"value": "{{api_key}}",
1420+
"type": "text"
1421+
}
1422+
],
1423+
"body": {
1424+
"mode": "raw",
1425+
"raw": "{\n \"input_text\": \"Marv, I'd like to introduce you to all the nice YouTube viewers.\",\n \"chat_history\": []\n}",
1426+
"options": {
1427+
"raw": {
1428+
"language": "json"
1429+
}
1430+
}
1431+
},
1432+
"url": {
1433+
"raw": "{{base_url}}/examples/default-marv-sarcastic-chat",
1434+
"host": ["{{base_url}}"],
1435+
"path": ["examples", "default-marv-sarcastic-chat"]
1436+
}
1437+
},
1438+
"response": [
1439+
{
1440+
"name": "example-15-marv-sarcastic-chat",
1441+
"originalRequest": {
1442+
"method": "POST",
1443+
"header": [
1444+
{
1445+
"key": "x-api-key",
1446+
"value": "{{api_key}}",
1447+
"type": "text"
1448+
}
1449+
],
1450+
"body": {
1451+
"mode": "raw",
1452+
"raw": "{\n \"input_text\": \"Marv, I'd like to introduce you to all the nice YouTube viewers.\",\n \"chat_history\": []\n}",
1453+
"options": {
1454+
"raw": {
1455+
"language": "json"
1456+
}
1457+
}
1458+
},
1459+
"url": {
1460+
"raw": "{{base_url}}/examples/default-marv-sarcastic-chat",
1461+
"host": ["{{base_url}}"],
1462+
"path": ["examples", "default-marv-sarcastic-chat"]
1463+
}
1464+
},
1465+
"status": "OK",
1466+
"code": 200,
1467+
"_postman_previewlanguage": "json",
1468+
"header": [
1469+
{
1470+
"key": "Date",
1471+
"value": "Mon, 27 Nov 2023 19:18:12 GMT"
1472+
},
1473+
{
1474+
"key": "Content-Type",
1475+
"value": "application/json"
1476+
},
1477+
{
1478+
"key": "Content-Length",
1479+
"value": "857"
1480+
},
1481+
{
1482+
"key": "Connection",
1483+
"value": "keep-alive"
1484+
},
1485+
{
1486+
"key": "x-amzn-RequestId",
1487+
"value": "efbf23b1-64a4-4785-afe4-d32ce5efa31c"
1488+
},
1489+
{
1490+
"key": "Access-Control-Allow-Origin",
1491+
"value": "*"
1492+
},
1493+
{
1494+
"key": "Access-Control-Allow-Headers",
1495+
"value": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token"
1496+
},
1497+
{
1498+
"key": "x-amz-apigw-id",
1499+
"value": "PEm4-GgpoAMEszQ="
1500+
},
1501+
{
1502+
"key": "Access-Control-Allow-Methods",
1503+
"value": "GET,OPTIONS,POST,PUT"
1504+
},
1505+
{
1506+
"key": "X-Amzn-Trace-Id",
1507+
"value": "Root=1-6564eb6c-17069edf0733242230aed60b;Sampled=0;lineage=dcadcbad:0"
1508+
}
1509+
],
1510+
"cookie": [],
1511+
"body": "{\n \"isBase64Encoded\": false,\n \"statusCode\": 200,\n \"body\": {\n \"chat_memory\": {\n \"messages\": [\n {\n \"content\": \"Marv, I'd like to introduce you to all the nice YouTube viewers.\",\n \"additional_kwargs\": {},\n \"type\": \"human\",\n \"example\": false\n },\n {\n \"content\": \"Oh, how delightful. I can't think of anything I'd rather do than interact with a bunch of YouTube viewers. Just kidding, I'd rather be doing literally anything else. But go ahead, introduce me to your lovely audience. I'm sure they'll be absolutely thrilled to meet me.\",\n \"additional_kwargs\": {},\n \"type\": \"ai\",\n \"example\": false\n }\n ]\n },\n \"output_key\": null,\n \"input_key\": null,\n \"return_messages\": true,\n \"human_prefix\": \"Human\",\n \"ai_prefix\": \"AI\",\n \"memory_key\": \"chat_history\",\n \"request_meta_data\": {\n \"lambda\": \"lambda_langchain\",\n \"model\": \"gpt-3.5-turbo\",\n \"end_point\": \"ChatCompletion\",\n \"temperature\": 0.5,\n \"max_tokens\": 256\n }\n }\n}"
1512+
}
1513+
]
13741514
}
13751515
]
13761516
}

api/terraform/lambda_layer_pandas.tf

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#------------------------------------------------------------------------------
2+
# written by: Lawrence McDaniel
3+
# https://lawrencemcdaniel.com/
4+
#
5+
# date: sep-2023
6+
#
7+
# usage: implement a Python Lambda layer containing Pandas and NumPy.
8+
#------------------------------------------------------------------------------
9+
locals {
10+
pandas_layer_slug = "pandas"
11+
pandas_layer_name = "layer_${local.pandas_layer_slug}"
12+
pandas_layer_parent_directory = "${path.module}/python"
13+
pandas_layer_source_directory = "${local.pandas_layer_parent_directory}/${local.pandas_layer_name}"
14+
pandas_layer_packaging_script = "${local.pandas_layer_source_directory}/create_container.sh"
15+
pandas_layer_package_folder = local.pandas_layer_slug
16+
pandas_layer_dist_build_path = "${path.module}/build/"
17+
pandas_layer_dist_package_name = "${local.pandas_layer_name}_dst.zip"
18+
}
19+
20+
###############################################################################
21+
# Python package
22+
# https://alek-cora-glez.medium.com/deploying-aws-lambda-function-with-terraform-custom-dependencies-7874407cd4fc
23+
###############################################################################
24+
resource "null_resource" "package_pandas_layer" {
25+
triggers = {
26+
redeployment = sha1(jsonencode([
27+
"${path.module}/lambda_layer.tf",
28+
file("${local.pandas_layer_packaging_script}"),
29+
file("${local.pandas_layer_source_directory}/Dockerfile"),
30+
file("${local.pandas_layer_source_directory}/create_container.sh"),
31+
file("${local.pandas_layer_source_directory}/requirements.txt"),
32+
fileexists("${local.pandas_layer_source_directory}/${local.pandas_layer_dist_package_name}") ? filebase64("${local.pandas_layer_source_directory}/${local.pandas_layer_dist_package_name}") : "default"
33+
]))
34+
}
35+
36+
provisioner "local-exec" {
37+
interpreter = ["/bin/bash"]
38+
command = local.pandas_layer_packaging_script
39+
40+
environment = {
41+
SOURCE_CODE_PATH = local.pandas_layer_source_directory
42+
RUNTIME = var.lambda_python_runtime
43+
CONTAINER_NAME = local.pandas_layer_name
44+
PACKAGE_NAME = local.pandas_layer_dist_package_name
45+
}
46+
}
47+
}
48+
49+
resource "aws_lambda_layer_version" "pandas" {
50+
filename = "${local.pandas_layer_source_directory}/${local.pandas_layer_dist_package_name}"
51+
source_code_hash = fileexists("${local.pandas_layer_source_directory}/${local.pandas_layer_dist_package_name}") ? filebase64sha256("${local.pandas_layer_source_directory}/${local.pandas_layer_dist_package_name}") : null
52+
layer_name = local.pandas_layer_slug
53+
compatible_architectures = var.compatible_architectures
54+
compatible_runtimes = [var.lambda_python_runtime]
55+
lifecycle {
56+
create_before_destroy = true
57+
}
58+
depends_on = [
59+
null_resource.package_pandas_layer
60+
]
61+
}

api/terraform/lambda_openai_function.tf

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,17 @@ resource "aws_lambda_function" "lambda_openai_function" {
7979
architectures = var.compatible_architectures
8080
filename = data.archive_file.lambda_openai_function.output_path
8181
source_code_hash = data.archive_file.lambda_openai_function.output_base64sha256
82-
layers = [aws_lambda_layer_version.openai.arn, aws_lambda_layer_version.nlp.arn]
83-
tags = var.tags
82+
layers = [
83+
aws_lambda_layer_version.openai.arn,
84+
aws_lambda_layer_version.nlp.arn,
85+
aws_lambda_layer_version.pandas.arn
86+
]
87+
tags = var.tags
8488

8589
environment {
8690
variables = {
8791
DEBUG_MODE = var.debug_mode
92+
GOOGLE_MAPS_API_KEY = data.external.env_lambda_openai_function.result["GOOGLE_MAPS_API_KEY"]
8893
OPENAI_API_ORGANIZATION = data.external.env_lambda_openai_function.result["OPENAI_API_ORGANIZATION"]
8994
OPENAI_API_KEY = data.external.env_lambda_openai_function.result["OPENAI_API_KEY"]
9095
OPENAI_ENDPOINT_IMAGE_N = var.openai_endpoint_image_n
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# AWS Lambda Layer for OpenAI/Langchain Lambdas
22

3-
This layer contains the combined pip requirements for Natural Language Processing features.
3+
This layer contains the combined pip requirements for Natural Language Processing and OpenAI API Function Calling features.

api/terraform/python/layer_nlp/requirements.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@
1212
# --------------------------
1313
python-Levenshtein==0.23.0
1414
pyyaml
15+
16+
# weather function
17+
googlemaps
18+
openmeteo-requests
19+
requests-cache
20+
retry-requests
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.zip
2+
venv
3+
archive
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Use an AWS Lambda Python runtime as the base image
2+
# https://hub.docker.com/r/amazon/aws-lambda-python
3+
# ------------------------------------------------------
4+
5+
# Stage 1: Build dependencies for x86_64
6+
FROM --platform=linux/amd64 public.ecr.aws/lambda/python:3.11
7+
8+
WORKDIR /var/task
9+
10+
COPY requirements.txt .
11+
12+
RUN yum install -y zip
13+
RUN pip install -r requirements.txt --target python/lib/python3.11/site-packages
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# AWS Lambda Layer for OpenAI/Langchain Lambdas
2+
3+
This layer contains Pandas and NumPy.

0 commit comments

Comments
 (0)