WebashalarForML commited on
Commit
4e6d72a
·
verified ·
1 Parent(s): 83e0fd9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +174 -180
app.py CHANGED
@@ -4,20 +4,7 @@ import pandas as pd
4
  from werkzeug.utils import secure_filename
5
  from joblib import load
6
  import numpy as np
7
- from sklearn.preprocessing import OneHotEncoder, LabelEncoder
8
- from sklearn.model_selection import train_test_split
9
- from sklearn.preprocessing import StandardScaler
10
- from sklearn.decomposition import PCA
11
- from sklearn.pipeline import Pipeline
12
- from sklearn.tree import DecisionTreeRegressor
13
- from sklearn.ensemble import RandomForestRegressor
14
- from sklearn.linear_model import LinearRegression
15
- from xgboost import XGBRegressor
16
- from sklearn.neighbors import KNeighborsRegressor
17
- from sklearn.model_selection import cross_val_score
18
- from sklearn.metrics import mean_squared_error
19
- from sklearn import metrics
20
- from sklearn.metrics.pairwise import cosine_similarity
21
  from time import time
22
 
23
  app = Flask(__name__)
@@ -29,62 +16,75 @@ app.secret_key = os.urandom(24)
29
  UPLOAD_FOLDER = "uploads/"
30
  DATA_FOLDER = "data/"
31
 
32
- # Define the model directory (ensuring correct path formatting)
33
- MODEL_DIR = r"./Model"
34
- LABEL_ENOCDER_DIR = r'./Label_encoders'
35
 
36
- # Define the output file path
37
- PRED_OUTPUT_FILE = "./data/pred_output.csv"
38
- CLASS_OUTPUT_FILE = "./data/class_output.csv"
39
 
40
  ALLOWED_EXTENSIONS = {'csv', 'xlsx'}
41
 
42
  app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
43
- app.config['DATA_FOLDER'] = DATA_FOLDER
44
-
45
- # Ensure the upload folder exists
46
  os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
47
- os.makedirs(app.config['DATA_FOLDER'], exist_ok=True)
48
-
49
- # Load models using os.path.join for better cross-platform compatibility
50
 
51
- # linear_regression_model
 
 
 
52
  gia_model = load(os.path.join(MODEL_DIR, 'linear_regression_model_gia_price.joblib'))
53
  grade_model = load(os.path.join(MODEL_DIR, 'linear_regression_model_grade_price.joblib'))
54
  bygrade_model = load(os.path.join(MODEL_DIR, 'linear_regression_model_bygrade_price.joblib'))
55
  makable_model = load(os.path.join(MODEL_DIR, 'linear_regression_model_makable_price.joblib'))
56
 
57
- # classifier_model
58
  col_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_col.joblib'))
59
  cts_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_cts.joblib'))
60
  cut_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_cut.joblib'))
61
  qua_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_qua.joblib'))
62
  shp_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_shp.joblib'))
63
 
64
- # print("===================================models==================================")
65
- # print(gia_model)
66
- # print(grade_model)
67
- # print(bygrade_model)
68
- # print(makable_model)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
- # Load label encoders
71
- encoder_list = ['Tag', 'EngShp', 'EngQua', 'EngCol', 'EngCut', 'EngPol', 'EngSym', 'EngFlo', 'EngNts', 'EngMikly', 'EngLab',
72
- 'Change_cts_value', 'Change_shape_value', 'Change_quality_value', 'Change_color_value', 'Change_cut_value']
73
- #loaded_label_encoder = {val: load(f"./Label_encoders/label_encoder_{val}.joblib") for val in encoder_list}
74
  loaded_label_encoder = {}
75
  for val in encoder_list:
76
- #encoder_path = f"H:/DEV PATEL/2025/AI_In_Diamond_Industry/Label_encoders/label_encoder_{val}.joblib"
77
  encoder_path = os.path.join(LABEL_ENOCDER_DIR, f"label_encoder_{val}.joblib")
78
  loaded_label_encoder[val] = load(encoder_path)
