reconnect moved files to git repo
This commit is contained in:
202
app.py
Executable file
202
app.py
Executable file
@ -0,0 +1,202 @@
|
||||
from flask import Flask, request, render_template, session
|
||||
from werkzeug.utils import secure_filename
|
||||
from models.time_series import process_time_series
|
||||
from models.plotting import create_comparison_plot
|
||||
from utils.file_handling import allowed_file, read_file, save_processed_file
|
||||
from utils.forecast_history import update_forecast_history, download_forecast_history
|
||||
import os
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['UPLOAD_FOLDER'] = 'Uploads'
|
||||
app.config['ALLOWED_EXTENSIONS'] = {'csv', 'xls', 'xlsx'}
|
||||
app.secret_key = 'your-secret-key' # Required for session management
|
||||
|
||||
# Ensure upload folder exists
|
||||
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
|
||||
@app.route('/upload', methods=['POST'])
|
||||
def upload_file():
|
||||
if 'file' not in request.files:
|
||||
return render_template('index.html', error='No file part')
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return render_template('index.html', error='No selected file')
|
||||
|
||||
if file and allowed_file(file.filename):
|
||||
filename = secure_filename(file.filename)
|
||||
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||
file.save(filepath)
|
||||
session['filepath'] = filepath # Store filepath in session
|
||||
session['forecast_history'] = [] # Initialize forecast history
|
||||
session['selected_indices'] = [] # Initialize selected indices
|
||||
|
||||
# Get user selections
|
||||
do_decomposition = 'decomposition' in request.form
|
||||
do_forecasting = 'forecasting' in request.form
|
||||
do_acf_pacf = 'acf_pacf' in request.form
|
||||
train_percent = float(request.form.get('train_percent', 80)) / 100
|
||||
test_percent = float(request.form.get('test_percent', 20)) / 100
|
||||
forecast_periods = int(request.form.get('forecast_periods', 12))
|
||||
model_type = request.form.get('model_type', 'ARIMA')
|
||||
|
||||
# Validate train/test percentages
|
||||
if abs(train_percent + test_percent - 1.0) > 0.01: # Allow small float precision errors
|
||||
return render_template('index.html', error='Train and test percentages must sum to 100%')
|
||||
|
||||
session['do_decomposition'] = do_decomposition
|
||||
session['do_forecasting'] = do_forecasting
|
||||
session['do_acf_pacf'] = do_acf_pacf
|
||||
session['train_percent'] = train_percent
|
||||
session['test_percent'] = test_percent
|
||||
session['forecast_periods'] = forecast_periods
|
||||
session['model_type'] = model_type
|
||||
|
||||
result = process_time_series(filepath, do_decomposition, do_forecasting, do_acf_pacf, train_percent,
|
||||
forecast_periods, model_type)
|
||||
|
||||
if 'error' in result:
|
||||
return render_template('index.html', error=result['error'])
|
||||
|
||||
# Update forecast history if unique
|
||||
if do_forecasting and result['metrics']:
|
||||
update_forecast_history(session, train_percent, test_percent, forecast_periods, model_type,
|
||||
result['metrics'])
|
||||
|
||||
return render_template('results.html',
|
||||
do_decomposition=do_decomposition,
|
||||
do_forecasting=do_forecasting,
|
||||
do_acf_pacf=do_acf_pacf,
|
||||
train_percent=train_percent * 100,
|
||||
test_percent=test_percent * 100,
|
||||
forecast_periods=forecast_periods,
|
||||
forecast_history=session['forecast_history'],
|
||||
selected_indices=session['selected_indices'],
|
||||
**result)
|
||||
|
||||
|
||||
@app.route('/reforecast', methods=['POST'])
|
||||
def reforecast():
|
||||
filepath = session.get('filepath')
|
||||
if not filepath or not os.path.exists(filepath):
|
||||
return render_template('index.html', error='Session expired or file not found. Please upload the file again.')
|
||||
|
||||
# Get user selections from reforecast form
|
||||
train_percent = float(request.form.get('train_percent', 80)) / 100
|
||||
test_percent = float(request.form.get('test_percent', 20)) / 100
|
||||
forecast_periods = int(request.form.get('forecast_periods', 12))
|
||||
model_type = request.form.get('model_type', 'ARIMA')
|
||||
add_to_existing = 'add_to_existing' in request.form
|
||||
|
||||
# Validate train/test percentages
|
||||
if abs(train_percent + test_percent - 1.0) > 0.01: # Allow small float precision errors
|
||||
return render_template('index.html', error='Train and test percentages must sum to 100%')
|
||||
|
||||
# Get original selections from session or defaults
|
||||
do_decomposition = session.get('do_decomposition', False)
|
||||
do_forecasting = True # Since this is a reforecast
|
||||
do_acf_pacf = session.get('do_acf_pacf', False)
|
||||
|
||||
result = process_time_series(filepath, do_decomposition, do_forecasting, do_acf_pacf, train_percent,
|
||||
forecast_periods, model_type)
|
||||
|
||||
if 'error' in result:
|
||||
return render_template('index.html', error=result['error'])
|
||||
|
||||
# Update forecast history if unique
|
||||
if do_forecasting and result['metrics']:
|
||||
update_forecast_history(session, train_percent, test_percent, forecast_periods, model_type, result['metrics'],
|
||||
add_to_existing)
|
||||
|
||||
# Update session with current parameters
|
||||
session['train_percent'] = train_percent
|
||||
session['test_percent'] = test_percent
|
||||
session['forecast_periods'] = forecast_periods
|
||||
session['model_type'] = model_type
|
||||
|
||||
# Generate comparison plot if multiple forecasts are selected
|
||||
if len(session.get('selected_indices', [])) > 1:
|
||||
result['forecast_html'] = create_comparison_plot(filepath, session['forecast_history'],
|
||||
session['selected_indices'])
|
||||
|
||||
return render_template('results.html',
|
||||
do_decomposition=do_decomposition,
|
||||
do_forecasting=do_forecasting,
|
||||
do_acf_pacf=do_acf_pacf,
|
||||
train_percent=train_percent * 100,
|
||||
test_percent=test_percent * 100,
|
||||
forecast_periods=forecast_periods,
|
||||
forecast_history=session['forecast_history'],
|
||||
selected_indices=session['selected_indices'],
|
||||
scroll_to_forecast=True,
|
||||
**result)
|
||||
|
||||
|
||||
@app.route('/compare_forecasts', methods=['POST'])
|
||||
def compare_forecasts():
|
||||
filepath = session.get('filepath')
|
||||
if not filepath or not os.path.exists(filepath):
|
||||
return render_template('index.html', error='Session expired or file not found. Please upload the file again.')
|
||||
|
||||
# Get selected forecast indices
|
||||
selected_indices = [int(idx) for idx in request.form.getlist('selected_forecasts')]
|
||||
if not selected_indices:
|
||||
return render_template('index.html', error='No forecasts selected for comparison')
|
||||
|
||||
# Update session with selected indices
|
||||
session['selected_indices'] = selected_indices
|
||||
session.modified = True
|
||||
|
||||
# Get current parameters and settings
|
||||
do_decomposition = session.get('do_decomposition', False)
|
||||
do_forecasting = session.get('do_forecasting', True)
|
||||
do_acf_pacf = session.get('do_acf_pacf', False)
|
||||
train_percent = session.get('train_percent', 0.8)
|
||||
test_percent = session.get('test_percent', 0.2)
|
||||
forecast_periods = session.get('forecast_periods', 12)
|
||||
model_type = session.get('model_type', 'ARIMA')
|
||||
|
||||
# Generate comparison plot
|
||||
forecast_html = create_comparison_plot(filepath, session['forecast_history'], selected_indices)
|
||||
|
||||
# Re-run the current forecast to maintain other results
|
||||
result = process_time_series(filepath, do_decomposition, do_forecasting, do_acf_pacf, train_percent,
|
||||
forecast_periods, model_type)
|
||||
|
||||
if 'error' in result:
|
||||
return render_template('index.html', error=result['error'])
|
||||
|
||||
result['forecast_html'] = forecast_html
|
||||
|
||||
return render_template('results.html',
|
||||
do_decomposition=do_decomposition,
|
||||
do_forecasting=do_forecasting,
|
||||
do_acf_pacf=do_acf_pacf,
|
||||
train_percent=train_percent * 100,
|
||||
test_percent=test_percent * 100,
|
||||
forecast_periods=forecast_periods,
|
||||
forecast_history=session['forecast_history'],
|
||||
selected_indices=selected_indices,
|
||||
scroll_to_forecast=True,
|
||||
**result)
|
||||
|
||||
|
||||
@app.route('/download_forecast_history')
|
||||
def download_forecast_history():
|
||||
return download_forecast_history(session)
|
||||
|
||||
|
||||
@app.route('/download/<filename>')
|
||||
def download_file(filename):
|
||||
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||
return send_file(filepath, as_attachment=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||
Reference in New Issue
Block a user