Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CashGPT- AI finance assistant to help you track your Google Pay expenses. #45

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions community/cashGPT/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# CashGPT

Tracking your UPI transactions is a hassle. CashGPT helps you analyze your transactions based on your Google Pay data. You can track your spending and much more.

## Table of Contents

- [Usage](#usage)
- [Example Prompts](#Example)
- [Technologies Used](#technologies-used)

## Usage

1. Download your Google Takeout data from [Google Takeout](https://takeout.google.com/) for Google Pay.
2. Find the `My Activity.html` file inside `Takeout/Google Pay/My Activity` and paste it inside the CashGPT folder.
3. Start the Python server: `python3 api.py`
4. Open `index.html` from the `client` folder: `client/index.html`

## Example Prompts

- How much did I overall spend last month?
- Where did I spend the most this month?
- My last 5 transactions

## Technologies Used

- **Backend:** Python
- **Frontend:** HTML, CSS, JavaScript
- **AI Model API:** proxy.tune.app

## Snippet of Working

![Working Demo](https://github.com/phaniankur/cookbook/blob/main/community/cashGPT/demo.gif)
63 changes: 63 additions & 0 deletions community/cashGPT/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
from cashgpt import cashgpt_controller # Import the controller function

# Define the request handler class
class RequestHandler(BaseHTTPRequestHandler):

def _send_response(self, response_data, status=200):
self.send_response(status)
self.send_header('Content-type', 'application/json')
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
self.end_headers()
self.wfile.write(json.dumps(response_data).encode('utf-8'))

# Handle POST requests
def do_POST(self):
# Check if the request path is /api/cashgpt
if self.path == '/api/cashgpt':
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length)

try:
# Parse the data as JSON
data = json.loads(post_data)

# Check if 'hukum' key is in the data
if 'hukum' not in data:
response_data = {"error": "Missing 'hukum' key"}
self._send_response(response_data, status=400)
return

# Process the 'hukum' value
hukum_value = data['hukum']
# Call the controller function
response_data = cashgpt_controller(hukum_value)
self._send_response(response_data)

except json.JSONDecodeError:
# Handle invalid JSON
response_data = {"error": "Invalid JSON format"}
self._send_response(response_data, status=400)
else:
self.send_response(404)
self.end_headers()
self.wfile.write(b'Not Found')

# Handle OPTIONS requests for CORS preflight
def do_OPTIONS(self):
self.send_response(204) # No content
self.send_header('Access-Control-Allow-Origin', '*') # Allow all origins
self.send_header('Access-Control-Allow-Methods', 'POST, OPTIONS') # Allow specific methods
self.send_header('Access-Control-Allow-Headers', 'Content-Type') # Allow specific headers
self.end_headers()

# Define the server address and port
server_address = ('', 8080)

# Create and run the HTTP server
httpd = HTTPServer(server_address, RequestHandler)
print("Server running on port 8080...")
httpd.serve_forever()
152 changes: 152 additions & 0 deletions community/cashGPT/cashgpt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
from bs4 import BeautifulSoup
from datetime import datetime, timedelta
import re
import http.client
import json
import os
from dotenv import load_dotenv
load_dotenv()

def extract_content_from_html(file_path):
extracted_data = []

# Open and parse the HTML file
with open(file_path, "r") as fp:
soup = BeautifulSoup(fp, 'html.parser')

# Loop through all <div> elements with the specified class
for tag in soup.find_all('div', {'class': 'content-cell mdl-cell mdl-cell--6-col mdl-typography--body-1'}):
text = tag.get_text(strip=True)
br_tag = tag.find("br")

# Extract the text after the <br> tag
if br_tag:
DateToBeAppended = br_tag.find_next_sibling(string=True)

try:
# Convert the string to a datetime object
date_object = datetime.strptime(DateToBeAppended, '%b %d, %Y, %I:%M:%S %p %Z')

# Format the date to only display the date (YYYY-MM-DD)
formatted_date = date_object.strftime('%Y-%m-%d')

# Get the current date and calculate the date one month (30 days) ago
current_date = datetime.now()
one_month_ago = current_date - timedelta(days=60) # restricting the search till 60 days to keep the model light

# Check if the `date_object` is within the last month
if date_object >= one_month_ago:
amountToBeAppended = extract_amount(text) # Extract the amount from the text

if amountToBeAppended is not None:
# Identify the business, person, or bank name
business_name = extract_business_name(text)
isPaid = paidOrReceived(text)

# Initialize the base data structure
data = {
"date": formatted_date,
"paid": 0,
"received": 0,
"business_name": business_name
}

# Update the `paid` or `received` field based on the transaction type
if isPaid == "paid" or isPaid == "sent":
data["paid"] = amountToBeAppended
elif isPaid == "received":
data["received"] = amountToBeAppended

# Append the transaction data to the result list
extracted_data.append(data)
except Exception as e:
print(f"Error processing date: {e}")

return extracted_data

# extract business name
def extract_business_name(text):
# Look for "to [Business]" or "using [Bank Account]"
to_pattern = re.search(r'to ([A-Za-z\s]+)', text)
using_bank_pattern = re.search(r'using (Bank Account)', text)

if to_pattern:
return to_pattern.group(1).strip() # Extract the business or person name
elif using_bank_pattern:
return "Bank Account" # Return "Bank Account" if no business is found
else:
return "Unknown" # Return Unknown if no match is found

# extract amount from string
def extract_amount(text):
# Sample regex to extract the amount (e.g., "₹250.00")
match = re.search(r'₹([\d,]+\.\d{2})', text)
if match:
return match.group(1)
return None

# was amount paid or received
def paidOrReceived(text):
# logic to determine the transaction type
if "Paid" in text:
return "paid"
elif "Sent" in text:
return "sent"
elif "Received" in text:
return "received"
return None


def prompt_transaction_calculation(transaction_prompt, client_prompt):
conn = http.client.HTTPSConnection("proxy.tune.app")
payload = json.dumps({
"temperature": 0.9,
"messages": [
{
"role": "system",
"content": transaction_prompt
},
{
"role": "user",
"content": client_prompt
}
],
"model": "AnkurPhani/AP",
"stream": False,
"frequency_penalty": 0.2,
"max_tokens": 500
})
headers = {
'Authorization': os.getenv('AUTHORIZATION_KEY'),
'Content-Type': 'application/json'
}

conn.request("POST", "/chat/completions", payload, headers)
res = conn.getresponse()
data = res.read()
result = json.loads(data.decode("utf-8"))

# Extract and return the desired content
return result['choices'][0]['message']['content']



def cashgpt_controller(client_prompt):
if client_prompt != "":
# Specify the path to the HTML file
file_path = "./My Activity.html"

# Call the function and store the result
transaction = extract_content_from_html(file_path)

# Convert the transaction to a string representation
transaction_string = str(transaction)
# print("Transaction str", transaction)

accountant_prompt = f"You are an experienced accountant responsible for handling your client's finances. You will be prompted by your client to analyse his financial transactions. You are provided an array of objects of your client's transactions like transaction date, paid or received amount and the name of the business the amount was paid to. \n 'date' key is the date of transaction, 'paid' is amount is paid if not zero and 'received' is amount is received if non zero. 'business_name' is the name of the business. Calculate requested calculations by your client like expenses, or received to a business or monthly or weekly expenses, Last paid amount to a business or total amount paid to a business in a month.\n\nHere is the list of all transactions\n\n{transaction_string}The output of your response needs to be formal and any amount mentioned should be in rupee (₹). Stick to the point with the answers."
response = prompt_transaction_calculation(accountant_prompt, client_prompt)
return response
else:
print("Prompt is required to continue.")

return "no prompt to continue"
110 changes: 110 additions & 0 deletions community/cashGPT/client/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

body {
background-color: #f0f8f0;
font-family: 'Roboto', sans-serif;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}

.chat-container {
/* min-width: 7%; */
width: 800px;
margin: 0; /*Remove margin to use flex centering */
border: 1px solid #4CAF50;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
height: 600px; /* Set a fixed height */
}


.chat-header {
background-color: #4CAF50;
color: white;
padding: 15px;
text-align: center;
}
.chat-header h2{
font-size: 18px;
}
.chat-header p{
font-size: 18px;
}

.chat-box {
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start; /* Align items to the left */
height: 300px;
overflow-y: auto;
padding: 10px;
background-color: #fff;
}

.input-container {
display: flex;
padding: 10px;
background-color: #f9f9f9;
border-top: 1px solid #4CAF50;
min-height: 50px;
}

input[type="text"] {
flex: 1;
padding: 10px;
border: 1px solid #4CAF50;
border-radius: 5px;
margin-right: 10px;
}

button {
background-color: #4CAF50;
color: white;
border: none;
padding: 10px 15px;
border-radius: 5px;
cursor: pointer;
}

button:hover {
background-color: #45a049;
}

.message {
margin: 10px 0;
padding: 10px;
border-radius: 10px;
max-width: 70%;
}

.user {
background-color: #d1ffd1;
align-self: flex-start;
}

.assistant {
background-color: #4CAF50;
color: white;
align-self: flex-end;
line-height: 28px;
}

/* Animation */
.message {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.5s, transform 0.5s;
}

.message.show {
opacity: 1;
transform: translateY(0);
}
29 changes: 29 additions & 0 deletions community/cashGPT/client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./index.css">
<title>CashGPT</title>
</head>

<body>
<div class="chat-container">
<div class="chat-header">
<h1>CashGPT</h1>
<p>AI Finance assistant to help you track your Google Pay expenses.</p>

</div>
<div class="chat-box" id="chat-box">
<!-- Chat messages will be displayed here -->
</div>
<div class="input-container">
<input type="text" id="user-input" placeholder="How much did I spend this month?" />
<button id="send-button">Send</button>
</div>
</div>
<script src="script.js"></script>
</body>

</html>
Loading