@@ -43,7 +43,7 @@ def log_print(*args):
4343 print (* args , file = log_stream )
4444 sys .stdout .flush ()
4545
46- # ========== PDF REPORT ======= ===
46+ # === PDF REPORT GENERATOR ===
4747def generate_pdf_report (summary , r2 , mse , forecast_dict ):
4848 c = canvas .Canvas (REPORT_PATH , pagesize = letter )
4949 width , height = letter
@@ -79,13 +79,13 @@ def generate_pdf_report(summary, r2, mse, forecast_dict):
7979 c .drawImage (FORECAST_PLOT_PATH , 1 * inch , 1 * inch , width = 5.5 * inch , preserveAspectRatio = True )
8080 c .save ()
8181
82- # ========== FORECAST PLOT ======= ===
82+ # === PLOT FORECAST (READABLE X) ===
8383def plot_forecast_with_axis (X , y , model , values_parsed , y_future , use_dates ):
8484 x_min , x_max = min (X .min (), values_parsed .min ()), max (X .max (), values_parsed .max ())
8585 x_plot = np .linspace (x_min , x_max , 200 ).reshape (- 1 , 1 )
8686 y_plot = model .predict (x_plot )
8787
88- plt .figure ()
88+ plt .figure (figsize = ( 10 , 5 ) )
8989 plt .scatter (X , y , label = 'Training Data' , alpha = 0.6 )
9090 plt .plot (x_plot , y_plot , color = 'blue' , label = 'Linear Regression' )
9191 plt .scatter (values_parsed , y_future , color = 'red' , label = 'Forecast' , marker = 'x' )
@@ -95,16 +95,15 @@ def plot_forecast_with_axis(X, y, model, values_parsed, y_future, use_dates):
9595 plt .title ('Forecast with Linear Regression' )
9696
9797 if use_dates :
98- ticks = np .linspace (x_min , x_max , 6 )
99- labels = [datetime .fromordinal (int ( t ) ).strftime ('%Y-%m-%d' ) for t in ticks ]
100- plt .xticks (ticks , labels , rotation = 45 )
98+ ticks = np .linspace (x_min , x_max , 6 , dtype = int )
99+ labels = [datetime .fromordinal (t ).strftime ('%Y-%m-%d' ) for t in ticks ]
100+ plt .xticks (ticks , labels , rotation = 45 , ha = 'right' )
101101
102102 plt .tight_layout ()
103103 plt .savefig (FORECAST_PLOT_PATH )
104104 plt .close ()
105105
106- # ========== ROUTES ==========
107-
106+ # === ROUTES ===
108107@app .route ("/get-columns" , methods = ["POST" ])
109108def get_columns ():
110109 file = request .files .get ("file" )
@@ -137,14 +136,16 @@ def upload_file():
137136
138137 df = df [[x_col , y_col ]].dropna ()
139138 df .columns = ['X' , 'Y' ]
140- log_print ("Data Cleaned using Pandas :\n \n Printing Header: \n " , df .head ())
139+ log_print ("Data Cleaned:\n \n " , df .head ())
141140
142- # Plot original data
143- plt .figure ()
141+ # Save scatter plot
142+ plt .figure (figsize = ( 10 , 5 ) )
144143 plt .scatter (df ['X' ], df ['Y' ])
145144 plt .xlabel ('X' )
146145 plt .ylabel ('Y' )
147146 plt .title ('Scatter Plot' )
147+ plt .xticks (rotation = 45 , ha = 'right' )
148+ plt .tight_layout ()
148149 plt .savefig (PLOT_PATH )
149150 plt .close ()
150151
@@ -162,7 +163,7 @@ def upload_file():
162163 y_pred = model .predict (X )
163164 r2 = r2_score (y , y_pred )
164165 mse = mean_squared_error (y , y_pred )
165- log_print (f"\n \n Model Trained with Scikit-Learn: \n R ² = { r2 :.4f} , MSE = { mse :.4f} " )
166+ log_print (f"\n Model Trained: \n R ² = { r2 :.4f} , MSE = { mse :.4f} " )
166167
167168 try :
168169 openai .api_key = os .getenv ("OPENAI_API_KEY" )
@@ -176,9 +177,10 @@ def upload_file():
176177 )
177178 summary = response .choices [0 ].message .content
178179 cached_summary = summary
179- except :
180+ except Exception as e :
180181 summary = "OpenAI summarization failed."
181182 cached_summary = summary
183+ log_print ("OpenAI error:" , str (e ))
182184
183185 return jsonify ({
184186 "summary" : summary ,
@@ -192,19 +194,29 @@ def upload_file():
192194@app .route ("/predict" , methods = ["POST" ])
193195def predict ():
194196 future_x = request .form .get ("future_x" )
195- if not future_x :
196- return jsonify ({"forecast" : "No future values provided." }), 400
197-
198- values = future_x .split ("," )
199- numeric_vals , date_vals = [], []
200- for x in values :
201- try :
202- date_vals .append (datetime .strptime (x .strip (), "%Y-%m-%d" ).toordinal ())
203- except :
204- numeric_vals .append (float (x .strip ()))
205- values_parsed = np .array (date_vals if date_vals else numeric_vals ).reshape (- 1 , 1 )
197+ x_col = request .form .get ("x_column" )
198+ y_col = request .form .get ("y_column" )
199+
200+ if not future_x or not x_col or not y_col :
201+ return jsonify ({"forecast" : "Missing input values or column selection." }), 400
202+
203+ try :
204+ values = future_x .split ("," )
205+ numeric_vals , date_vals = [], []
206+ for x in values :
207+ try :
208+ date_vals .append (datetime .strptime (x .strip (), "%Y-%m-%d" ).toordinal ())
209+ except :
210+ numeric_vals .append (float (x .strip ()))
211+ values_parsed = np .array (date_vals if date_vals else numeric_vals ).reshape (- 1 , 1 )
212+ except Exception as e :
213+ return jsonify ({"forecast" : f"Invalid input: { str (e )} " }), 400
206214
207215 df = pd .read_csv (CSV_CACHE )
216+ if x_col not in df .columns or y_col not in df .columns :
217+ return jsonify ({"forecast" : "Selected columns not found." }), 400
218+
219+ df = df [[x_col , y_col ]].dropna ()
208220 df .columns = ['X' , 'Y' ]
209221 df ['X_date' ] = pd .to_datetime (df ['X' ], errors = 'coerce' )
210222 use_dates = df ['X_date' ].notna ().sum () >= len (df ) // 2
@@ -217,7 +229,6 @@ def predict():
217229
218230 model = LinearRegression ()
219231 model .fit (X , y )
220-
221232 y_future = model .predict (values_parsed )
222233 result = {
223234 datetime .fromordinal (int (x )).strftime ("%Y-%m-%d" ) if use_dates else float (x ): round (p , 2 )
0 commit comments