├── .gitattributes ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── example.gif ├── function.py └── main.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[python]": { 3 | "editor.defaultFormatter": "ms-python.autopep8" 4 | }, 5 | "python.formatting.provider": "none" 6 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenAi Function Calling Use Examples 2 | 3 | A simple example that demonstrates how to use the function call feature of the OpenAI API 4 | 5 | ## Example 6 | 7 | 8 | 9 | ## Libraries that need to be installed 10 | 11 | 1. openai 12 | 2. streamlit 13 | 3. python-dotenv 14 | 15 | ## installation 16 | 17 | 1. Clone the current repository 18 | 19 | ```shell 20 | $ git clone https://github.com/Simoon-F/openai-function-calling-use-exaples 21 | ``` 22 | 23 | 2. Enter the project root directory 24 | 25 | ```shell 26 | $ cd openai-function-calling-use-exaples 27 | ``` 28 | 29 | 3. Create the `.env` file and add your api key 30 | 31 | 4. Set up environment variables: 32 | 33 | - Create a `.env` file in the root of the project. 34 | 35 | - Add your Open AI API key to the .env file: 36 | 37 | ```env 38 | OPENAI_API_KEY=your Open AI api key 39 | AMAP_API_KEY=your AMAP api key 40 | ``` 41 | 42 | `TIPS:` If there is no AMAP_API_KEY, you can comment out the relevant code. 43 | 44 | 5. Run Project 45 | ```shell 46 | $ streamlit run main.py 47 | ``` 48 | 49 | ## Official Description 50 | 51 | [function-calling-and-other-api-updates](https://openai.com/blog/function-calling-and-other-api-updates) 52 | -------------------------------------------------------------------------------- /example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Simoon-F/openai-function-calling-use-examples/340c1212dae3aa00b5bf9f5439d3e85ba31880ab/example.gif -------------------------------------------------------------------------------- /function.py: -------------------------------------------------------------------------------- 1 | function_list = [ 2 | { 3 | "name": "query_city_weather", # Function Name 4 | "description": "query weather temperature", # Meta information of function 5 | "parameters": { # parameters 6 | "type": "object", 7 | "properties": { 8 | "city": { 9 | "type": "string", 10 | "description": "The city", 11 | }, 12 | }, 13 | "required": ["city"], 14 | }, 15 | }, 16 | { 17 | "name": "send_email", 18 | "description": "Send email information", 19 | "parameters": { 20 | "type": "object", 21 | "properties": { 22 | "to_email": { 23 | "type": "string", 24 | "description": "Recipient's email address" 25 | }, 26 | "title": { 27 | "type": "string", 28 | "description": "The title of the email" 29 | }, 30 | "body": { 31 | "type": "string", 32 | "description": "The Body of the email" 33 | } 34 | }, 35 | "required": ["to_email", "title", "body"], 36 | } 37 | }, 38 | { 39 | "name": "addition_function", 40 | "description": "Calculate the left and right values ​​of the + method operator symbol", 41 | "parameters": { 42 | "type": "object", 43 | "properties": { 44 | "left": { 45 | "type": "number", 46 | "description": "+The value on the left side of the operator symbol" 47 | }, 48 | "right": { 49 | "type": "number", 50 | "description": "+The value on the right side of the operator symbol" 51 | } 52 | }, 53 | "required": ["left", "right"] 54 | } 55 | }, 56 | { 57 | "name": "substruction_function", 58 | "description": "substruction the left and right values ​​of the - method operator symbol", 59 | "parameters": { 60 | "type": "object", 61 | "properties": { 62 | "left": { 63 | "type": "number", 64 | "description": "-The value on the left side of the operator symbol" 65 | }, 66 | "right": { 67 | "type": "number", 68 | "description": "-The value on the right side of the operator symbol" 69 | } 70 | }, 71 | "required": ["left", "right"] 72 | } 73 | } 74 | ] 75 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import time 2 | import streamlit as st 3 | import openai 4 | import json 5 | import function as f 6 | import requests as rq 7 | from streamlit_chat import message 8 | from dotenv import dotenv_values 9 | 10 | 11 | # initialization 12 | if 'generated' not in st.session_state: 13 | st.session_state['generated'] = [] 14 | if 'past' not in st.session_state: 15 | st.session_state['past'] = [] 16 | if 'messages' not in st.session_state: 17 | st.session_state['messages'] = [] 18 | 19 | 20 | class IntentsList: 21 | def __init__(self): 22 | """ 23 | The api of Gaud Open Platform is used here. 24 | 25 | https://lbs.amap.com/api/webservice/guide/api/weatherinfo 26 | """ 27 | self.weather_api_url = "https://restapi.amap.com/v3/weather/weatherInfo" 28 | self.amap_api_key = env['AMAP_API_KEY'] 29 | 30 | def query_city_weather(self, city): 31 | """ 32 | Query the weather temperature of the city. 33 | 34 | Args: 35 | city (str): Cities that should be queried. 36 | """ 37 | params = { 38 | "key": self.amap_api_key, 39 | "city": city, 40 | "output": "json", 41 | "extensions": "all", 42 | } 43 | 44 | response = rq.get(self.weather_api_url, params=params) 45 | 46 | response.raise_for_status() 47 | 48 | weather_data = response.json() 49 | 50 | return json.dumps(weather_data) 51 | 52 | for item in weather_data['forecasts']: 53 | st.markdown(f"{item['province'] + item['city']} is as follows:") 54 | for cast in item['casts']: 55 | st.markdown( 56 | f"**{cast['date']}** :`dayweather`:{cast['dayweather']}, `nightweather`:{cast['nightweather']}, `daytemp`: {cast['daytemp']}, `nighttemp`:{cast['nighttemp']}") 57 | 58 | @staticmethod 59 | def send_email(to_email, title, body): 60 | # st.markdown(f"Recipient:{to_email}") 61 | # st.markdown(f"Email Title:{title}") 62 | # st.markdown(f"Email Body:{body}") 63 | 64 | return "Mail Sent,Recipient:{to_email}, Email Title: {title}, Email body: {body}" 65 | 66 | @staticmethod 67 | def addition_function(left, right): 68 | return left + right 69 | 70 | @staticmethod 71 | def substruction_function(left, right): 72 | return left - right 73 | 74 | 75 | def call_gpt(user_input): 76 | # 将用户输入添加到会话状态中的消息列表中 77 | st.session_state['messages'].append( 78 | {"role": "user", "content": user_input}) 79 | 80 | # 使用OpenAI的GPT-3.5模型进行聊天补全 81 | completion = openai.ChatCompletion.create( 82 | model="gpt-3.5-turbo-0613", 83 | # 将会话状态中的消息列表传递给聊天补全模型 84 | messages=st.session_state['messages'], 85 | # messages=messages, 86 | # 定义可调用的函数列表 87 | functions=f.function_list, 88 | # 设置函数调用方式为自动调用 89 | function_call="auto", 90 | ) 91 | 92 | # 打印补全结果 93 | print(completion) 94 | 95 | # 返回补全结果中的第一个选项的消息 96 | return completion.choices[0].message 97 | 98 | 99 | if __name__ == "__main__": 100 | st.title("Small assistant") 101 | 102 | env = dotenv_values() 103 | openai.api_key = env['OPENAI_API_KEY'] 104 | 105 | intents_list_obj = IntentsList() 106 | 107 | user_input = st.chat_input("Enter your prompt:") 108 | 109 | if user_input: 110 | assistant_output = call_gpt(user_input) 111 | 112 | st.session_state['past'].append(user_input) 113 | 114 | function_call = assistant_output.get('function_call') 115 | 116 | if (function_call): 117 | 118 | method_name, method_args = function_call.get( 119 | 'name'), function_call.get('arguments') 120 | 121 | method_args_dict = json.loads(method_args) 122 | method = getattr(intents_list_obj, method_name) 123 | method_result = method(**method_args_dict) 124 | 125 | # Append output to messages 126 | st.session_state['messages'].append(assistant_output) 127 | 128 | # Int to string 129 | if type(method_result) == int: 130 | method_result = str(method_result) 131 | 132 | # Append method result to messages 133 | st.session_state['messages'].append( 134 | {"role": "function", "name": method_name, 135 | "content": method_result, }) 136 | 137 | second_response = openai.ChatCompletion.create( 138 | model="gpt-3.5-turbo-0613", 139 | messages=st.session_state['messages'], 140 | ) 141 | 142 | st.session_state['generated'].append( 143 | second_response.choices[0].message.get('content')) 144 | 145 | else: 146 | content = assistant_output.get('content') 147 | 148 | st.session_state['generated'].append( 149 | assistant_output.get('content')) 150 | 151 | # Append content to messages 152 | st.session_state['messages'].append( 153 | {"role": "assistant", "content": content}) 154 | 155 | # History chat container 156 | response_container = st.container() 157 | 158 | # Render session 159 | if st.session_state['generated']: 160 | with response_container: 161 | for i in range(len(st.session_state['generated'])): 162 | message(st.session_state["past"][i], 163 | is_user=True, key=str(i) + '_user') 164 | message(st.session_state["generated"][i], key=str(i)) 165 | --------------------------------------------------------------------------------