79
-
80
- # print(loaded_label_encoder)
81
-
82
- # Ensure upload folder exists
83
- os.makedirs(UPLOAD_FOLDER, exist_ok=True)
84
 
 
 
 
85
  def allowed_file(filename):
86
  return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
87
 
 
 
 
88
  @app.route('/')
89
  def index():
90
  return render_template('index.html')
@@ -105,181 +105,175 @@ def predict():
105
  filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
106
  file.save(filepath)
107
 
108
- # Convert to DataFrame
109
  if filename.endswith('.csv'):
110
  df = pd.read_csv(filepath)
111
  else:
112
  df = pd.read_excel(filepath)
113
 
114
- # Preprocess DataFrame
115
- print("===================================process_dataframe=0==================================")
116
- df,dx = process_dataframe(df)
117
- print("===================================process_dataframe=5==================================")
118
- return render_template('output.html', df=df.to_html(), dx=dx.to_html())
 
 
 
 
 
 
 
 
119
  else:
120
  flash('Invalid file type. Only CSV and Excel files are allowed.', 'error')
121
- print('Invalid file type. Only CSV and Excel files are allowed.')
122
  return redirect(request.url)
123
 
124
  def process_dataframe(df):
125
  try:
126
- print("===================================process_dataframe=1==================================")
127
- # 'EngLab' is not in the required columns
128
- required_columns = ['Tag', 'EngCts', 'EngShp', 'EngQua', 'EngCol', 'EngCut', 'EngPol',
129
- 'EngSym', 'EngFlo', 'EngNts', 'EngMikly', 'EngAmt']
130
-
131
- # for prediction
132
- df = df[required_columns]
133
- df = df.copy()
134
- # for classification
135
 
 
 
 
136
 
137
- # df[col] = df[col].map(lambda x: loaded_label_encoder[col].transform([x])[0] if x in loaded_label_encoder[col].classes_ else np.nan)
138
-
139
- # Transform categorical features using loaded label encoders
140
- df["Tag"] = loaded_label_encoder['Tag'].transform(df["Tag"])
141
- df["EngShp"] = loaded_label_encoder['EngShp'].transform(df["EngShp"])
142
- df["EngQua"] = loaded_label_encoder['EngQua'].transform(df["EngQua"])
143
- df["EngCol"] = loaded_label_encoder['EngCol'].transform(df["EngCol"])
144
- df["EngCut"] = loaded_label_encoder['EngCut'].transform(df["EngCut"])
145
- df["EngPol"] = loaded_label_encoder['EngPol'].transform(df["EngPol"])
146
- df["EngSym"] = loaded_label_encoder['EngSym'].transform(df["EngSym"])
147
- df["EngFlo"] = loaded_label_encoder['EngFlo'].transform(df["EngFlo"])
148
- df["EngNts"] = loaded_label_encoder['EngNts'].transform(df["EngNts"])
149
- df["EngMikly"] = loaded_label_encoder['EngMikly'].transform(df["EngMikly"])
150
- #EngLab = loaded_label_encoder['EngLab'].transform(df[EngLab])
151
-
152
- df=df.astype(float)
153
- print(df.head())
154
-
155
- dx = df.copy()
156
 
157
- print(df.columns)
158
- x= df.copy()
 
159
 
160
- # print("Model expects", gia_model.n_features_in_, "features.")
161
- # print("X_features shape:", x.shape)
 
162
 
163
- print("===================================process_dataframe=2==================================")
 
 
164
 
165
- # ================================================================================================
166
- # Prediction report
167
- # ================================================================================================
 
 
 
 
 
 
 
 
 
 
168
 
