Edgar Garcia commited on
Commit
b36e1d2
·
unverified ·
1 Parent(s): 870a315

transferring files from spendtracker

Browse files
Files changed (5) hide show
  1. LLM_openai.py +31 -0
  2. app.py +102 -0
  3. dataframe_processing.py +42 -0
  4. utils.py +70 -0
  5. vision_api_call.py +61 -0
LLM_openai.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai import OpenAI
2
+ import os
3
+ my_key = os.environ.get('MY_OPENAI_KEY')
4
+ client = OpenAI(
5
+ api_key= my_key
6
+ )
7
+
8
+ def expense_classifier(expense):
9
+ chat_completion = client.chat.completions.create(
10
+ messages=[
11
+ { "role": "system",
12
+ "content": [
13
+ {
14
+ "type": "text",
15
+ "text": """You are a helpful personal finance assistant.
16
+ The user will input some expense concept and you will classify it in a broader category from the following:
17
+ [alcohol, food, restaurant, clothing, entertainment, transport, sports, wellbeing, personal_development,others]
18
+ Provide only the category as an answer
19
+ """
20
+ }
21
+ ]
22
+ },
23
+ {
24
+ "role": "user",
25
+ "content": expense,
26
+ }
27
+ ],
28
+ model="gpt-4o-mini",
29
+ temperature=0
30
+ )
31
+ return chat_completion.choices[0].message.content
app.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import os
3
+ import gspread
4
+ import gradio as gr
5
+ import datetime
6
+ import pandas as pd
7
+ import matplotlib
8
+ matplotlib.use('Agg')
9
+ import matplotlib.pyplot as plt
10
+ from LLM_openai import client, expense_classifier
11
+ from utils import create_plot, create_barplot
12
+ from dataframe_processing import dataframe_process
13
+ from vision_api_call import process_image
14
+
15
+ #connect to the service account
16
+ gc = gspread.service_account(filename="spend_tracker_creds.json")
17
+ #connect to your sheet (between "" = the name of your G Sheet, keep it short)
18
+ spreadsheet = gc.open("spend_tracker").sheet1
19
+
20
+ def update_spend_from_image(img):
21
+ ##This processes the image
22
+ extracted_dictionay_from_image=process_image(img)
23
+ total_from_receipt=extracted_dictionay_from_image['total']
24
+ concept_from_receipt=extracted_dictionay_from_image['purchase_summary']
25
+ shop_type=extracted_dictionay_from_image['store_type']
26
+ shop_name=extracted_dictionay_from_image['store']
27
+ receipt_items=str(extracted_dictionay_from_image['items'])
28
+
29
+ concept_and_shop=concept_from_receipt+" from "+shop_type+f" ({shop_name})"
30
+
31
+ ##The function update_spend in the line below only takes a string and float
32
+ category, day_month, todays_amount, current_week_amount , fig, fig2, fig3=update_spend(concept_and_shop, total_from_receipt, receipt_items)
33
+
34
+ return category, day_month, todays_amount, current_week_amount , fig, fig2, fig3
35
+
36
+
37
+
38
+ def update_spend(concept, amount, items_from_receipt=None):
39
+ category=expense_classifier(concept)
40
+ today = datetime.date.today()
41
+
42
+ # Append a new row
43
+ spreadsheet.append_row([str(today), concept,float(amount),category, items_from_receipt ])
44
+
45
+ day_month, todays_amount, current_week_amount , fig, fig2, fig3=dataframe_process(spreadsheet)
46
+ return category, day_month, todays_amount, current_week_amount , fig, fig2, fig3
47
+
48
+ def show_plots():
49
+ category='N/A'
50
+ today = 'N/A'
51
+
52
+ # Append a new row
53
+ # spreadsheet.append_row([str(today), concept,float(amount),category, items_from_receipt ])
54
+
55
+ day_month, todays_amount, current_week_amount , fig, fig2, fig3=dataframe_process(spreadsheet)
56
+ return category, day_month, todays_amount, current_week_amount , fig, fig2, fig3
57
+
58
+
59
+
60
+
61
+ with gr.Blocks() as demo:
62
+ gr.Markdown("Expense tracker")
63
+
64
+ with gr.Tab("Manual input"):
65
+ with gr.Row():
66
+ concept = gr.Textbox(label="concept")
67
+ with gr.Row():
68
+ amount= gr.Textbox(label="amount")
69
+ btn_manual = gr.Button("Submit expense")
70
+
71
+ with gr.Tab("Upload receipt"):
72
+ with gr.Row():
73
+ input_image = gr.Image( type="pil")
74
+ btn_image = gr.Button("Submit expense")
75
+
76
+
77
+
78
+
79
+
80
+ with gr.Row():
81
+ btn_show = gr.Button("Show plots")
82
+
83
+ with gr.Row():
84
+ expense_class= gr.Textbox(label='expense class')
85
+ ui_date=gr.Textbox(label='date')
86
+ expenses_today= gr.Textbox(label='expenses today')
87
+ expenses_this_week= gr.Textbox(label='expenses this week')
88
+ with gr.Row():
89
+ daily_plot=gr.Plot(label=None)
90
+ week_plot=gr.Plot()
91
+ category_plot=gr.Plot()
92
+
93
+
94
+ btn_manual.click(fn=update_spend, inputs=[concept, amount], outputs=[expense_class,ui_date, expenses_today,expenses_this_week,
95
+ daily_plot,week_plot,category_plot])
96
+ btn_image.click(fn=update_spend_from_image, inputs=[input_image], outputs=[expense_class,ui_date, expenses_today,expenses_this_week,
97
+ daily_plot,week_plot,category_plot])
98
+ btn_show.click(fn=show_plots, inputs=[], outputs=[expense_class,ui_date, expenses_today,expenses_this_week,
99
+ daily_plot,week_plot,category_plot])
100
+
101
+
102
+ demo.launch()
dataframe_processing.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import re
3
+ from utils import create_plot, create_barplot
4
+
5
+ def dataframe_process(sheet):
6
+ # Create dataframe
7
+ df = pd.DataFrame(sheet.get_all_records())
8
+ df['date'] = pd.to_datetime(df['date'])
9
+ df['week'] = df['date'].dt.to_period('W')
10
+
11
+ #Per day
12
+ daily_total=df[['concept','amount','category','date']].groupby('date').sum().reset_index()
13
+ daily_total['month_day'] = daily_total['date'].dt.strftime('%m-%d')
14
+
15
+
16
+
17
+ fig = create_plot(daily_total['month_day'],daily_total['amount'])
18
+
19
+ daily_total=daily_total.sort_values(by='date', ascending=False)
20
+ daily_total=daily_total[['date', 'amount']]
21
+ todays_amount=daily_total.iloc[0]['amount']
22
+ todays_date=daily_total.iloc[0]['date']
23
+ day_month = todays_date.strftime('%m-%d-%Y')
24
+
25
+ #Per week
26
+ # Group by 'week' and sum the values
27
+ weekly_df = df[['concept','amount','category','week']].groupby('week').sum().reset_index()
28
+ weekly_df=weekly_df.sort_values(by='week', ascending=True)
29
+ # weekly_df.index=weekly_df.index.strftime('%m-%d')
30
+ current_week_amount="{:.2f}".format(weekly_df.iloc[-1]['amount'])
31
+ weekly_df['week'] = weekly_df['week'].astype(str)
32
+ weekly_df['week']=weekly_df['week'].apply(lambda x: re.sub(r'\d{4}-', '', x))
33
+
34
+ fig2 = create_barplot(weekly_df['week'],weekly_df['amount'],"week","amount","expense per week")
35
+
36
+
37
+ #Per category
38
+ expenses_per_category=df[['concept','amount','category']].groupby('category').sum().reset_index()
39
+ expenses_per_category=expenses_per_category.sort_values(by='amount', ascending=False)
40
+ fig3 = create_barplot(expenses_per_category['category'],expenses_per_category['amount'],"category","amount","expense per category")
41
+
42
+ return day_month, todays_amount, current_week_amount , fig, fig2, fig3
utils.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import matplotlib.pyplot as plt
2
+ from LLM_openai import client, expense_classifier
3
+ import datetime
4
+ import base64
5
+ from io import BytesIO
6
+ import re
7
+ import json
8
+ import matplotlib.dates as mdates
9
+
10
+ def create_plot(x, y):
11
+ fig, ax = plt.subplots()
12
+ ax.plot(x, y, marker='o')
13
+ for i in range(len(x)):
14
+ ax.text(x[i], y[i], f'{y[i]:.2f}', fontsize=10, ha='left', va='bottom')
15
+ ax.set_xlabel('Money')
16
+ ax.set_ylabel('Expenses')
17
+ ax.set_title('Daily expenses')
18
+ ax.set_xticks(x[::5]) # Show every 5th day
19
+ ax.set_xticklabels(x[::5], rotation=45, ha='right')
20
+ plt.xticks(rotation=30)
21
+ return fig
22
+
23
+
24
+ def create_barplot(x, y, xlabel,ylabel, title):
25
+ fig, ax = plt.subplots()
26
+ ax.bar(x, y)
27
+ for i in range(len(x)):
28
+ ax.text(x[i], y[i], f'{y[i]:.2f}', fontsize=10, ha='left', va='bottom')
29
+ ax.set_xlabel(xlabel)
30
+ ax.set_ylabel(ylabel)
31
+ ax.set_title(title)
32
+ plt.xticks(rotation=30)
33
+ return fig
34
+
35
+
36
+ ####
37
+ ##OCR functions
38
+
39
+
40
+
41
+ def pil_to_base64(pil_img):
42
+ img_buffer = BytesIO()
43
+ pil_img.save(img_buffer, format='JPEG')
44
+ byte_data = img_buffer.getvalue()
45
+ base64_str = base64.b64encode(byte_data).decode("utf-8")
46
+ return base64_str
47
+
48
+ def js_to_prefere_the_back_camera_of_mobilephones():
49
+ custom_html = """
50
+ <script>
51
+ const originalGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
52
+
53
+ navigator.mediaDevices.getUserMedia = (constraints) => {
54
+ if (!constraints.video.facingMode) {
55
+ constraints.video.facingMode = {ideal: "environment"};
56
+ }
57
+ return originalGetUserMedia(constraints);
58
+ };
59
+ </script>
60
+ """
61
+ return custom_html
62
+
63
+ def result_cleaner(text):
64
+ pattern = r'\{[^}]*\}'
65
+ match = re.search(pattern, text)
66
+ match_string=match[0]
67
+ json_dict=json.loads(match_string)
68
+
69
+
70
+ return json_dict
vision_api_call.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai import OpenAI
2
+ import os
3
+ import base64
4
+ from io import BytesIO
5
+ from PIL import Image
6
+ from utils import pil_to_base64, result_cleaner
7
+
8
+
9
+ my_key = os.environ.get('MY_OPENAI_KEY')
10
+ client = OpenAI(
11
+ api_key= my_key
12
+ )
13
+
14
+ prompt="""
15
+
16
+ You'll be analyzing purchase receipts you will extract the following information:
17
+ -date: date of the purchase in the format YYYY-MM-DD
18
+ -Store: Name of the store where items or services were purchased
19
+ -Store_type: Type of store (supermarket, restaurant, bookstore, etc)
20
+ -Purchase_summary: in maximum 5 words summarize the purchase (cleaning products, breakfast, books, food items for home, online services, clothes ,etc)
21
+ -items: create a list of all the items in the receipt
22
+ -total: total amount spent
23
+
24
+ Provide your answer in a dictionary like the following
25
+ {{date: "xxxx-xx-xx"
26
+ store: "example store",
27
+ store_type: "supermarket",
28
+ purchase_summary: "food items for home",
29
+ items: "xxxx, xxxx, xxx"
30
+ total: xxxx }}
31
+ """
32
+
33
+
34
+ def analyse_image(processed_image):
35
+ #
36
+ response = client.chat.completions.create(
37
+ model="gpt-4o-mini",
38
+ messages=[
39
+ {
40
+ "role": "user",
41
+ "content": [
42
+ {
43
+ "type": "text",
44
+ "text": prompt,
45
+ },
46
+ {
47
+ "type": "image_url",
48
+ "image_url": {"url": f"data:image/jpeg;base64,{processed_image}"},
49
+ },
50
+ ],
51
+ }
52
+ ],
53
+ )
54
+ return response.choices[0].message.content
55
+
56
+ def process_image(img):
57
+ image_base64=pil_to_base64(img)
58
+ analysis_result=analyse_image(image_base64)
59
+ clean_analysis_result=result_cleaner(analysis_result)
60
+
61
+ return clean_analysis_result