Khor Kean Teng commited on
Commit
a17bdfd
·
1 Parent(s): 2ddf01d

stage for update

Browse files
Files changed (12) hide show
  1. .gitignore +26 -0
  2. LICENSE +21 -0
  3. app.py +103 -0
  4. backend/utils.py +14 -0
  5. data/sample_data.csv +0 -0
  6. data/sample_output.csv +0 -0
  7. git.sh +25 -0
  8. model/model.pkl +3 -0
  9. pages/documentation.py +20 -0
  10. requirements.txt +6 -0
  11. run.sh +2 -0
  12. test.py +17 -0
.gitignore ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python cache files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Jupyter Notebook checkpoints
7
+ .ipynb_checkpoints
8
+
9
+ # Environment variables
10
+ .env
11
+
12
+ # Streamlit specific files
13
+ .streamlit/
14
+
15
+ draft.ipynb
16
+
17
+ # Model files
18
+
19
+ *.h5
20
+
21
+ # Logs
22
+ *.log
23
+
24
+ # Virtual environment
25
+ venv/
26
+ env/
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2025 keanteng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
app.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from backend.utils import *
3
+ import pandas as pd
4
+ from datetime import datetime, timedelta
5
+ import time
6
+ import joblib
7
+ import google.generativeai as genai
8
+ import matplotlib.pyplot as plt
9
+
10
+ # page layout
11
+ st.set_page_config(page_title="Telco Churn Engine", page_icon="🧊", layout="wide")
12
+
13
+ # title
14
+ st.title("Telco Churn Engine")
15
+ st.write("Speed up predicting customer churn in the telecommunications industry. Powered by Generative AI and Job Schedule Function.")
16
+
17
+ # sidebar
18
+ with st.sidebar:
19
+ with st.expander("⏰ Schedule Run (Demo)", expanded=False):
20
+ st.caption("Schedule a run for the app.")
21
+ run_date = st.date_input("Select Date")
22
+ run_time = st.time_input("Select Time")
23
+ countdown_placeholder = st.empty()
24
+ if st.button("Schedule Run", type='secondary'):
25
+ run_datetime = datetime.combine(run_date, run_time)
26
+ # scheduler.add_job(scheduled_task, 'date', run_date=run_datetime)
27
+ st.success(f"App scheduled to run on {run_datetime}.")
28
+
29
+ # Countdown logic
30
+ while True:
31
+ now = datetime.now()
32
+ time_left = run_datetime - now
33
+ if time_left.total_seconds() <= 0:
34
+ countdown_placeholder.write("Scheduled task is running!")
35
+ break
36
+ countdown_placeholder.write(f"Time left: {time_left}")
37
+ time.sleep(1)
38
+
39
+ with st.expander("⚙️ Generative AI", expanded=True):
40
+ st.caption("API token can be obtained at https://aistudio.google.com/.")
41
+ gemini_api = st.text_input("Gemini Token", "", type='password')
42
+ if authenticate_gemini(gemini_api):
43
+ st.success("Gemini API token is valid.")
44
+ else:
45
+ st.error("Gemini API token is invalid.")
46
+
47
+ with st.expander("🗳️ Sample Data Download", expanded=False):
48
+ st.caption("Download sample data for testing.")
49
+ sample_data = load_data("data/sample_data.csv")
50
+ st.download_button("Download Sample Data", sample_data.to_csv(), "sample_data.csv", "text/csv")
51
+
52
+ st.divider()
53
+
54
+ st.caption("MIT License 2025 © Khor Kean Teng, Loong Shih-Wai, Tioh Zi Cong, Yee See Marn")
55
+
56
+
57
+ # main content
58
+ with st.chat_message("assistant", avatar="https://static.vecteezy.com/system/resources/previews/035/010/451/non_2x/bionic-zombie-infusion-design-zombie-cyborg-evolution-icon-vector.jpg"):
59
+ response = st.write("Hello admin! I am Arnold. How can I automate so that you might lost your job?")
60
+ st.caption("If you use predefined data, the file upload step will be hidden.")
61
+ toggle = st.toggle('Use Predefined Data', True)
62
+ data = load_data("data/sample_data.csv")
63
+
64
+ if toggle == False:
65
+ uploaded_file = st.file_uploader("Upload a CSV file", type=["csv"])
66
+ if uploaded_file is not None:
67
+ data = pd.read_csv(uploaded_file)
68
+
69
+ submit = st.button("Execute", type='primary')
70
+
71
+ if submit:
72
+ # show preview in table in expander
73
+ with st.status("Preview Data", expanded=True):
74
+ st.write(data.head())
75
+
76
+ model = joblib.load("model/model.pkl")
77
+ prediction = model.predict(data)
78
+ data["Churn Prediction"] = prediction
79
+
80
+ # count how many churn
81
+ churn_count = data["Churn Prediction"].value_counts()
82
+
83
+ # show prview in table in expander
84
+ with st.status("Prediction", expanded=True):
85
+ st.write("The prediction is done. There are {} churn customers out of the total {} customers.".format(churn_count[1], len(data)))
86
+ st.write(data.head())
87
+
88
+ # plot a pie chart
89
+ with st.status("Churn Pie Chart", expanded=True):
90
+ st.write("The pie chart shows the distribution of churn customers.")
91
+ fig, ax = plt.subplots()
92
+ # resize the pie chart
93
+ fig.set_size_inches(3, 3)
94
+ ax.pie(churn_count, labels=["Churn", "Non-Churn"], autopct='%1.1f%%', startangle=90)
95
+ st.pyplot(fig)
96
+
97
+ with st.status("AI Opinion", expanded=True):
98
+ try:
99
+ ai_model = genai.GenerativeModel("gemini-1.5-flash")
100
+ response = ai_model.generate_content(f"Give some opinions in about 100 word based on the prediction results where there are {churn_count[1]} cases of attrition out of the total {len(data)} number of customers.")
101
+ st.write(response.text)
102
+ except Exception as e:
103
+ st.write("You don't have access to this feature. Please authenticate to use this feature.")
backend/utils.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import google.generativeai as genai
2
+ import pandas as pd
3
+
4
+ def authenticate_gemini(api_key):
5
+ try:
6
+ genai.configure(api_key=api_key)
7
+ ai_model = genai.GenerativeModel("gemini-1.5-flash")
8
+ test = ai_model.generate_content("Explain how AI works")
9
+ return True
10
+ except Exception as e:
11
+ return False
12
+
13
+ def load_data(path):
14
+ return pd.read_csv(path)
data/sample_data.csv ADDED
The diff for this file is too large to render. See raw diff
 
