-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added sentence splitter and properly deployed
- Loading branch information
Showing
16 changed files
with
1,256 additions
and
49 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
# private key for JWT authentication | ||
JWT_PRIVATE_KEY= | ||
# use this if you are in China and need to lock in vendor to AWS | ||
SERVERLESS_PLATFORM_VENDOR=aws | ||
|
||
# private key for JWT authentication (see scripts/create_jwt.py to create a new private key) | ||
JWT_SIGNING_KEY= | ||
|
||
# API key for OpenAI | ||
OPENAI_API_KEY= |
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 |
---|---|---|
@@ -1,4 +1,8 @@ | ||
.vscode | ||
node_modules | ||
__pycache__ | ||
|
||
.serverless | ||
.requirements.zip | ||
|
||
.env* |
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,54 @@ | ||
# OpenAI Serverless | ||
|
||
A Stack for managing OpenAI API access using Serverless Framework against AWS. | ||
|
||
## Prerequisites | ||
|
||
- NodeJS LTS | ||
- yarn | ||
- pyenv | ||
- Poetry | ||
- make | ||
|
||
## Install | ||
|
||
``` | ||
yarn | ||
poetry install | ||
``` | ||
|
||
## Env Vars | ||
|
||
Please check `.env.example`. Copy to `.env` and add the OpenAI API Key. | ||
|
||
Run `make create-jwt` to create the JWK for signing. Put that in to `.env`. | ||
|
||
Run `make sign-jwt user="<username>"` to get a signed JWT for requests. | ||
|
||
## How to run locally | ||
|
||
``` | ||
make local args="--stage dev" | ||
``` | ||
|
||
## How to deploy | ||
|
||
First make sure we have the right AWS profile set up, it is best to inject keys via `AWS_PROFILE` env var. (Put into `.env` is fine). | ||
|
||
``` | ||
make deploy | ||
``` | ||
|
||
## How to make requests | ||
|
||
For example, with `/split_sentences`: | ||
|
||
``` | ||
curl --request POST \ | ||
--url http://localhost:3000/dev/split_sentences \ | ||
--header 'Authorization: jwt <jwt_token>' \ | ||
--header 'Content-Type: application/json' \ | ||
--data '{ | ||
"sentence": "This is a sentence splitter that can split sentences into its own line. Please feel free to try it out!" | ||
}' | ||
``` |
Empty file.
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,58 @@ | ||
try: | ||
import unzip_requirements | ||
except ImportError: | ||
pass | ||
|
||
import os | ||
import json | ||
from typing import Any, Dict | ||
from dotenv import dotenv_values | ||
from jwcrypto import jwk, jwt | ||
from aws_lambda_powertools.utilities.typing import LambdaContext | ||
|
||
config = { | ||
**dotenv_values(os.path.join(os.path.dirname(__file__), '..', '.env')), | ||
**os.environ, | ||
} | ||
|
||
signing_key = jwk.JWK.from_json(config.get('JWT_SIGNING_KEY')) | ||
|
||
def generatePolicy(principalId, effect, methodArn): | ||
authResponse = {} | ||
authResponse['principalId'] = principalId | ||
|
||
if effect and methodArn: | ||
policyDocument = { | ||
'Version': '2012-10-17', | ||
'Statement': [ | ||
{ | ||
'Sid': 'FirstStatement', | ||
'Action': 'execute-api:Invoke', | ||
'Effect': effect, | ||
'Resource': methodArn | ||
} | ||
] | ||
} | ||
|
||
authResponse['policyDocument'] = policyDocument | ||
|
||
return authResponse | ||
|
||
def handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Any]: | ||
try: | ||
# test the JWT | ||
token = str(event['authorizationToken']).replace('jwt ', '') | ||
print('jwt token', token) | ||
decrypted = jwt.JWT(key=signing_key, jwt=token) | ||
print('jwt claims', decrypted.claims) | ||
|
||
# Get principalId from idInformation | ||
principalId = json.loads(decrypted.claims).get('uid') | ||
except: | ||
# Deny access if the token is invalid | ||
return generatePolicy(None, 'Deny', event['methodArn']) | ||
|
||
return generatePolicy(principalId, 'Allow', event['methodArn']) | ||
|
||
if __name__ == '__main__': | ||
print(signing_key.export_public()) |
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 |
---|---|---|
@@ -1,10 +1,93 @@ | ||
try: | ||
import unzip_requirements | ||
except ImportError: | ||
pass | ||
|
||
import os | ||
import json | ||
from typing import Any, Dict | ||
from dotenv import dotenv_values | ||
from aws_lambda_powertools.utilities.typing import LambdaContext | ||
import openai | ||
|
||
config = { | ||
**dotenv_values(os.path.join(os.path.dirname(__file__), '..', '.env')), | ||
**os.environ, | ||
} | ||
|
||
openai.api_key = config.get('OPENAI_API_KEY') | ||
|
||
def handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Any]: | ||
try: | ||
body = event.get('body') | ||
|
||
if body is None: | ||
return { | ||
'statusCode': 400, | ||
'body': json.dumps({ 'message': 'please provide POST body' }), | ||
'headers': { | ||
'Content-Type': 'application/json', | ||
}, | ||
} | ||
|
||
sentence = json.loads(body).get('sentence') | ||
|
||
if sentence is None: | ||
return { | ||
'statusCode': 400, | ||
'body': json.dumps({ 'message': 'please provide sentence in body JSON' }), | ||
'headers': { | ||
'Content-Type': 'application/json', | ||
}, | ||
} | ||
|
||
prompt = f'''Split the message into individual sentences. Put each sentence into its own line. Keep the original punctuations as much as possible. | ||
#### | ||
Message: | ||
Hi, my name is Simon. I am working on a sentence splitter powered by OpenAI | ||
Sentences: | ||
Hi, my name is Simon. | ||
I am working on a sentence splitter powered by OpenAI | ||
#### | ||
Message: | ||
{sentence} | ||
Sentences:''' | ||
response = openai.Completion.create( | ||
engine='curie-instruct-beta', | ||
prompt=prompt, | ||
max_tokens=256, | ||
temperature=0.3, | ||
stop=['####'], | ||
) | ||
|
||
sentences = response.get('choices', {})[0].get('text') | ||
|
||
if sentences is None: | ||
return { | ||
'statusCode': 400, | ||
'body': json.dumps({ 'message': 'no sentences produced' }), | ||
'headers': { | ||
'Content-Type': 'application/json', | ||
}, | ||
} | ||
|
||
sentences = list(filter(lambda s: s.strip(), str(sentences).split('\n'))) | ||
|
||
return { | ||
'statusCode': 200, | ||
'body': json.dumps({ 'sentences': sentences }), | ||
'headers': { | ||
'Content-Type': 'application/json', | ||
}, | ||
} | ||
except Exception as e: | ||
return { | ||
'statusCode': 400, | ||
'body': json.dumps({ 'message': 'error occurred, please check logs' }), | ||
'headers': { | ||
'Content-Type': 'application/json', | ||
}, | ||
} | ||
|
||
if __name__ == '__main__': | ||
print(config) |
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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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,5 @@ | ||
authorizer_function: | ||
runtime: python3.8 | ||
handler: functions/authorizer.handler | ||
environment: | ||
JWT_SIGNING_KEY: ${env:JWT_SIGNING_KEY} |
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 |
---|---|---|
@@ -1,11 +1,16 @@ | ||
importer: | ||
split_sentences: | ||
runtime: python3.8 | ||
handler: split_sentences.handler | ||
module: functions | ||
handler: functions/split_sentences.handler | ||
events: | ||
- http: | ||
path: split_sentences | ||
method: post | ||
cors: true | ||
authorizer: | ||
name: authorizer_function | ||
resultTtlInSeconds: 0 | ||
identitySource: method.request.header.Authorization | ||
identityValidationExpression: jwt .+ | ||
type: token | ||
environment: | ||
OPENAI_API_KEY: ${env:OPENAI_API_KEY} |
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 |
---|---|---|
@@ -1,6 +1,6 @@ | ||
from jwcrypto import jwk | ||
|
||
key = jwk.JWK.generate(kty='RSA', size=2048) | ||
key = jwk.JWK.generate(kty='oct', size=256) | ||
|
||
print(key.export(private_key=True)) | ||
print(key.export(private_key=False)) | ||
print('Signing Key:') | ||
print(key.export()) |
Oops, something went wrong.