169
- # Predict prices
170
- df['GIA_Predicted'] = gia_model.predict(x)
171
- df['Grade_Predicted'] = grade_model.predict(x)
172
- df['ByGrade_Predicted'] = bygrade_model.predict(x)
173
- df['Makable_Predicted'] = makable_model.predict(x)
174
-
175
-
176
- # Compute differences
177
- df['GIA_Diff'] = df['EngAmt'] - df['GIA_Predicted']
178
- df['Grade_Diff'] = df['EngAmt'] - df['Grade_Predicted']
179
- df['ByGrade_Diff'] = df['EngAmt'] - df['ByGrade_Predicted']
180
- df['Makable_Diff'] = df['EngAmt'] - df['Makable_Predicted']
181
-
182
- print(df.head())
183
-
184
- predictions = df.to_dict(orient='records')
185
- analysis = df.describe().to_html()
186
- #print(analysis)
187
- #print(predictions)
188
- print("===================================process_dataframe=3==================================")
189
-
190
- # ================================================================================================
191
- # Classification report
192
- # ================================================================================================
193
-
194
  dx['col_change'] = col_model.predict(x)
195
  dx['cts_change'] = cts_model.predict(x)
196
  dx['cut_change'] = cut_model.predict(x)
197
  dx['qua_change'] = qua_model.predict(x)
198
  dx['shp_change'] = shp_model.predict(x)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
- # Inverse transform the predictions
201
  dx['col_change'] = loaded_label_encoder['Change_color_value'].inverse_transform(dx['col_change'])
202
  dx['cts_change'] = loaded_label_encoder['Change_cts_value'].inverse_transform(dx['cts_change'])
203
  dx['cut_change'] = loaded_label_encoder['Change_cut_value'].inverse_transform(dx['cut_change'])
204
  dx['qua_change'] = loaded_label_encoder['Change_quality_value'].inverse_transform(dx['qua_change'])
205
- dx['shp_change'] = loaded_label_encoder['Change_shape_value'].inverse_transform(dx['shp_change'])
206
-
207
- print(dx.head())
208
-
209
- print("===================================process_dataframe=4==================================")
210
-
211
- # Save output file with date and time
212
- time = str(pd.Timestamp.now().strftime("%Y-%m-%d"))
213
-
214
- #saving the output file
215
- global PRED_OUTPUT_FILE
216
- PRED_OUTPUT_FILE = f'data/prediction_output_{time}.csv'
217
- df.to_csv(PRED_OUTPUT_FILE, index=False)
218
-
219
- #saving the output file
220
- global CLASS_OUTPUT_FILE
221
- CLASS_OUTPUT_FILE = f'data/classification_output_{time}.csv'
222
- dx.to_csv(CLASS_OUTPUT_FILE, index=False)
223
 
224
- print("===================================Output file saved as output.csv===================================")
225
-
226
- return df.head(), dx.head()
227
  except Exception as e:
228
- print(f'Error processing file: {e}')
229
  flash(f'Error processing file: {e}', 'error')
230
  return pd.DataFrame(), pd.DataFrame()
231
-
232
- def classification_report(df):
233
- try:
234
- classifcation_data = df[["EngGraphCts","EngCts","EngShp","EngQua","EngCol","EngCut","EngPol","EngSym","EngFlo","EngNts","EngMikly","EngLab","EngAmt",
235
- "MkblCts","MkblShp","MkblQua","MkblCol","MkblCut","MkblPol","MkblSym","MkblFlo","MkblNts","MkblMikly","MkblLab","MkblAmt"]]
236
-
237
- # Make predictions
238
- classifcation_data["Cts_diff_eng_mkbl"] = round(classifcation_data["EngCts"] - classifcation_data["MkblCts"],2)
239
 