data/sample_output.csv ADDED
The diff for this file is too large to render. See raw diff
 
git.sh ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Get the current commit count
4
+ commit_count=$(git rev-list --count HEAD)
5
+
6
+ # Increment the commit count
7
+ next_commit_count=$((commit_count + 1))
8
+
9
+ # Add all changes
10
+ git add .
11
+
12
+ # Check if a custom message is provided
13
+ if [ -z "$1" ]; then
14
+ commit_message="auto commit #$next_commit_count"
15
+ else
16
+ commit_message="$1 #$next_commit_count"
17
+ fi
18
+
19
+ # Commit with the message
20
+ git commit -m "$commit_message"
21
+
22
+ # Push the changes
23
+ git push
24
+
25
+ # to run ./git_auto.sh "Your custom message"
model/model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:07e0fdb36fa70e97c0bcaeb438056e7bb6d87f82af1df4c262ce1b1ada9c8ff4
3
+ size 193308
pages/documentation.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ st.set_page_config(page_title='Documentation', layout='wide')
4
+
5
+ with st.sidebar:
6
+ with st.expander("⚠️ Disclaimer", expanded=True):
7
+ st.write("This web app is intended for prediction purposes only. The results are based on the input data provided and \
8
+ the performance of the machine learning model. The accuracy of the predictions may vary depending on data quality \
9
+ and model reliability.")
10
+
11
+ st.caption("MIT License 2025 © Khor Kean Teng, Loong Shih-Wai, Tioh Zi Cong, Yee See Marn")
12
+
13
+ st.title("📄 Documentation")
14
+ st.markdown("""
15
+ To learn more about the project, please refer to the sections below.
16
+ """)
17
+ st.subheader("About Telco Churn")
18
+ st.write("""Customer churn is a critical issue in the telecommunications industry. \
19
+ It refers to the percentage of customers who discontinue their services with a company within a given time period.
20
+ The churn rate is a key metric for businesses to measure customer satisfaction and loyalty.""")
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ streamlit
2
+ pandas
3
+ joblib
4
+ scikit-learn==1.3.1
5
+ google-generativeai
6
+ matplotlib
run.sh ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # only work if use python 3.12 on bash shell
2
+ py -3.12 -m streamlit run app.py
test.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import joblib
2
+ import pandas as pd
3
+
4
+ # Load the model
5
+ model = joblib.load('model/model.pkl')
6
+
7
+ # Load the data
8
+ data = pd.read_csv('data/sample_data.csv')
9
+
10
+ # Make predictions
11
+ predictions = model.predict(data)
12
+
13
+ # save the predictions
14
+ data['Churn'] = predictions
15
+
16
+ # save as sample_output.csv
17
+ data.to_csv('data/sample_output.csv', index=False)