├── openai_proxy ├── utils │ ├── __init__.py │ ├── auth.py │ ├── constants │ │ └── __init__.py │ └── token_estimator.py ├── __init__.py ├── price.py ├── embeddings.py ├── chat_completion.py ├── image.py ├── completion.py └── sample.ipynb ├── requirements.txt ├── .gitignore ├── setup.py └── README.md /openai_proxy/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | setuptools~=65.4.1 2 | requests~=2.27.1 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .idea 3 | build/ 4 | dist/ 5 | openai_proxy.egg-info 6 | *.pyc 7 | sample.py -------------------------------------------------------------------------------- /openai_proxy/utils/auth.py: -------------------------------------------------------------------------------- 1 | import openai_proxy 2 | 3 | from enum import Enum 4 | 5 | 6 | # def an enum with a public, private and error field 7 | class AuthStatus(str, Enum): 8 | PUBLIC = "PUBLIC" 9 | PRIVATE = "PRIVATE" 10 | ERROR = "ERROR" 11 | 12 | 13 | def authenticate(): 14 | # TODO: Authorize public users 15 | if openai_proxy.api_key is not None and openai_proxy.api_key != "": 16 | return AuthStatus.PUBLIC 17 | if openai_proxy.username is not None and openai_proxy.username != "" \ 18 | and openai_proxy.course_id is not None and openai_proxy.course_id != "" \ 19 | and openai_proxy.access_key is not None and openai_proxy.access_key != "" \ 20 | and openai_proxy.access_token is not None and openai_proxy.access_token != "": 21 | return AuthStatus.PRIVATE 22 | return AuthStatus.ERROR 23 | -------------------------------------------------------------------------------- /openai_proxy/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import requests 4 | 5 | from openai_proxy.completion import Completion 6 | from openai_proxy.embeddings import Embedding 7 | from openai_proxy.chat_completion import ChatCompletion 8 | from openai_proxy.image import Image 9 | from openai_proxy.price import Price 10 | 11 | 12 | api_key = os.environ.get("OPENAI_API_KEY") 13 | access_key = os.environ.get("OPENAI_PROXY_ACCESS_KEY") 14 | access_token = os.environ.get("OPENAI_PROXY_ACCESS_TOKEN") 15 | 16 | username = os.environ.get("OPENAI_PROXY_USERNAME") 17 | course_id = os.environ.get("OPENAI_PROXY_COURSE_ID") 18 | 19 | session_price = 0 20 | 21 | # r = requests.get('http://openai-proxy.herokuapp.com/b/request/engines') 22 | # response = json.loads(r.text) 23 | # 24 | # engines = [engine for engine in response if engine is not None] 25 | 26 | __all__ = [ 27 | "api_key", 28 | "access_key", 29 | "access_token", 30 | "username", 31 | "course_id", 32 | # "engines", 33 | "Completion", 34 | "Embedding", 35 | "ChatCompletion", 36 | "Image", 37 | "Price", 38 | "session_price" 39 | ] -------------------------------------------------------------------------------- /openai_proxy/price.py: -------------------------------------------------------------------------------- 1 | from openai_proxy.utils import token_estimator 2 | 3 | 4 | class Price: 5 | def __init__(self): 6 | pass 7 | 8 | @staticmethod 9 | def from_response(response): 10 | if "model" not in response: 11 | # TODO: Image price cannot be estimated from response object 12 | return 0.02 * len(response["data"]) 13 | 14 | model = response["model"] 15 | 16 | if "gpt" in model: 17 | # TODO: Support specific model names from response eg gpt-3.5-turbo-0301 18 | return token_estimator.price_calculator_chat_completion(response["usage"]) 19 | elif "text-embedding" in model: 20 | return token_estimator.price_calculator_embedding_completion(response["usage"]) 21 | else: 22 | return token_estimator.price_calculator_completion({ 23 | "engine": model, 24 | "total_tokens": response["usage"]["total_tokens"], 25 | }) 26 | 27 | 28 | @staticmethod 29 | def from_list_response(responses): 30 | cost = 0 31 | for response in responses: 32 | cost += Price.from_response(response) 33 | return cost 34 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | VERSION = '0.2.5' 4 | DESCRIPTION = 'A price proxy for the OpenAI API' 5 | LONG_DESCRIPTION = 'This proxy enables better budgeting and cost management for making OpenAI API calls ' \ 6 | 'including more transparency into pricing. Github repo here: ' \ 7 | 'https://github.com/tomiwa123/openai-proxy-python' 8 | 9 | # Setting up 10 | setup( 11 | # the name must match the folder name 'openai_proxy' 12 | name="openai_proxy", 13 | version=VERSION, 14 | author="Ayotomiwa Akinyele", 15 | author_email="", 16 | description=DESCRIPTION, 17 | long_description=LONG_DESCRIPTION, 18 | packages=find_packages(), 19 | install_requires=['openai', 'tiktoken'], # add any additional packages that 20 | # needs to be installed along with your package. Eg: 'caer' 21 | 22 | keywords=['python', 'openai', 'proxy', 'api', 'wrapper'], 23 | classifiers=[ 24 | "Development Status :: 3 - Alpha", 25 | "Intended Audience :: Education", 26 | "Programming Language :: Python :: 2", 27 | "Programming Language :: Python :: 3", 28 | "Operating System :: MacOS :: MacOS X", 29 | "Operating System :: Microsoft :: Windows", 30 | ] 31 | ) -------------------------------------------------------------------------------- /openai_proxy/embeddings.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | 4 | import openai 5 | import openai_proxy 6 | from openai_proxy.utils import token_estimator, auth 7 | 8 | 9 | class Embedding: 10 | @staticmethod 11 | def create(phrases=[]): 12 | authentication = auth.authenticate() 13 | if authentication == auth.AuthStatus.ERROR: 14 | return "Please set your username, courseId, accessKey, and accessToken or just your OpenAI API key" 15 | 16 | if authentication == auth.AuthStatus.PUBLIC: 17 | openai.api_key = openai_proxy.api_key 18 | response = openai.Embedding.create(input=phrases, model="text-embedding-ada-002") 19 | response["price"] = token_estimator.price_calculator_embedding(phrases) 20 | openai_proxy.session_price += response["price"] 21 | return response 22 | 23 | body = { 24 | "username": openai_proxy.username, 25 | "courseId": openai_proxy.course_id, 26 | "accessKey": openai_proxy.access_key, 27 | "accessToken": openai_proxy.access_token, 28 | "phrases": phrases, 29 | } 30 | r = requests.post('http://openai-proxy.herokuapp.com/b/request/openai/embedding', json=body) 31 | response = json.loads(r.text) 32 | if response['status'] == 'success': 33 | openai_proxy.session_price += response['response']["price"] 34 | return response['response'] 35 | else: 36 | return response 37 | 38 | @staticmethod 39 | def price(phrases=[]): 40 | 41 | return { 42 | "status": "success", 43 | "price": token_estimator.price_calculator_embedding(phrases) 44 | } 45 | -------------------------------------------------------------------------------- /openai_proxy/chat_completion.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | import openai 4 | 5 | import openai_proxy 6 | from openai_proxy.utils import token_estimator, auth 7 | 8 | 9 | class ChatCompletion: 10 | @staticmethod 11 | def create(messages=[], model="gpt-3.5-turbo", n=1): 12 | authentication = auth.authenticate() 13 | if authentication == auth.AuthStatus.ERROR: 14 | return "Please set your username, courseId, accessKey, and accessToken or just your OpenAI API key" 15 | 16 | if authentication == auth.AuthStatus.PUBLIC: 17 | openai.api_key = openai_proxy.api_key 18 | response = openai.ChatCompletion.create( 19 | model=model, 20 | messages=messages, 21 | n=n 22 | ) 23 | response["price"] = token_estimator.price_calculator_chat_completion(response["usage"], model=model) 24 | openai_proxy.session_price += response["price"] 25 | return response 26 | 27 | body = { 28 | "username": openai_proxy.username, 29 | "courseId": openai_proxy.course_id, 30 | "accessKey": openai_proxy.access_key, 31 | "accessToken": openai_proxy.access_token, 32 | "model": model, 33 | "messages": messages, 34 | "n": n 35 | } 36 | r = requests.post('http://openai-proxy.herokuapp.com/b/request/openai/chat', json=body) 37 | response = json.loads(r.text) 38 | if response['status'] == 'success': 39 | openai_proxy.session_price += response['response']["price"] 40 | return response['response'] 41 | else: 42 | return response 43 | 44 | @staticmethod 45 | def price(messages=[], model="gpt-3.5-turbo", n=1): 46 | return { 47 | "status": "success", 48 | "price": token_estimator.price_calculator_chat(messages, model, n) 49 | } 50 | -------------------------------------------------------------------------------- /openai_proxy/image.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | 4 | import openai 5 | import openai_proxy 6 | from openai_proxy.utils import token_estimator, auth 7 | 8 | 9 | class Image: 10 | @staticmethod 11 | def create(prompt, 12 | n=1, 13 | size="1024x1024" 14 | ): 15 | authentication = auth.authenticate() 16 | if authentication == auth.AuthStatus.ERROR: 17 | return "Please set your username, courseId, accessKey, and accessToken or just your OpenAI API key" 18 | 19 | params = { 20 | "prompt": prompt, 21 | "n": n, 22 | "size": size 23 | } 24 | 25 | if authentication == auth.AuthStatus.PUBLIC: 26 | openai.api_key = openai_proxy.api_key 27 | response = openai.Image.create(**params) 28 | response["price"] = token_estimator.price_calculator_image(params) 29 | openai_proxy.session_price += response["price"] 30 | return response 31 | 32 | params["username"] = openai_proxy.username 33 | params["courseId"] = openai_proxy.course_id 34 | params["accessKey"] = openai_proxy.access_key 35 | params["accessToken"] = openai_proxy.access_token 36 | r = requests.post('http://openai-proxy.herokuapp.com/b/request/openai/image', json=params) 37 | response = json.loads(r.text) 38 | if response['status'] == 'success': 39 | openai_proxy.session_price += response['response']["price"] 40 | return response['response'] 41 | else: 42 | return response 43 | 44 | @staticmethod 45 | def price(prompt, 46 | n=1, 47 | size="1024x1024" 48 | ): 49 | 50 | body = { 51 | "prompt": prompt, 52 | "n": n, 53 | "size": size 54 | } 55 | 56 | return { 57 | "status": "success", 58 | "price": token_estimator.price_calculator_image(body) 59 | } 60 | -------------------------------------------------------------------------------- /openai_proxy/completion.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | 4 | import openai 5 | import openai_proxy 6 | from openai_proxy.utils import token_estimator, auth 7 | 8 | 9 | class Completion: 10 | @staticmethod 11 | def create(prompt, 12 | engine="babbage", 13 | temperature=0.7, 14 | max_tokens=200, 15 | top_p=1, 16 | frequency_penalty=0, 17 | presence_penalty=0, 18 | stop='', 19 | n=1 20 | ): 21 | authentication = auth.authenticate() 22 | if authentication == auth.AuthStatus.ERROR: 23 | return "Please set your username, courseId, accessKey, and accessToken or just your OpenAI API key" 24 | 25 | params = { 26 | "prompt": prompt, 27 | "max_tokens": max_tokens, 28 | "engine": engine, 29 | "temperature": temperature, 30 | "top_p": top_p, 31 | "frequency_penalty": frequency_penalty, 32 | "presence_penalty": presence_penalty, 33 | "stop": stop, 34 | "n": n 35 | } 36 | 37 | if authentication == auth.AuthStatus.PUBLIC: 38 | openai.api_key = openai_proxy.api_key 39 | response = openai.Completion.create(**params) 40 | response["price"] = token_estimator.price_calculator_completion({ 41 | "total_tokens": response["usage"]["total_tokens"], 42 | "engine": response["model"] 43 | }) 44 | openai_proxy.session_price += response["price"] 45 | return response 46 | 47 | params["username"] = openai_proxy.username 48 | params["courseId"] = openai_proxy.course_id 49 | params["accessKey"] = openai_proxy.access_key 50 | params["accessToken"] = openai_proxy.access_token 51 | r = requests.post('http://openai-proxy.herokuapp.com/b/request/openai/completion', json=params) 52 | response = json.loads(r.text) 53 | if response['status'] == 'success': 54 | openai_proxy.session_price += response['response']["price"] 55 | return response['response'] 56 | else: 57 | return response 58 | 59 | @staticmethod 60 | def price(prompt, 61 | engine="babbage", 62 | max_tokens=200, 63 | n=1 64 | ): 65 | 66 | body = { 67 | "prompt": prompt, 68 | "max_tokens": max_tokens, 69 | "engine": engine, 70 | "n": n 71 | } 72 | 73 | return { 74 | "status": "success", 75 | "price": token_estimator.price_calculator_completion(body) 76 | } 77 | -------------------------------------------------------------------------------- /openai_proxy/utils/constants/__init__.py: -------------------------------------------------------------------------------- 1 | price_per_token = { 2 | 'text-ada-001': 0.0004 / 1000, 3 | 'text-babbage-001': 0.0005 / 1000, 4 | 'text-curie-001': 0.002 / 1000, 5 | 'text-davinci-003': 0.02 / 1000, 6 | 'ada-finetuned': 0.0016 / 1000, 7 | 'babbage-finetuned': 0.0024 / 1000, 8 | 'curie-finetuned': 0.0120 / 1000, 9 | 'davinci-finetuned': 0.1200 / 1000, 10 | 'ada-finetuned-training': 0.0004 / 1000, 11 | 'babbage-finetuned-training': 0.0006 / 1000, 12 | 'curie-finetuned-training': 0.0030 / 1000, 13 | 'davinci-finetuned-training': 0.0300 / 1000, 14 | 'text-embedding-ada-002': 0.0004 / 1000, 15 | '1024x1024': 0.02, 16 | '512x512': 0.018, 17 | '256x256': 0.016, 18 | 'gpt-3.5-turbo-prompt': 0.002 / 1000, 19 | 'gpt-3.5-turbo-completion': 0.002 / 1000, 20 | 'gpt-4-prompt': 0.03 / 1000, # default 8k model 21 | 'gpt-4-completion': 0.06 / 1000, # default 8k model 22 | } 23 | 24 | 25 | def get_price_per_token(engine): 26 | if engine in price_per_token: 27 | return price_per_token[engine] 28 | else: 29 | if 'ada' in engine: 30 | return price_per_token['ada-finetuned'] 31 | elif 'babbage' in engine: 32 | return price_per_token['babbage-finetuned'] 33 | elif 'curie' in engine: 34 | return price_per_token['curie-finetuned'] 35 | elif 'davinci' in engine: 36 | return price_per_token['davinci-finetuned'] 37 | else: 38 | return 0.1200 / 1000 39 | 40 | 41 | engine_max_tokens = { 42 | 'text-ada-001': 2048, 43 | 'text-babbage-001': 2048, 44 | 'text-curie-001': 2048, 45 | 'text-davinci-003': 4000, 46 | 'ada-finetuned': 2048, 47 | 'babbage-finetuned': 2048, 48 | 'curie-finetuned': 2048, 49 | 'davinci-finetuned': 4000, 50 | 'ada-finetuned-training': 2048, 51 | 'babbage-finetuned-training': 2048, 52 | 'curie-finetuned-training': 2048, 53 | 'davinci-finetuned-training': 4000, 54 | 'text-embedding-ada-002': 2048, 55 | 'gpt-3.5-turbo': 4096, 56 | 'gpt-4': 8192, 57 | } 58 | 59 | 60 | def get_engine_max_tokens(engine): 61 | if engine in engine_max_tokens: 62 | return engine_max_tokens[engine] 63 | else: 64 | if 'ada' in engine: 65 | return engine_max_tokens['ada-finetuned'] 66 | elif 'babbage' in engine: 67 | return engine_max_tokens['babbage-finetuned'] 68 | elif 'curie' in engine: 69 | return engine_max_tokens['curie-finetuned'] 70 | elif 'davinci' in engine: 71 | return engine_max_tokens['davinci-finetuned'] 72 | else: 73 | return 2048 74 | 75 | 76 | __all__ = [ 77 | "price_per_token", 78 | "get_price_per_token", 79 | "engine_max_tokens", 80 | "get_engine_max_tokens", 81 | ] 82 | -------------------------------------------------------------------------------- /openai_proxy/utils/token_estimator.py: -------------------------------------------------------------------------------- 1 | import tiktoken 2 | from openai_proxy.utils.constants import get_price_per_token, get_engine_max_tokens 3 | 4 | 5 | def token_counter(prompt, model): 6 | # TODO: Does not properly support key "name" in chat models 7 | # counts tokens given input text 8 | # 9 | # input: text 10 | # output: length of tokens 11 | 12 | encoder = tiktoken.encoding_for_model(model) if model else tiktoken.get_encoding("cl100k_base") 13 | token_len = len(encoder.encode(prompt)) 14 | 15 | return token_len 16 | 17 | 18 | def get_message_padding(model): 19 | message_padding = 0 20 | if not model: 21 | pass 22 | elif model == "gpt-4": 23 | message_padding = 3 24 | elif model == "gpt-3.5-turbo": 25 | message_padding = 4 26 | return message_padding 27 | 28 | 29 | def parse_args(args): 30 | prompt = args['prompt'] if 'prompt' in args else '' 31 | engine = args['engine'] if 'engine' in args else 'babbage' 32 | max_tokens = args['max_tokens'] if 'max_tokens' in args else 500 33 | n = args['n'] if 'n' in args else 1 34 | total_tokens = args['total_tokens'] if 'total_tokens' in args else None 35 | 36 | return { 37 | "prompt": prompt, 38 | "engine": engine, 39 | "max_tokens": max_tokens, 40 | "n": n, 41 | "total_tokens": total_tokens, 42 | } 43 | 44 | 45 | def price_calculator_completion(args): 46 | # given prompt, engine and max_tokens, calculate estimated price in dollar 47 | # 48 | # input: 49 | # prompt: text 50 | # engine: choose between ada, babbage, curie and davinci 51 | # max_tokens: parameter that sets maximum length of model response, int 52 | # output: estimated price in dollar 53 | # 54 | # acknowledgement: this calculation is for completion model only. 55 | # best_of option is not considered. 56 | 57 | p_args = parse_args(args) 58 | prompt = p_args['prompt'] 59 | engine = p_args['engine'] 60 | max_tokens = p_args['max_tokens'] 61 | n = p_args['n'] 62 | total_tokens = p_args['total_tokens'] 63 | 64 | token_len = token_counter(prompt, engine) 65 | this_engine_max_tokens = get_engine_max_tokens(engine) 66 | this_price_per_token = get_price_per_token(engine) 67 | 68 | price_per_completion = min((token_len + int(max_tokens)), this_engine_max_tokens) * this_price_per_token 69 | 70 | if engine in ['ada', 'babbage', 'curie', 'davinci', 'ada-finetuned', 'babbage-finetuned', 'curie-finetuned', 71 | 'davinci-finetuned']: 72 | price = price_per_completion * n 73 | else: 74 | price = price_per_completion * 1 75 | 76 | # the prompt in this case is the entire training data (prompt + completion) 77 | if engine in ['ada-finetuned-training', 'babbage-finetuned-training', 'curie-finetuned-training', 78 | 'davinci-finetuned-training']: 79 | price = token_len * this_price_per_token 80 | 81 | if total_tokens: 82 | price = total_tokens * this_price_per_token 83 | 84 | return round(price, 10) 85 | 86 | 87 | def price_calculator_chat(messages, model='gpt-3.5-turbo', n=1): 88 | prompt_cost = 0 89 | completion_cost = 0 90 | 91 | # Pre-request estimation with max_tokens 92 | prompt_tokens = 0 93 | for message in messages: 94 | token_len = token_counter(message["content"], model) + \ 95 | token_counter(message["role"], model) + \ 96 | get_message_padding(model) 97 | prompt_tokens += token_len 98 | prompt_cost += token_len * get_price_per_token(model + "-prompt") 99 | completion_cost += (get_engine_max_tokens(model) - prompt_tokens) * \ 100 | get_price_per_token(model + "-completion") 101 | return round(prompt_cost + (n * completion_cost), 10) 102 | 103 | 104 | def price_calculator_chat_completion(usage, model='gpt-3.5-turbo'): 105 | return round(usage["prompt_tokens"] * get_price_per_token(model + "-prompt") + 106 | usage["completion_tokens"] * get_price_per_token(model + "-completion") 107 | , 10) 108 | 109 | 110 | def price_calculator_embedding(phrases): 111 | model = 'text-embedding-ada-002' 112 | cost = 0 113 | for phrase in phrases: 114 | token_len = token_counter(phrase, model) 115 | cost += token_len * get_price_per_token(model) 116 | return round(cost, 10) 117 | 118 | 119 | def price_calculator_embedding_completion(usage): 120 | model = 'text-embedding-ada-002' 121 | return round(usage["total_tokens"] * get_price_per_token(model), 10) 122 | 123 | 124 | def price_calculator_image(args): 125 | n = args['n'] if 'n' in args else 1 126 | size = args['size'] if 'size' in args else "1024x1024" 127 | return round(n * get_price_per_token(size), 10) 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Openai_proxy 2 | A proxy for OpenAI requests. 3 | Primarily for AI students at UPenn to track their spending on GPT-3 requests. 4 | Available for anyone to get the estimate and actual cost of a request 5 | 6 | Price estimates in this package are based on the [OpenAI API docs](https://beta.openai.com/docs/api-reference/completions/create) and [pricing page](https://beta.openai.com/pricing) 7 | They are also designed to estimate the highest possible cost of requests before they are sent. 8 | Actual request costs will always, assuming no bugs, be lower than the estimates. 9 | 10 | A frontend GUI is available [here](https://openai-proxy-client.herokuapp.com/) 11 | 12 | ## Installation 13 | Install the python package using pip 14 | ```angular2html 15 | pip install --upgrade openai_proxy 16 | ``` 17 | 18 | ## Setup 19 | Setup as follows in your development environment or server (not frontend, otherwise you may get a "CORS Error") 20 | ``` 21 | import openai_proxy 22 | 23 | openai_proxy.username = "koawood" 24 | openai_proxy.course_id = "8000" 25 | openai_proxy.access_key = "O6rbLM3-yYcwS5GaWZEghA" 26 | openai_proxy.access_token = "4q-_apNm72sGENVtYtcCXAnC7jEGnIUZfylHbEAEdFQ" 27 | ``` 28 | 29 | 30 | ### Check Completion Price 31 | This request accepts the following parameters corresponding to the OpenAI API's request parameters: 32 | See the [OpenAI API docs](https://beta.openai.com/docs/api-reference/completions/create) for more details 33 |
Note that this request does not require the credentials in the setup. 34 | - prompt: the prompt to be sent to OpenAI's GPT-3 [_required_] 35 | - engine: the GPT-3 engine to be used for the request 36 | - max_tokens: the maximum number of tokens to be generated in the completion 37 | 38 | Example: 39 | ``` 40 | response = openai_proxy.Completion.price( 41 | engine="davinci", 42 | prompt="What can you say about the Aztec Empire. Thousands of years", 43 | max_tokens=200, 44 | n=2, 45 | ) 46 | 47 | response['price'] 48 | ``` 49 | Returns a response object with a price field. 50 | Note that the Embedding and ChatCompletion classes also have price functions to estimate without sending a request. 51 | 52 | ### Send Completion Request to OpenAI 53 | This request accepts the following parameters corresponding to the OpenAI API's request parameters. 54 | See the [OpenAI API docs](https://beta.openai.com/docs/api-reference/completions/create) for more details 55 |
Note that this request requires the credentials in the setup. 56 | - prompt: the prompt to be sent to OpenAI's GPT-3 [_required_] 57 | - engine: the GPT-3 engine to be used for the request 58 | - max_tokens: the maximum number of tokens to be generated in the completion 59 | - temperature: controls randomness. Lower temperature, lower randomness 60 | - top_p: controls diversity. 1.0 means no diversity, 0.0 means maximum diversity 61 | - frequency_penalty: controls frequency of words in the completion. high penalty, less repetition 62 | - presence_penalty: controls probability of words in the completion. high penalty, newer topics 63 | - stop: a list of tokens to stop the completion on 64 | - n: the number of completions to generate 65 | - best_of: the number of completions to generate and evaluate server side before returning only the best 66 | 67 | Example: 68 | ``` 69 | response = openai_proxy.Completion.create( 70 | engine="davinci", 71 | prompt="What can you say about the Aztec Empire. Thousands of years", 72 | temperature=0.7, 73 | max_tokens=200, 74 | top_p=1, 75 | frequency_penalty=0, 76 | presence_penalty=0, 77 | stop=["###", '\n'], 78 | n=2 79 | ) 80 | 81 | response['choices'][0]['text'] 82 | response['price'] 83 | ``` 84 | Returns the Openai response object along with a price field. 85 | 86 | 87 | ### Send Embedding Request to OpenAI 88 | This request accepts the following parameters corresponding to the OpenAI API's request parameters. 89 | See the [OpenAI API docs](https://beta.openai.com/docs/api-reference/embeddings/create) for more details 90 |
Note that this request requires the credentials in the setup. 91 | - phrases: the list of phrases to be sent to OpenAI's embedding model [_required_] 92 | - engine: defaults to text-embedding-ada-002 (the cheapest model) 93 | 94 | Example: 95 | ``` 96 | response = openai_proxy.Embedding.create( 97 | phrases=["What can you say about the Aztec Empire. Thousands of years"] 98 | ) 99 | 100 | print(response) 101 | print(response['price']) 102 | ``` 103 | Returns the Openai response object along with a price field. 104 | 105 | 106 | ### Send ChatCompletion Request to OpenAI 107 | This request accepts the following parameters corresponding to the OpenAI API's request parameters. 108 | See the [OpenAI API docs](https://platform.openai.com/docs/guides/chat/introduction) for more details 109 |
Note that this request requires the credentials in the setup. 110 | - messages: the list of phrases to be sent to OpenAI's embedding model [_required_] 111 | - engine: defaults to gpt-3.5-turbo (the cheapest model) 112 | 113 | Example: 114 | ``` 115 | response = openai_proxy.ChatCompletion.create( 116 | messages=[ 117 | { 118 | "role": "system", 119 | "content": "You are a polite but sarcastic chat bot" 120 | }, 121 | { 122 | "role": "user", 123 | "content": "What can you say about the Aztec Empire. Thousands of years" 124 | }] 125 | ) 126 | print(response) 127 | print(response['price']) 128 | ``` 129 | Returns the Openai response object along with a price field. 130 | 131 | Note that the Embedding and ChatCompletion classes also have price functions to estimate without sending a request. 132 | 133 | Please reach out with any questions or suggestions 134 |
Ayotomiwa, tomiwa@wharton.upenn.edu -------------------------------------------------------------------------------- /openai_proxy/sample.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "collapsed": false 7 | }, 8 | "source": [ 9 | "Estimating prices with OpenAI-proxy sample" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "# Install openai_proxy package into your environment\n", 19 | "%%capture\n", 20 | "!pip install --upgrade openai_proxy" 21 | ] 22 | }, 23 | { 24 | "attachments": {}, 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "# Setup" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "metadata": { 35 | "collapsed": true 36 | }, 37 | "outputs": [], 38 | "source": [ 39 | "import openai_proxy\n", 40 | "import os\n", 41 | "\n", 42 | "# For UPENN students\n", 43 | "# openai_proxy.username = \"kairos\"\n", 44 | "# openai_proxy.course_id = \"8000\"\n", 45 | "# openai_proxy.access_key = \"O6rbLM3-yYcwS5GaWZEghA\"\n", 46 | "# openai_proxy.access_token = \"4q-_apNm72sGENVtYtcCXAnC7jEGnIUZfylHbEAEdFQ\"\n", 47 | "\n", 48 | "# PUBLIC users\n", 49 | "openai_proxy.api_key = os.getenv(\"OPENAI_API_KEY\")" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "import openai\n", 59 | "\n", 60 | "openai.api_key = os.getenv(\"OPENAI_API_KEY\")" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "response = openai.ChatCompletion.create(\n", 70 | " messages=[\n", 71 | " {\n", 72 | " \"role\": \"system\",\n", 73 | " \"content\": \"You are a polite but sarcastic chat bot\"\n", 74 | " },\n", 75 | " {\n", 76 | " \"role\": \"user\",\n", 77 | " \"content\": \"What can you say about the Aztec Empire. Thousands of years\"\n", 78 | " }],\n", 79 | " model=\"gpt-3.5-turbo\",\n", 80 | ")\n", 81 | "print(response['choices'][0]['message']['content'])" 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": null, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "response_2 = openai.Image.create(\n", 91 | " prompt=\"flying monkeys in nyc\",\n", 92 | " n=2,\n", 93 | " size=\"1024x1024\",\n", 94 | ")\n", 95 | "print(response_2[\"data\"])" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": null, 101 | "metadata": {}, 102 | "outputs": [], 103 | "source": [ 104 | "# To get the prices of the first response\n", 105 | "print(\"response_price\", openai_proxy.Price.from_response(response))\n", 106 | "print(\"response_2_price\", openai_proxy.Price.from_response(response_2))\n", 107 | "\n", 108 | "# To get the prices of a list of responses\n", 109 | "print(\"response_list_price\", openai_proxy.Price.from_list_response([response, response_2]))" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": null, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "# Get the maximum price of a request BEFORE sending\n", 119 | "response = openai_proxy.ChatCompletion.price(\n", 120 | " messages=[\n", 121 | " {\n", 122 | " \"role\": \"system\",\n", 123 | " \"content\": \"You are a polite but sarcastic chat bot\"\n", 124 | " },\n", 125 | " {\n", 126 | " \"role\": \"user\",\n", 127 | " \"content\": \"What can you say about the Aztec Empire. Thousands of years\"\n", 128 | " }],\n", 129 | " model=\"gpt-3.5-turbo\",\n", 130 | ")\n", 131 | "print(response['price'])" 132 | ] 133 | }, 134 | { 135 | "attachments": {}, 136 | "cell_type": "markdown", 137 | "metadata": {}, 138 | "source": [ 139 | "# More supported uses" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": null, 145 | "metadata": { 146 | "collapsed": false, 147 | "pycharm": { 148 | "name": "#%%\n" 149 | } 150 | }, 151 | "outputs": [], 152 | "source": [ 153 | "\n", 154 | "response = openai_proxy.Completion.price(\n", 155 | " engine=\"text-davinci-003\",\n", 156 | " prompt=\"The average word contains about 1.3 tokens. But most words contain a single token and niche, longer words contain more tokens like tarantula contains 3\",\n", 157 | " max_tokens=200,\n", 158 | " n=2,\n", 159 | ")\n", 160 | "\n", 161 | "print(response['price'])\n" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": null, 167 | "metadata": { 168 | "collapsed": false, 169 | "pycharm": { 170 | "name": "#%%\n" 171 | } 172 | }, 173 | "outputs": [], 174 | "source": [ 175 | "response = openai_proxy.Completion.create(\n", 176 | " engine=\"text-davinci-003\",\n", 177 | " prompt=\"What can you say about the Aztec Empire. Thousands of years\",\n", 178 | " temperature=0.7,\n", 179 | " max_tokens=200,\n", 180 | " top_p=1,\n", 181 | " frequency_penalty=0,\n", 182 | " presence_penalty=0,\n", 183 | " stop=[\"###\", '\\n'],\n", 184 | " n=2\n", 185 | ")\n", 186 | "\n", 187 | "print(response['choices'][0]['text'])\n", 188 | "print(response['price'])" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": null, 194 | "metadata": { 195 | "collapsed": false, 196 | "pycharm": { 197 | "name": "#%%\n" 198 | } 199 | }, 200 | "outputs": [], 201 | "source": [ 202 | "response = openai_proxy.Embedding.create(\n", 203 | " phrases=[\n", 204 | " \"This is the first phrase\",\n", 205 | " \"This is the second slightly longer phrase\",\n", 206 | " \"This is the third phrase\",\n", 207 | " ]\n", 208 | ")\n", 209 | "print(response)\n", 210 | "print(response['price'])" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": null, 216 | "metadata": { 217 | "collapsed": false, 218 | "pycharm": { 219 | "name": "#%%\n" 220 | } 221 | }, 222 | "outputs": [], 223 | "source": [ 224 | "response = openai_proxy.ChatCompletion.create(\n", 225 | " messages=[\n", 226 | " {\n", 227 | " \"role\": \"system\",\n", 228 | " \"content\": \"You are a polite but sarcastic chat bot\"\n", 229 | " },\n", 230 | " {\n", 231 | " \"role\": \"user\",\n", 232 | " \"content\": \"What can you say about the Aztec Empire. Thousands of years\"\n", 233 | " }],\n", 234 | " model=\"gpt-3.5-turbo\",\n", 235 | ")\n", 236 | "print(response['choices'][0]['message']['content'])\n", 237 | "print(response['price'])" 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": null, 243 | "metadata": { 244 | "collapsed": false, 245 | "pycharm": { 246 | "name": "#%%\n" 247 | } 248 | }, 249 | "outputs": [], 250 | "source": [ 251 | "response_2 = openai_proxy.Image.create(\n", 252 | " prompt=\"flying monkeys in nyc\",\n", 253 | " n=2,\n", 254 | " size=\"1024x1024\",\n", 255 | ")\n", 256 | "print(response_2[\"data\"])\n", 257 | "print(response_2['price'])" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": null, 263 | "metadata": { 264 | "collapsed": false, 265 | "pycharm": { 266 | "name": "#%%\n" 267 | } 268 | }, 269 | "outputs": [], 270 | "source": [ 271 | "# To get the price of all the requests sent since last package import\n", 272 | "print(\"session_price\", openai_proxy.session_price)" 273 | ] 274 | } 275 | ], 276 | "metadata": { 277 | "kernelspec": { 278 | "display_name": "Python 3", 279 | "language": "python", 280 | "name": "python3" 281 | }, 282 | "language_info": { 283 | "codemirror_mode": { 284 | "name": "ipython", 285 | "version": 3 286 | }, 287 | "file_extension": ".py", 288 | "mimetype": "text/x-python", 289 | "name": "python", 290 | "nbconvert_exporter": "python", 291 | "pygments_lexer": "ipython3", 292 | "version": "3.9.5" 293 | }, 294 | "vscode": { 295 | "interpreter": { 296 | "hash": "2fe5bca17fb879a08cf6fd313262bb7ad63d5ffec61276eaa38c8f08b877b591" 297 | } 298 | } 299 | }, 300 | "nbformat": 4, 301 | "nbformat_minor": 0 302 | } 303 | --------------------------------------------------------------------------------