240
- # Create a new column 'Change_Label' based on the values in 'Cts_diff_eng_mkbl'
241
- classifcation_data['Change_cts_value'] = classifcation_data['Cts_diff_eng_mkbl'].apply(
242
- lambda x: str(x)+' negative change' if x < 0 else (str(x)+' positive change' if x > 0 else 'no change')
243
- )
244
-
245
- # Create a new column 'Shape_Change' based on the values in 'EngShp' and 'MkblShp'
246
- classifcation_data['Change_shape_value'] = classifcation_data.apply(
247
- lambda row: str(row['EngShp'])+' to '+str(row['MkblShp'])+' shape change' if row['EngShp'] != row['MkblShp'] else 'shape not change', axis=1
248
- )
249
-
250
- # Create a new column 'quality_Change' based on the values in 'EngQua' and 'MkblQua'
251
- classifcation_data['Change_quality_value'] = classifcation_data.apply(
252
- lambda row: str(row['EngQua'])+' to '+str(row['MkblQua'])+' quality change' if row['EngQua'] != row['MkblQua'] else 'quality not change', axis=1
253
- )
254
-
255
- # Create a new column 'color_Change' based on the values in 'EngCol' and 'MkblCol'
256
- classifcation_data['Change_color_value'] = classifcation_data.apply(
257
- lambda row: str(row['EngCol'])+' to '+str(row['MkblCol'])+' color change' if row['EngCol'] != row['MkblCol'] else 'color not change', axis=1
258
- )
259
-
260
- # Create a new column 'cut_Change' based on the values in 'EngCut' and 'MkblCut'
261
- classifcation_data['Change_cut_value'] = classifcation_data.apply(
262
- lambda row: str(row['EngCut'])+' to '+str(row['MkblCut'])+' cut change' if row['EngCut'] != row['MkblCut'] else 'cut not change', axis=1
263
- )
264
-
265
- # Generate classification report
266
-
267
-
268
- return classifcation_data
269
- except Exception as e:
270
- flash(f'Error generating classification report: {e}', 'error')
271
- print(f'Error generating classification report: {e}')
272
- return None
273
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  @app.route('/download_pred', methods=['GET'])
275
  def download_pred():
276
- """Serve the output.csv file for download."""
277
- return send_file(PRED_OUTPUT_FILE, as_attachment=True)
278
 
279
  @app.route('/download_class', methods=['GET'])
280
  def download_class():
281
- """Serve the output.csv file for download."""
282
- return send_file(CLASS_OUTPUT_FILE, as_attachment=True)
283
 
284
  if __name__ == "__main__":
285
- app.run(debug=True)
 
4
  from werkzeug.utils import secure_filename
5
  from joblib import load
6
  import numpy as np
7
+ from sklearn.preprocessing import LabelEncoder
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  from time import time
9
 
10
  app = Flask(__name__)
 
16
  UPLOAD_FOLDER = "uploads/"
17
  DATA_FOLDER = "data/"
18
 
19
+ # Define the model directory and label encoder directory
20
+ MODEL_DIR = r'.\Model'
21
+ LABEL_ENOCDER_DIR = r'.\Label_encoders'
22
 
23
+ # Global file names for outputs; these will be updated per prediction.
24
+ PRED_OUTPUT_FILE = "data/pred_output.csv"
25
+ CLASS_OUTPUT_FILE = "data/class_output.csv"
26
 
27
  ALLOWED_EXTENSIONS = {'csv', 'xlsx'}
28
 
29
  app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
 
 
 
30
  os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
 
 
 
31
 
32
+ # ------------------------------
33
+ # Load Models and Label Encoders
34
+ # ------------------------------
35
+ # (Loading models code remains unchanged)
36
  gia_model = load(os.path.join(MODEL_DIR, 'linear_regression_model_gia_price.joblib'))
37
  grade_model = load(os.path.join(MODEL_DIR, 'linear_regression_model_grade_price.joblib'))
38
  bygrade_model = load(os.path.join(MODEL_DIR, 'linear_regression_model_bygrade_price.joblib'))
39
  makable_model = load(os.path.join(MODEL_DIR, 'linear_regression_model_makable_price.joblib'))
40
 
 
41
  col_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_col.joblib'))
42
  cts_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_cts.joblib'))
43
  cut_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_cut.joblib'))
44
  qua_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_qua.joblib'))
45
  shp_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_shp.joblib'))
46
 
