├── .gitattributes └── app.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import json 3 | import os 4 | from dotenv import load_dotenv 5 | from pyairtable import Table 6 | import requests 7 | 8 | load_dotenv() 9 | openai.api_key = os.getenv("OPENAI_API_KEY") 10 | rapid_api_key = os.getenv("X-RapidAPI-Key") 11 | smart_light_api_key = os.getenv("SMART_LIGHT_API_KEY") 12 | 13 | airtable_api_key = os.getenv("AIRTABLE_API_KEY") 14 | table = Table(airtable_api_key, "appHojHIE4y8gVBgc", "tbldUUKZFngr78ogg") 15 | 16 | function_descriptions = [ 17 | { 18 | "name": "get_stock_movers", 19 | "description": "Get the stocks that has biggest price/volume moves, e.g. actives, gainers, losers, etc.", 20 | "parameters": { 21 | "type": "object", 22 | "properties": { 23 | }, 24 | } 25 | }, 26 | { 27 | "name": "get_stock_news", 28 | "description": "Get the latest news for a stock", 29 | "parameters": { 30 | "type": "object", 31 | "properties": { 32 | "performanceId": { 33 | "type": "string", 34 | "description": "id of the stock, which is referred as performanceID in the API" 35 | }, 36 | }, 37 | "required": ["performanceId"] 38 | } 39 | }, 40 | { 41 | "name": "add_stock_news_airtable", 42 | "description": "Add the stock, news summary & price move to Airtable", 43 | "parameters": { 44 | "type": "object", 45 | "properties": { 46 | "stock": { 47 | "type": "string", 48 | "description": "stock ticker" 49 | }, 50 | "move": { 51 | "type": "string", 52 | "description": "price move in %" 53 | }, 54 | "news_summary": { 55 | "type": "string", 56 | "description": "news summary of the stock" 57 | }, 58 | } 59 | } 60 | }, 61 | { 62 | "name": "control_light", 63 | "description": "Turn on/off the light", 64 | "parameters": { 65 | "type": "object", 66 | "properties": { 67 | "state": { 68 | "type": "string", 69 | "description": "the state of the light, should be on or off", 70 | "enum": ["on", "off"] 71 | } 72 | } 73 | } 74 | } 75 | ] 76 | 77 | 78 | def add_stock_news_airtable(stock, move, news_summary): 79 | table.create({"stock":stock, "move%": move, "news_summary":news_summary}) 80 | 81 | def get_stock_news(performanceId): 82 | url = "https://morning-star.p.rapidapi.com/news/list" 83 | 84 | querystring = {"performanceId":performanceId} 85 | 86 | headers = { 87 | "X-RapidAPI-Key": rapid_api_key, 88 | "X-RapidAPI-Host": "morning-star.p.rapidapi.com" 89 | } 90 | 91 | response = requests.get(url, headers=headers, params=querystring) 92 | 93 | short_news_list = response.json()[:5] 94 | 95 | print("response:", response, " json response:", short_news_list) 96 | 97 | return short_news_list 98 | 99 | 100 | def get_stock_movers(): 101 | url = "https://morning-star.p.rapidapi.com/market/v2/get-movers" 102 | 103 | headers = { 104 | "X-RapidAPI-Key": rapid_api_key, 105 | "X-RapidAPI-Host": "morning-star.p.rapidapi.com" 106 | } 107 | 108 | response = requests.get(url, headers=headers) 109 | 110 | return response.json() 111 | 112 | 113 | def control_light(state): 114 | token = smart_light_api_key 115 | 116 | headers = { 117 | "Authorization": f"Bearer {token}", 118 | } 119 | 120 | payload = { 121 | "power": state, 122 | } 123 | 124 | response = requests.put('https://api.lifx.com/v1/lights/all/state', data=payload, headers=headers) 125 | 126 | return response.json() 127 | 128 | 129 | def function_call(ai_response): 130 | function_call = ai_response["choices"][0]["message"]["function_call"] 131 | function_name = function_call["name"] 132 | arguments = function_call["arguments"] 133 | if function_name == "get_stock_movers": 134 | return get_stock_movers() 135 | elif function_name == "get_stock_news": 136 | performanceId = eval(arguments).get("performanceId") 137 | return get_stock_news(performanceId) 138 | elif function_name == "add_stock_news_airtable": 139 | stock = eval(arguments).get("stock") 140 | news_summary = eval(arguments).get("news_summary") 141 | move = eval(arguments).get("move") 142 | return add_stock_news_airtable(stock, move, news_summary) 143 | elif function_name == "control_light": 144 | state = eval(arguments).get("state") 145 | return control_light(state) 146 | else: 147 | return 148 | 149 | 150 | def ask_function_calling(query): 151 | messages = [{"role": "user", "content": query}] 152 | 153 | response = openai.ChatCompletion.create( 154 | model="gpt-4-0613", 155 | messages=messages, 156 | functions = function_descriptions, 157 | function_call="auto" 158 | ) 159 | 160 | print(response) 161 | 162 | while response["choices"][0]["finish_reason"] == "function_call": 163 | function_response = function_call(response) 164 | messages.append({ 165 | "role": "function", 166 | "name": response["choices"][0]["message"]["function_call"]["name"], 167 | "content": json.dumps(function_response) 168 | }) 169 | 170 | print("messages: ", messages) 171 | 172 | response = openai.ChatCompletion.create( 173 | model="gpt-4-0613", 174 | messages=messages, 175 | functions = function_descriptions, 176 | function_call="auto" 177 | ) 178 | 179 | print("response: ", response) 180 | else: 181 | print(response) 182 | 183 | 184 | user_query = "Turn on the light" 185 | 186 | ask_function_calling(user_query) --------------------------------------------------------------------------------