File size: 6,991 Bytes
b54df69
 
1798d16
771a15e
 
b54df69
 
 
 
 
 
 
 
 
 
 
 
d6e934d
 
b54df69
 
 
 
 
 
 
 
 
 
 
 
d6e934d
b54df69
 
 
 
 
d6e934d
 
 
b54df69
d6e934d
b54df69
 
 
d6e934d
 
b54df69
 
 
 
d6e934d
 
 
 
b54df69
d6e934d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2532ae2
 
bbfaf4f
 
771a15e
 
2532ae2
 
 
bbfaf4f
d6e934d
b54df69
 
 
 
 
 
 
 
 
c7fc47a
 
 
 
 
 
 
 
 
 
 
 
 
 
b54df69
 
 
771a15e
 
d6e934d
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import streamlit as st
import pandas as pd
import requests
from datetime import datetime
from transformers import AutoTokenizer, AutoModelForTableQuestionAnswering

class InterestCalculatorApp:
    def __init__(self):
        self.invoices_df = None
        self.base_rates_df = None
        self.late_payment_interest = st.sidebar.slider("Late Payment Interest Rate (%)", min_value=0.0, max_value=10.0, value=4.0)
        self.compounding_method = st.sidebar.selectbox("Compounding Method", ["x% above Base Rate (daily)", 
                                                                            "x% above Base Rate (annually)",
                                                                             "Quarterly compounding (25 Mar, 24 Jun, 29 Sep, 25 Dec)",
                                                                             "Quarterly compounding (1 Mar, 1 Jun, 1 Sep, 1 Dec)"])

        # Load TAPAS model
        self.tokenizer = AutoTokenizer.from_pretrained("google/tapas-large-finetuned-wtq")
        self.model = AutoModelForTableQuestionAnswering.from_pretrained("google/tapas-large-finetuned-wtq")

    def load_invoices(self, file_path):
        try:
            self.invoices_df = pd.read_excel(file_path, parse_dates=['Due Date'])
            st.success("Invoices loaded successfully.")
        except Exception as e:
            st.error(f"Failed to load invoices: {e}")

    def calculate_interest(self):
        if self.invoices_df is not None and self.base_rates_df is not None:
            st.write("Calculating interest...")
            today = datetime.today()
            interests = []
            for index, invoice in self.invoices_df.iterrows():
                due_date = invoice['Due Date']
                amount = invoice['Amount']
                base_rate = self.get_base_rate(due_date)
                effective_rate = base_rate + self.late_payment_interest
                if due_date > today:
                    interests.append(0)
                    continue
                interest = self.calculate_compound_interest(due_date, amount, effective_rate, self.compounding_method, today)
                interests.append(interest)
                total_amount_owed = amount + interest
                self.invoices_df.loc[index, 'Interest'] = interest
                self.invoices_df.loc[index, 'Total Amount Owed'] = total_amount_owed
            total_interest = sum(interests)
            st.success(f"Total Interest Calculated: £{total_interest:.2f}")
            st.write(self.invoices_df)
        else:
            st.error("Please load both invoices and base rates files.")

    def get_base_rate(self, due_date):
        self.base_rates_df['Date Changed'] = pd.to_datetime(self.base_rates_df['Date Changed'])
        rate_rows = self.base_rates_df[self.base_rates_df['Date Changed'] <= due_date].sort_values(by='Date Changed', ascending=False)
        return rate_rows.iloc[0]['Rate'] if not rate_rows.empty else 0

    def calculate_compound_interest(self, due_date, amount, effective_rate, method, today):
        days = (today - due_date).days
        if 'daily' in method:
            daily_rate = (effective_rate / 100) / 365
            return amount * daily_rate * days
        elif 'annually' in method:
            annual_rate = effective_rate / 100
            return amount * annual_rate * (days / 365)
        elif 'Quarterly compounding' in method:
            return self.calculate_quarterly_interest(due_date, amount, effective_rate, method, today)

    def calculate_quarterly_interest(self, due_date, amount, effective_rate, method, today):
        quarterly_dates = {
            "Quarterly compounding (25 Mar, 24 Jun, 29 Sep, 25 Dec)": [(3, 25), (6, 24), (9, 29), (12, 25)],
            "Quarterly compounding (1 Mar, 1 Jun, 1 Sep, 1 Dec)": [(3, 1), (6, 1), (9, 1), (12, 1)]
        }[method]
        interest = 0
        compounded_amount = amount
        for month, day in quarterly_dates:
            compounding_date = datetime(today.year, month, day)
            if compounding_date > today:
                break
            if compounding_date > due_date:
                days_since_last_compounding = (today - compounding_date).days
                period_rate = effective_rate / 4  # Quarterly rate
                compounded_interest = compounded_amount * ((1 + period_rate) ** (days_since_last_compounding / 365.25) - 1)
                compounded_amount += compounded_interest
                interest += compounded_interest
                due_date = compounding_date
        return interest

    def download_boe_rates(self):
        try:
            headers = {
                'accept-language': 'en-US,en;q=0.9',
                'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'
            }
            url = 'https://www.bankofengland.co.uk/boeapps/database/Bank-Rate.asp'
            response = requests.get(url, headers=headers)
            if response.status_code == 200:
                df = pd.read_html(response.text)[0]
                df.to_csv('boe_rates.csv', index=False)
                self.base_rates_df = df
                self.base_rates_df['Date Changed'] = pd.to_datetime(self.base_rates_df['Date Changed'], format='%d %b %y')
                st.success("Bank of England rates downloaded successfully.")
            else:
                st.error("Failed to retrieve data from the Bank of England website.")
        except requests.RequestException as e:
            st.error(f"Failed to download rates: {e}")

    def ask_tapas(self, query, table):
        if isinstance(table, pd.DataFrame):
            tokenized_query = self.tokenizer.tokenize(query)
            tokenized_table = [[self.tokenizer.tokenize(str(cell)) for cell in row] for row in table.values]

            inputs = self.tokenizer(table=tokenized_table, queries=[tokenized_query], return_tensors="pt", padding=True)
            return inputs
        else:
            raise TypeError("Table must be of type pd.DataFrame")

def main():
    st.title("Interest Calculation App")

    app = InterestCalculatorApp()

    file_path = st.file_uploader("Upload Invoices File", type=["xlsx"])

    if file_path is not None:
        app.load_invoices(file_path)

    query = st.text_input("Enter your query:")
    if query:
        # Assuming you have a DataFrame named 'invoices_df' containing the invoice data
        if not app.invoices_df.empty:
            # Display the invoice data
            st.write("Invoice Data:")
            st.write(app.invoices_df)

            # Call TAPAS model to answer user's query
            answer = app.ask_tapas(query, app.invoices_df)
            st.write("Answer:", answer)
        else:
            st.warning("Please upload the invoices file first.")

    if st.button("Calculate Interest"):
        app.calculate_interest()

    app.download_boe_rates()

if __name__ == "__main__":
    main()