47
+ blk_eng_to_mkbl_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_mkbl_blk.joblib'))
48
+ wht_eng_to_mkbl_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_mkbl_wht.joblib'))
49
+ open_eng_to_mkbl_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_mkbl_open.joblib'))
50
+ pav_eng_to_mkbl_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_mkbl_pav.joblib'))
51
+ blk_eng_to_grade_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_grade_blk.joblib'))
52
+ wht_eng_to_grade_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_grade_wht.joblib'))
53
+ open_eng_to_grade_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_grade_open.joblib'))
54
+ pav_eng_to_grade_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_grade_pav.joblib'))
55
+ blk_eng_to_bygrade_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_bygrade_blk.joblib'))
56
+ wht_eng_to_bygrade_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_bygrade_wht.joblib'))
57
+ open_eng_to_bygrade_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_bygrade_open.joblib'))
58
+ pav_eng_to_bygrade_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_bygrade_pav.joblib'))
59
+ blk_eng_to_gia_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_gia_blk.joblib'))
60
+ wht_eng_to_gia_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_gia_wht.joblib'))
61
+ open_eng_to_gia_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_gia_open.joblib'))
62
+ pav_eng_to_gia_model = load(os.path.join(MODEL_DIR, 'classification_LogisticRegression_gia_pav.joblib'))
63
+
64
+ encoder_list = ['Tag', 'EngShp', 'EngQua', 'EngCol', 'EngCut', 'EngPol', 'EngSym', 'EngFlo',
65
+ 'EngNts', 'EngMikly', 'EngLab','EngBlk', 'EngWht', 'EngOpen','EngPav',
66
+ 'Change_cts_value', 'Change_shape_value', 'Change_quality_value', 'Change_color_value',
67
+ 'Change_cut_value', 'Change_Blk_Eng_to_Mkbl_value', 'Change_Wht_Eng_to_Mkbl_value',
68
+ 'Change_Open_Eng_to_Mkbl_value', 'Change_Pav_Eng_to_Mkbl_value', 'Change_Blk_Eng_to_Grd_value',
69
+ 'Change_Wht_Eng_to_Grd_value', 'Change_Open_Eng_to_Grd_value', 'Change_Pav_Eng_to_Grd_value',
70
+ 'Change_Blk_Eng_to_ByGrd_value', 'Change_Wht_Eng_to_ByGrd_value', 'Change_Open_Eng_to_ByGrd_value',
71
+ 'Change_Pav_Eng_to_ByGrd_value', 'Change_Blk_Eng_to_Gia_value', 'Change_Wht_Eng_to_Gia_value',
72
+ 'Change_Open_Eng_to_Gia_value', 'Change_Pav_Eng_to_Gia_value']
73
 
 
 
 
 
74
  loaded_label_encoder = {}
75
  for val in encoder_list:
 
76
  encoder_path = os.path.join(LABEL_ENOCDER_DIR, f"label_encoder_{val}.joblib")
77
  loaded_label_encoder[val] = load(encoder_path)
 
 
 
 
 
78
 
79
+ # ------------------------------
80
+ # Utility: Allowed File Check
81
+ # ------------------------------
82
  def allowed_file(filename):
83
  return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
84
 
85
+ # ------------------------------
86
+ # Routes
87
+ # ------------------------------
88
  @app.route('/')
89
  def index():
90
  return render_template('index.html')
 
105
  filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
106
  file.save(filepath)
107
 
108
+ # Convert file to DataFrame
109
  if filename.endswith('.csv'):
110
  df = pd.read_csv(filepath)
111
  else:
112
  df = pd.read_excel(filepath)
113
 
114
+ # Process the DataFrame and generate predictions and classification analysis.
115
+ df_pred, dx_class = process_dataframe(df)
116
+
117
+ # Save output files with a timestamp (you can also store in session if needed)
118
+ current_date = pd.Timestamp.now().strftime("%Y-%m-%d")
119
+ global PRED_OUTPUT_FILE, CLASS_OUTPUT_FILE
120
+ PRED_OUTPUT_FILE = f'data/prediction_output_{current_date}.csv'
121
+ CLASS_OUTPUT_FILE = f'data/classification_output_{current_date}.csv'
122
+ df_pred.to_csv(PRED_OUTPUT_FILE, index=False)
123
+ dx_class.to_csv(CLASS_OUTPUT_FILE, index=False)
124
+
125
+ # Redirect to report view; default to prediction report, page 1.
126
+ return redirect(url_for('report_view', report_type='pred', page=1))
127
  else:
