├── .DS_Store ├── .gitignore ├── README.md ├── fineTuneBad.txt ├── fineTuneData.txt ├── gpt3.py ├── main.py ├── requirements.txt ├── sheets.py └── utils.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yash-dani/AutoAccounting/8d3808d4828ba02bc459ce5a5ce1b24f27a1cce8/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | credentials.json 2 | token.pickle 3 | key.txt 4 | .vscode/.ropeproject/config.py 5 | .vscode/.ropeproject/objectdb 6 | fineTuneBad.txt 7 | gpt-3_finetune 8 | __pycache__ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GPT-3 for Finance 2 | A GPT-3 bot that lets people with no accounting knowledge generate financial statements using everyday language. 3 | 4 | ### Demo 5 | A demo of this program can be found [here](https://twitter.com/itsyashdani/status/1285695850300219392). 6 | -------------------------------------------------------------------------------- /fineTuneBad.txt: -------------------------------------------------------------------------------- 1 | Q: I bought a $30000 car on credit to be repaid in 5 years. 2 | A: add(30000, Property, Plant, Equipment); add (30000, Long-Term Debt) 3 | 4 | Q: I bought $20000 of equipment to be repaid in 2 months. 5 | A: add(20000, Property, Plant, Equipment); add(20000, Short-Term Loans) 6 | 7 | Q: A customer owes me $150 for his purchases. 8 | A: add(150, Accounts Receivable) 9 | 10 | Q: I bought $3000 software to be repaid in 1 month 11 | A: add(3000, Property, Plant, Equipment); add(3000, Short-Term Loans) 12 | 13 | -------------------------------------------------------------------------------- /fineTuneData.txt: -------------------------------------------------------------------------------- 1 | Q: I bought a $30000 car on credit to be repaid in 5 years. 2 | A: [["add", 30000, "Property, Plant, Equipment"], ["add", 30000, "Long-Term Debt"]] 3 | 4 | Q: I bought $20000 of equipment to be repaid in 2 months. 5 | A: [["add", 20000, "Property, Plant, Equipment"], ["add", 20000, "Short-Term Loans"]] 6 | 7 | Q: A customer owes me $150 for his purchases. 8 | A: [["add", 150, "Accounts Receivable"]] 9 | 10 | Q: I bought an additional $12000 worth of inventory which I paid for immediately. 11 | A: [["add", 1200, "Inventory"], ["remove", 12000, "Cash"]] 12 | 13 | Q: I bought new furniture for the store that cost me $99 in cash. 14 | A: [["add", 99, "Property, Plant, Equipment"], ["remove", 99, "Cash"]] 15 | 16 | Q: I just took out a loan for $12900 that I need to pay back in 3 years. 17 | A: [["add", 12900, "Long-Term Debt"], ["add", 12900, "Cash"]] 18 | 19 | Q: I prepaid $12000 for the rent for the next 3 months. 20 | A: [["add", 12000, "Prepaid Expenses"], ["remove", 12000, "Cash"]] 21 | 22 | -------------------------------------------------------------------------------- /gpt3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | authors: @yash-dani @gkysaad 3 | date: July 2020 4 | Turn informat statements into requests to update balance sheets using GPT-3 5 | ''' 6 | 7 | import ast # standard library 8 | import openai # 3rd party packages 9 | import json 10 | 11 | ''' 12 | Function to turn informal request into transactional statement 13 | ''' 14 | def getGPT3(request): 15 | 16 | # setup key and fine tuning data 17 | key = open("key.txt", "r") 18 | fineTuneData = open("fineTuneData.txt", "r") 19 | question = "Q: " + request 20 | openai.api_key = key.read() 21 | 22 | # request completion from GPT-3 23 | output = openai.Completion.create( 24 | engine="davinci", 25 | prompt= fineTuneData.read() + question + "\n", 26 | max_tokens=100, 27 | temperature=0.4, 28 | stop=["Q: ",'\n'] 29 | ) 30 | 31 | # process output 32 | try: 33 | output = json.loads(output["choices"][0]["text"].replace('A:','')) 34 | except: 35 | output = output["choices"][0]["text"].replace('A: ','') 36 | 37 | 38 | return output 39 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import gpt3 # user generated packages 2 | from sheets import balanceSheet 3 | from utils import clear 4 | import webbrowser 5 | 6 | if __name__ == '__main__': 7 | clear() 8 | # Intro text 9 | print("------------------------------------------------------") 10 | print('Welcome to the Balance Sheet Maker, powered by GPT-3.') 11 | print("") 12 | print('Your transaction -> python code -> Google Sheets file') 13 | print("-----------------------------------------------------") 14 | print() 15 | statement = balanceSheet() 16 | 17 | # Open sheet in browser 18 | webbrowser.open('https://docs.google.com/spreadsheets/d/' + 19 | statement.current_sheet_id, new=1) 20 | # Loop to make requests to bot 21 | while True: 22 | print() 23 | request = input("Tell me about your transaction:\n") 24 | transactionInfo = gpt3.getGPT3(request) # get GPT-3 Output 25 | # print(transactionInfo) 26 | if type(transactionInfo) == list: 27 | # Successfully parsed output 28 | print() 29 | print("Results:") 30 | for transaction in transactionInfo: 31 | print(transaction[0],transaction[1], "to ", transaction[2]) 32 | statement.update(transaction[0], transaction[1],transaction[2]) 33 | else: 34 | # Error in parsing gpt3 35 | print('GPT-3 was not able to process your statement. Try rewording it!') 36 | clear() 37 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | openai==0.2.4 2 | datetime==4.3 3 | google-api-python-client==1.10.0 4 | google-auth-httplib2==0.0.4 5 | google-auth-oauthlib==0.4.1 -------------------------------------------------------------------------------- /sheets.py: -------------------------------------------------------------------------------- 1 | ''' 2 | author @george 3 | 4 | Sheets API integration to duplicate balance sheet template and add to it 5 | ''' 6 | 7 | import pickle 8 | import os.path 9 | from datetime import date 10 | from googleapiclient.discovery import build 11 | from google_auth_oauthlib.flow import InstalledAppFlow 12 | from google.auth.transport.requests import Request 13 | 14 | 15 | class balanceSheet(): 16 | def __init__(self, sheetId=''): 17 | ''' 18 | Initializes SheetsAPI 19 | ''' 20 | # auth scope for sheets API, if modifying, delete token.pickle 21 | self.SCOPES = ['https://www.googleapis.com/auth/drive'] 22 | 23 | # balance sheet template 24 | self.TEMPLATE_ID = '17bnwsQya4yrbk9h8cR2-2fiVEYU2Eo-aA7LbowoRPzc' 25 | 26 | self.current_sheet_id = sheetId 27 | 28 | # dictionary of mapping of cell title with cell index 29 | self.get_cell = { 30 | # Current Assets 31 | 'Cash': 'B5', 32 | 'Accounts Receivable': 'B6', 33 | 'Inventory': 'B7', 34 | 'Prepaid Expenses': 'B8', 35 | 'Short-Term Investment': 'B9', 36 | 37 | # Non-Current Assets 38 | 'Long-Term Investments': 'B13', 39 | 'Property, Plant, Equipment': 'B14', 40 | '(Less Accumulated Depreciation)': 'B15', 41 | 'Intangible Assets': 'B16', 42 | 43 | # Current Liabilities 44 | 'Accounts Payable': 'E5', 45 | 'Short-Term Loans': 'E6', 46 | 'Income Taxes Payable': 'E7', 47 | 'Accrued Salaries and Wages': 'E8', 48 | 'Unearned Revenue': 'E9', 49 | 'Current Portion of Long-Term Debt': 'E10', 50 | 51 | # Non-Current Liabilities 52 | 'Long-Term Debt': 'E14', 53 | 'Deferred Income Tax': 'E15', 54 | 'Non-Current Liabilities Other': 'E16', 55 | 56 | # Owner's Equity 57 | 'Owner\'s Investment': 'E20', 58 | 'Retained Earnings': 'E21', 59 | 'Owner\'s Equity Other': 'E22' 60 | } 61 | self.service = self.sheets_auth() 62 | self.create_sheet_from_template() 63 | 64 | def sheets_auth(self): 65 | ''' 66 | Gets authorization to modify sheets 67 | ''' 68 | creds = None 69 | # The file token.pickle stores the user's access and refresh tokens, and is 70 | # created automatically when the authorization flow completes for the first 71 | # time. 72 | if os.path.exists('token.pickle'): 73 | with open('token.pickle', 'rb') as token: 74 | creds = pickle.load(token) 75 | # If there are no (valid) credentials available, let the user log in. 76 | if not creds or not creds.valid: 77 | if creds and creds.expired and creds.refresh_token: 78 | creds.refresh(Request()) 79 | else: 80 | flow = InstalledAppFlow.from_client_secrets_file( 81 | 'credentials.json', self.SCOPES) 82 | creds = flow.run_local_server(port=0) 83 | # Save the credentials for the next run 84 | with open('token.pickle', 'wb') as token: 85 | pickle.dump(creds, token) 86 | 87 | service = build('sheets', 'v4', credentials=creds) 88 | return service 89 | 90 | def create_sheet_from_template(self): 91 | ''' 92 | Creates new blank sheet, duplicated the template balance sheet into it and deletes 93 | the intial empty sheet. 94 | ''' 95 | 96 | # Get authenitcated service 97 | service = self.service 98 | 99 | spreadsheet = { 100 | 'properties': { 101 | 'title': 'Personalized Balance Sheet' 102 | } 103 | } 104 | 105 | # Create a new spreadsheet 106 | spreadsheet = service.spreadsheets().create( 107 | body=spreadsheet, fields='spreadsheetId').execute() 108 | 109 | newSheetId = spreadsheet.get('spreadsheetId') 110 | 111 | self.current_sheet_id = newSheetId 112 | 113 | copy_sheet_to_another_spreadsheet_request_body = { 114 | 'destination_spreadsheet_id': newSheetId, 115 | } 116 | 117 | # Copy template sheet to the new spreadsheet 118 | request = service.spreadsheets().sheets().copyTo(spreadsheetId=self.TEMPLATE_ID, 119 | sheetId=0, body=copy_sheet_to_another_spreadsheet_request_body) 120 | response = request.execute() 121 | 122 | # Delete the empty intial sheet in the new spreadsheet 123 | deleteData = { 124 | "requests": [ 125 | { 126 | "deleteSheet": { 127 | "sheetId": 0 128 | } 129 | } 130 | ] 131 | } 132 | 133 | deleteSheet = service.spreadsheets().batchUpdate( 134 | spreadsheetId=self.current_sheet_id, body=deleteData).execute() 135 | 136 | # Sets the date on the spreadsheet to today's date 137 | body = { 138 | 'values': [[str(date.today())]] 139 | } 140 | 141 | resultSet = service.spreadsheets().values().update( 142 | spreadsheetId=self.current_sheet_id, range='D1', valueInputOption='USER_ENTERED', body=body).execute() 143 | 144 | return response 145 | 146 | def update(self, function, amount, section, sheetId=None): 147 | ''' 148 | Modifies a cell in the spreadsheet by adding to it. 149 | ''' 150 | 151 | # Get cell being updated with error handling 152 | try: 153 | cell = self.get_cell[section] 154 | except KeyError: 155 | print("Field not found") 156 | return 157 | 158 | # add or remove handling 159 | if function == "remove": 160 | amount *= -1.0 161 | 162 | # Set object sheet ID if one is provided 163 | if sheetId: 164 | self.current_sheet_id = sheetId 165 | 166 | # Get authenitcated service 167 | service = self.service 168 | 169 | # Get the current value in the cell to be modified 170 | resultGet = service.spreadsheets().values().get( 171 | spreadsheetId=self.current_sheet_id, range=cell).execute() 172 | vals = resultGet.get('values', []) 173 | 174 | if len(vals) == 0: 175 | vals = [[0]] 176 | 177 | # Add to the cell 178 | vals[0][0] = str(round(float(vals[0][0]) + float(amount), 2)) 179 | 180 | # Update cell in sheet 181 | body = { 182 | 'values': vals 183 | } 184 | 185 | resultSet = service.spreadsheets().values().update( 186 | spreadsheetId=self.current_sheet_id, range=cell, valueInputOption='USER_ENTERED', body=body).execute() 187 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | from os import system, name # built in packages 2 | from time import sleep 3 | 4 | # clear screen (for readability when interacting with bot) 5 | def clear(): 6 | # windows 7 | if name == 'nt': 8 | _ = system('cls') 9 | # mac & linux 10 | else: 11 | _ = system('clear') --------------------------------------------------------------------------------