yoursdvniel commited on
Commit
977039f
1 Parent(s): 536d413

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +67 -97
main.py CHANGED
@@ -5,6 +5,7 @@ import io
5
  from flask import Flask, request, jsonify
6
  from flask_cors import CORS, cross_origin
7
  import firebase_admin
 
8
  from firebase_admin import credentials, firestore
9
  from dotenv import load_dotenv
10
  from pandasai import SmartDatalake
@@ -93,130 +94,99 @@ def marketing_rec():
93
 
94
  return jsonify(str(response['text']))
95
 
96
- # Profit/Customer Engagement Prediction endpoint
97
  @app.route("/predict_metric", methods=["POST"])
98
  @cross_origin()
99
  def predict_metric():
100
  try:
101
  request_data = request.json
 
 
102
  user_id = request_data.get("user_id")
103
  interval = request_data.get("interval", 30)
104
  metric_type = request_data.get("metric_type", "Profit") # "Profit" or "Customer Engagement"
105
 
106
- # Log received request data
107
- print("Received request:", request_data)
 
 
108
 
109
  transactions_ref = db.collection("system_users").document(user_id).collection("transactions")
110
  data = []
111
 
 
112
  if metric_type == "Profit":
113
- try:
114
- # Fetch both Income and Expense transactions for Profit calculation
115
- income_query = transactions_ref.where("transactionType", "==", "Income").stream()
116
- expense_query = transactions_ref.where("transactionType", "==", "Expense").stream()
117
-
118
- income_data = {}
119
- expense_data = {}
120
-
121
- for doc in income_query:
122
- transaction = doc.to_dict()
123
- date_str = transaction["date"].toDate() # Convert Firestore Timestamp to DateTime
124
- amount = transaction["amountDue"]
125
- income_data[date_str] = income_data.get(date_str, 0) + amount
126
- print(f"Income transaction - Date: {date_str}, Amount: {amount}")
127
-
128
- for doc in expense_query:
129
- transaction = doc.to_dict()
130
- date_str = transaction["date"].toDate() # Convert Firestore Timestamp to DateTime
131
- amount = transaction["amountDue"]
132
- expense_data[date_str] = expense_data.get(date_str, 0) + amount
133
- print(f"Expense transaction - Date: {date_str}, Amount: {amount}")
134
-
135
- # Calculate net profit for each date
136
- for date, income in income_data.items():
137
- expense = expense_data.get(date, 0)
138
- data.append({"date": date, "amountDue": income - expense})
139
-
140
- except Exception as e:
141
- print("Error processing Profit data:", str(e))
142
- return jsonify({"error": "Error processing Profit data"}), 500
143
 
144
  elif metric_type == "Customer Engagement":
145
- try:
146
- # Use count of Income transactions per day as Customer Engagement
147
- income_query = transactions_ref.where("transactionType", "==", "Income").stream()
148
-
149
- engagement_data = {}
150
- for doc in income_query:
151
- transaction = doc.to_dict()
152
- date_str = transaction["date"].toDate() # Convert Firestore Timestamp to DateTime
153
- engagement_data[date_str] = engagement_data.get(date_str, 0) + 1
154
- print(f"Engagement transaction - Date: {date_str}")
155
-
156
- for date, count in engagement_data.items():
157
- data.append({"date": date, "amountDue": count})
158
-
159
- except Exception as e:
160
- print("Error processing Customer Engagement data:", str(e))
161
- return jsonify({"error": "Error processing Customer Engagement data"}), 500
162
-
163
- # Create DataFrame from the aggregated data
164
- try:
165
- df = pd.DataFrame(data)
166
- print("Data before processing:", df)
167
 
168
- # Ensure 'date' column is datetime
169
- df['date'] = pd.to_datetime(df['date'], errors='coerce')
170
- df['date'] = df['date'].dt.tz_localize(None)
 
 
171
 
172
- # Drop rows where 'date' could not be parsed
173
- df = df.dropna(subset=['date'])
174
 
175
- # Set 'date' as index
176
- df = df.sort_values("date").set_index("date")
177
 
178
- # Resample daily to ensure regular intervals (fill missing dates)
179
- df = df.resample("D").sum().reset_index()
180
- print("Data after resampling:", df)
 
 
 
 
181
 
182
- df.columns = ["ds", "y"] # ds: date, y: target
 
 
 
183
 
184
- # Check if there's enough data to train the model
185
- if df.shape[0] < 10:
186
- print("Not enough data for prediction")
187
- return jsonify({"error": "Not enough data for prediction"}), 400
188
 
189
- except Exception as e:
190
- print("Error processing DataFrame:", str(e))
191
- return jsonify({"error": "Error processing DataFrame"}), 500
192
 
193
- # Prophet prediction
194
- try:
195
- # Initialize and fit the Prophet model
196
- model = Prophet(daily_seasonality=True, yearly_seasonality=True)
197
- model.fit(df)
198
-
199
- # DataFrame for future predictions
200
- future_dates = model.make_future_dataframe(periods=interval)
201
- forecast = model.predict(future_dates)
202
-
203
- # Extract the forecast for the requested interval
204
- forecast_data = forecast[['ds', 'yhat']].tail(interval)
205
- predictions = [{"date": row['ds'].strftime('%Y-%m-%d'), "value": row['yhat']} for _, row in forecast_data.iterrows()]
206
 