128
  flash('Invalid file type. Only CSV and Excel files are allowed.', 'error')
 
129
  return redirect(request.url)
130
 
131
  def process_dataframe(df):
132
  try:
133
+ # Define the columns needed for two parts
134
+ required_columns = ['Tag', 'EngCts', 'EngShp', 'EngQua', 'EngCol', 'EngCut',
135
+ 'EngPol', 'EngSym', 'EngFlo', 'EngNts', 'EngMikly', 'EngAmt']
136
+ required_columns_2 = required_columns + ['EngBlk', 'EngWht', 'EngOpen', 'EngPav']
 
 
 
 
 
137
 
138
+ # Create two DataFrames: one for prediction and one for classification.
139
+ df_pred = df[required_columns].copy()
140
+ df_class = df[required_columns_2].fillna("NA").copy()
141
 
142
+ # Transform categorical columns for prediction DataFrame using the label encoders.
143
+ for col in ['Tag', 'EngShp', 'EngQua', 'EngCol', 'EngCut', 'EngPol', 'EngSym', 'EngFlo', 'EngNts', 'EngMikly']:
144
+ df_pred[col] = loaded_label_encoder[col].transform(df_pred[col])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
+ # Update the classification DataFrame with the transformed prediction columns.
147
+ for col in ['Tag', 'EngShp', 'EngQua', 'EngCol', 'EngCut', 'EngPol', 'EngSym', 'EngFlo', 'EngNts', 'EngMikly']:
148
+ df_class[col] = df_pred[col]
149
 
150
+ # Transform the extra columns in the classification DataFrame.
151
+ for col in ['EngBlk', 'EngWht', 'EngOpen', 'EngPav']:
152
+ df_class[col] = loaded_label_encoder[col].transform(df_class[col])
153
 
154
+ # Convert both DataFrames to float (or handle as needed).
155
+ df_pred = df_pred.astype(float)
156
+ df_class = df_class.astype(float)
157
 
158
+ # -------------------------
159
+ # Prediction Report Section
160
+ # -------------------------
161
+ # Use the prediction DataFrame for price predictions.
162
+ x = df_pred.copy()
163
+ df_pred['GIA_Predicted'] = gia_model.predict(x)
164
+ df_pred['Grade_Predicted'] = grade_model.predict(x)
165
+ df_pred['ByGrade_Predicted'] = bygrade_model.predict(x)
166
+ df_pred['Makable_Predicted'] = makable_model.predict(x)
167
+ df_pred['GIA_Diff'] = df_pred['EngAmt'] - df_pred['GIA_Predicted']
168
+ df_pred['Grade_Diff'] = df_pred['EngAmt'] - df_pred['Grade_Predicted']
169
+ df_pred['ByGrade_Diff'] = df_pred['EngAmt'] - df_pred['ByGrade_Predicted']
170
+ df_pred['Makable_Diff'] = df_pred['EngAmt'] - df_pred['Makable_Predicted']
171
 
172
+ # -------------------------
173
+ # Classification Report Section
174
+ # -------------------------
175
+ # For classification, use df_class (which has extra columns).
176
+ x2 = df_class.copy()
177
+ dx = df_pred.copy() # Start with the prediction data.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  dx['col_change'] = col_model.predict(x)
179
  dx['cts_change'] = cts_model.predict(x)
180
  dx['cut_change'] = cut_model.predict(x)
181
  dx['qua_change'] = qua_model.predict(x)
182
  dx['shp_change'] = shp_model.predict(x)
183
+ dx['Change_Blk_Eng_to_Mkbl_value'] = blk_eng_to_mkbl_model.predict(x2)
184
+ dx['Change_Wht_Eng_to_Mkbl_value'] = wht_eng_to_mkbl_model.predict(x2)
185
+ dx['Change_Open_Eng_to_Mkbl_value'] = open_eng_to_mkbl_model.predict(x2)
186
+ dx['Change_Pav_Eng_to_Mkbl_value'] = pav_eng_to_mkbl_model.predict(x2)
187
+ dx['Change_Blk_Eng_to_Grd_value'] = blk_eng_to_grade_model.predict(x2)
188
+ dx['Change_Wht_Eng_to_Grd_value'] = wht_eng_to_grade_model.predict(x2)
189
+ dx['Change_Open_Eng_to_Grd_value'] = open_eng_to_grade_model.predict(x2)
190
+ dx['Change_Pav_Eng_to_Grd_value'] = pav_eng_to_grade_model.predict(x2)
191
+ dx['Change_Blk_Eng_to_ByGrd_value'] = blk_eng_to_bygrade_model.predict(x2)
192
+ dx['Change_Wht_Eng_to_ByGrd_value'] = wht_eng_to_bygrade_model.predict(x2)
193
+ dx['Change_Open_Eng_to_ByGrd_value'] = open_eng_to_bygrade_model.predict(x2)
194
+ dx['Change_Pav_Eng_to_ByGrd_value'] = pav_eng_to_bygrade_model.predict(x2)
195
+ dx['Change_Blk_Eng_to_Gia_value'] = blk_eng_to_gia_model.predict(x2)
196
+ dx['Change_Wht_Eng_to_Gia_value'] = wht_eng_to_gia_model.predict(x2)
197
+ dx['Change_Open_Eng_to_Gia_value'] = open_eng_to_gia_model.predict(x2)
198
+ dx['Change_Pav_Eng_to_Gia_value'] = pav_eng_to_gia_model.predict(x2)
199
 
200
+ # Inverse transform classification predictions.
201
  dx['col_change'] = loaded_label_encoder['Change_color_value'].inverse_transform(dx['col_change'])
202
  dx['cts_change'] = loaded_label_encoder['Change_cts_value'].inverse_transform(dx['cts_change'])
203
  dx['cut_change'] = loaded_label_encoder['Change_cut_value'].inverse_transform(dx['cut_change'])
204
  dx['qua_change'] = loaded_label_encoder['Change_quality_value'].inverse_transform(dx['qua_change'])
205
+ dx['shp_change'] = loaded_label_encoder['Change_shape_value'].inverse_transform(dx['shp_change'])
206
+ dx['Change_Blk_Eng_to_Mkbl_value'] = loaded_label_encoder['Change_Blk_Eng_to_Mkbl_value'].inverse_transform(dx['Change_Blk_Eng_to_Mkbl_value'])
207
+ dx['Change_Wht_Eng_to_Mkbl_value'] = loaded_label_encoder['Change_Wht_Eng_to_Mkbl_value'].inverse_transform(dx['Change_Wht_Eng_to_Mkbl_value'])
208
+ dx['Change_Open_Eng_to_Mkbl_value'] = loaded_label_encoder['Change_Open_Eng_to_Mkbl_value'].inverse_transform(dx['Change_Open_Eng_to_Mkbl_value'])
209
+ dx['Change_Pav_Eng_to_Mkbl_value'] = loaded_label_encoder['Change_Pav_Eng_to_Mkbl_value'].inverse_transform(dx['Change_Pav_Eng_to_Mkbl_value'])
210
+ dx['Change_Blk_Eng_to_Grd_value'] = loaded_label_encoder['Change_Blk_Eng_to_Grd_value'].inverse_transform(dx['Change_Blk_Eng_to_Grd_value'])
211
+ dx['Change_Wht_Eng_to_Grd_value'] = loaded_label_encoder['Change_Wht_Eng_to_Grd_value'].inverse_transform(dx['Change_Wht_Eng_to_Grd_value'])
212
+ dx['Change_Open_Eng_to_Grd_value'] = loaded_label_encoder['Change_Open_Eng_to_Grd_value'].inverse_transform(dx['Change_Open_Eng_to_Grd_value'])
213
+ dx['Change_Pav_Eng_to_Grd_value'] = loaded_label_encoder['Change_Pav_Eng_to_Grd_value'].inverse_transform(dx['Change_Pav_Eng_to_Grd_value'])
214
+ dx['Change_Blk_Eng_to_ByGrd_value'] = loaded_label_encoder['Change_Blk_Eng_to_ByGrd_value'].inverse_transform(dx['Change_Blk_Eng_to_ByGrd_value'])
215
+ dx['Change_Wht_Eng_to_ByGrd_value'] = loaded_label_encoder['Change_Wht_Eng_to_ByGrd_value'].inverse_transform(dx['Change_Wht_Eng_to_ByGrd_value'])
216
+ dx['Change_Open_Eng_to_ByGrd_value'] = loaded_label_encoder['Change_Open_Eng_to_ByGrd_value'].inverse_transform(dx['Change_Open_Eng_to_ByGrd_value'])
217
+ dx['Change_Pav_Eng_to_ByGrd_value'] = loaded_label_encoder['Change_Pav_Eng_to_ByGrd_value'].inverse_transform(dx['Change_Pav_Eng_to_ByGrd_value'])
218
+ dx['Change_Blk_Eng_to_Gia_value'] = loaded_label_encoder['Change_Blk_Eng_to_Gia_value'].inverse_transform(dx['Change_Blk_Eng_to_Gia_value'])
219
+ dx['Change_Wht_Eng_to_Gia_value'] = loaded_label_encoder['Change_Wht_Eng_to_Gia_value'].inverse_transform(dx['Change_Wht_Eng_to_Gia_value'])
220
+ dx['Change_Open_Eng_to_Gia_value'] = loaded_label_encoder['Change_Open_Eng_to_Gia_value'].inverse_transform(dx['Change_Open_Eng_to_Gia_value'])
221
+ dx['Change_Pav_Eng_to_Gia_value'] = loaded_label_encoder['Change_Pav_Eng_to_Gia_value'].inverse_transform(dx['Change_Pav_Eng_to_Gia_value'])
 