207
- # Log the predictions before returning
208
- print("Predictions:", predictions)
209
-
210
- # Return predictions in JSON format
211
- return jsonify({"predictedData": predictions})
212
-
213
- except Exception as e:
214
- print("Error in Prophet prediction:", str(e))
215
- return jsonify({"error": "Error in Prophet prediction"}), 500
216
 
217
  except Exception as e:
218
- print("General error:", str(e))
219
- return jsonify({"error": "Internal server error"}), 500
 
220
 
221
 
222
 
 
5
  from flask import Flask, request, jsonify
6
  from flask_cors import CORS, cross_origin
7
  import firebase_admin
8
+ import logging
9
  from firebase_admin import credentials, firestore
10
  from dotenv import load_dotenv
11
  from pandasai import SmartDatalake
 
94
 
95
  return jsonify(str(response['text']))
96
 
 
97
  @app.route("/predict_metric", methods=["POST"])
98
  @cross_origin()
99
  def predict_metric():
100
  try:
101
  request_data = request.json
102
+ logging.info(f"Received request data: {request_data}")
103
+
104
  user_id = request_data.get("user_id")
105
  interval = request_data.get("interval", 30)
106
  metric_type = request_data.get("metric_type", "Profit") # "Profit" or "Customer Engagement"
107
 
108
+ # Check if user_id is provided
109
+ if not user_id:
110
+ logging.error("User ID is missing in the request")
111
+ return jsonify({"error": "User ID is missing"}), 400
112
 
113
  transactions_ref = db.collection("system_users").document(user_id).collection("transactions")
114
  data = []
115
 
116
+ # Fetch Income and Expense for Profit calculation
117
  if metric_type == "Profit":
118
+ income_query = transactions_ref.where("transactionType", "==", "Income").stream()
119
+ expense_query = transactions_ref.where("transactionType", "==", "Expense").stream()
120
+
121
+ income_data = {}
122
+ expense_data = {}
123
+
124
+ for doc in income_query:
125
+ transaction = doc.to_dict()
126
+ logging.info(f"Processing income transaction: {transaction}")
127
+ date_str = transaction["date"]
128
+ amount = transaction["amountDue"]
129
+ income_data[date_str] = income_data.get(date_str, 0) + amount
130
+
131
+ for doc in expense_query:
132
+ transaction = doc.to_dict()
133
+ logging.info(f"Processing expense transaction: {transaction}")
134
+ date_str = transaction["date"]
135
+ amount = transaction["amountDue"]
136
+ expense_data[date_str] = expense_data.get(date_str, 0) + amount
137
+
138
+ for date, income in income_data.items():
139
+ expense = expense_data.get(date, 0)
140
+ data.append({"date": date, "amountDue": income - expense})
 
 
 
 
 
 
 
141
 
142
  elif metric_type == "Customer Engagement":
143
+ income_query = transactions_ref.where("transactionType", "==", "Income").stream()
144
+ engagement_data = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
+ for doc in income_query:
147
+ transaction = doc.to_dict()
148
+ logging.info(f"Processing engagement transaction: {transaction}")
149
+ date_str = transaction["date"]
150
+ engagement_data[date_str] = engagement_data.get(date_str, 0) + 1
151
 
152
+ for date, count in engagement_data.items():
153
+ data.append({"date": date, "amountDue": count})
154
 
155
+ # Log final aggregated data before processing
156
+ logging.info(f"Aggregated data: {data}")
157
 
158
+ # Data processing with Prophet
159
+ df = pd.DataFrame(data)
160
+ df['date'] = pd.to_datetime(df['date'])
161
+ df['date'] = df['date'].dt.tz_localize(None)
162
+ df = df.sort_values("date").set_index("date")
163
+ df = df.resample("D").sum().reset_index()
164
+ df.columns = ["ds", "y"]
165
 
166
+ # Check if data is sufficient
167
+ if df.shape[0] < 10:
168
+ logging.warning("Not enough data to train the Prophet model")
169
+ return jsonify({"error": "Not enough data for prediction"}), 400
170
 
171
+ # Train Prophet model
172
+ model = Prophet(daily_seasonality=True, yearly_seasonality=True)
173
+ model.fit(df)
 
174
 
175
+ # Make future predictions
176
+ future_dates = model.make_future_dataframe(periods=interval)
177
+ forecast = model.predict(future_dates)
178
 
179
+ # Prepare and log predictions
180
+ forecast_data = forecast[['ds', 'yhat']].tail(interval)
181
+ predictions = [{"date": row['ds'].strftime('%Y-%m-%d'), "value": row['yhat']} for _, row in forecast_data.iterrows()]
182
+ logging.info(f"Predictions: {predictions}")
 
 
 
 
 
 
 
 
 
183
 
184
+ return jsonify({"predictedData": predictions})
 
 
 
 
 
 
 
 
185
 
186
  except Exception as e:
187
+ logging.error(f"Error in /predict_metric endpoint: {e}")
188
+ return jsonify({"error": str(e)}), 500
189
+
190
 
191
 
192