222
 
223
+ return df_pred, dx.head(len(df_pred)) # Return full DataFrames for pagination later.
 
 
224
  except Exception as e:
 
225
  flash(f'Error processing file: {e}', 'error')
226
  return pd.DataFrame(), pd.DataFrame()
 
 
 
 
 
 
 
 
227
 
228
+ # ------------------------------
229
+ # Report View Route with Pagination & Toggle
230
+ # ------------------------------
231
+ @app.route('/report')
232
+ def report_view():
233
+ # Get query parameters: report_type (pred or class) and page number.
234
+ report_type = request.args.get('report_type', 'pred')
235
+ try:
236
+ page = int(request.args.get('page', 1))
237
+ except ValueError:
238
+ page = 1
239
+ per_page = 15 # records per page
240
+
241
+ # Read the appropriate CSV file.
242
+ if report_type == 'pred':
243
+ df = pd.read_csv(PRED_OUTPUT_FILE)
244
+ else:
245
+ df = pd.read_csv(CLASS_OUTPUT_FILE)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
 
247
+ # Calculate pagination indices.
248
+ start_idx = (page - 1) * per_page
249
+ end_idx = start_idx + per_page
250
+ total_records = len(df)
251
+
252
+ # Slice the DataFrame for the current page.
253
+ df_page = df.iloc[start_idx:end_idx]
254
+ table_html = df_page.to_html(classes="data-table", index=False)
255
+
256
+ # Determine if previous/next pages exist.
257
+ has_prev = page > 1
258
+ has_next = end_idx < total_records
259
+
260
+ return render_template('output.html',
261
+ table_html=table_html,
262
+ report_type=report_type,
263
+ page=page,
264
+ has_prev=has_prev,
265
+ has_next=has_next)
266
+
267
+ # ------------------------------
268
+ # Download Routes (remain unchanged)
269
+ # ------------------------------
270
  @app.route('/download_pred', methods=['GET'])
271
  def download_pred():
272
+ return send_file(PRED_OUTPUT_FILE, as_attachment=True)
 
273
 
274
  @app.route('/download_class', methods=['GET'])
275
  def download_class():
276
+ return send_file(CLASS_OUTPUT_FILE, as_attachment=True)
 
277
 
278
  if __name__ == "__main__":
279
+ app.run(debug=True)