|
|
from flask import Flask, render_template, request, redirect, url_for, send_file, flash, jsonify |
|
|
import os |
|
|
import traceback |
|
|
from pathlib import Path |
|
|
import json |
|
|
import pandas as pd |
|
|
|
|
|
app = Flask(__name__) |
|
|
app.secret_key = os.urandom(24) |
|
|
|
|
|
try: |
|
|
import main as project_main |
|
|
except Exception as e: |
|
|
project_main = None |
|
|
import_error = traceback.format_exc() |
|
|
else: |
|
|
import_error = None |
|
|
|
|
|
RESULTS_CSV = Path("results_flask.csv") |
|
|
|
|
|
def safe_update_dict_from_json(orig_dict, json_text): |
|
|
if not json_text or not json_text.strip(): |
|
|
return orig_dict |
|
|
try: |
|
|
new = json.loads(json_text) |
|
|
if not isinstance(new, dict): |
|
|
return orig_dict |
|
|
d = orig_dict.copy() |
|
|
d.update(new) |
|
|
return d |
|
|
except Exception: |
|
|
return orig_dict |
|
|
|
|
|
@app.route("/", methods=["GET"]) |
|
|
def index(): |
|
|
if project_main is None: |
|
|
return render_template("index.html", import_error=import_error, project=None) |
|
|
techs = list(project_main.TECHNOLOGY_DATA.keys()) |
|
|
defaults = { |
|
|
"inflation": project_main.INFLATION_RATE, |
|
|
"tax": project_main.TAX_RATE, |
|
|
"years": project_main.PROJECT_YEARS, |
|
|
"cap_min": project_main.OPTIMIZATION_SPACE['capacity_kta'][0], |
|
|
"cap_max": project_main.OPTIMIZATION_SPACE['capacity_kta'][1], |
|
|
"export_mix": project_main.OPTIMIZATION_SPACE['export_market_mix'][0], |
|
|
"technology": "Engro_Pakistan", |
|
|
} |
|
|
return render_template("index.html", import_error=None, project=project_main, techs=techs, defaults=defaults) |
|
|
|
|
|
@app.route("/run", methods=["POST"]) |
|
|
def run(): |
|
|
if project_main is None: |
|
|
flash("خطا: فایل main.py بارگزاری نشد. لطفاً لاگ را بررسی کنید.", "danger") |
|
|
return redirect(url_for("index")) |
|
|
try: |
|
|
inflation_rate = float(request.form.get("inflation", project_main.INFLATION_RATE)) |
|
|
tax_rate = float(request.form.get("tax", project_main.TAX_RATE)) |
|
|
project_years = int(request.form.get("years", project_main.PROJECT_YEARS)) |
|
|
capacity_min = float(request.form.get("cap_min", project_main.OPTIMIZATION_SPACE['capacity_kta'][0])) |
|
|
capacity_max = float(request.form.get("cap_max", project_main.OPTIMIZATION_SPACE['capacity_kta'][1])) |
|
|
technology = request.form.get("technology", "Engro_Pakistan") |
|
|
export_mix = float(request.form.get("export_mix", project_main.OPTIMIZATION_SPACE['export_market_mix'][0])) |
|
|
sell_byproducts = request.form.get("sell_byproducts") == "on" |
|
|
tech_json = request.form.get("tech_json", "") |
|
|
prices_json = request.form.get("prices_json", "") |
|
|
except Exception as e: |
|
|
flash("خطا در خواندن ورودیها: " + str(e), "danger") |
|
|
return redirect(url_for("index")) |
|
|
|
|
|
try: |
|
|
project_main.INFLATION_RATE = inflation_rate |
|
|
project_main.TAX_RATE = tax_rate |
|
|
project_main.PROJECT_YEARS = project_years |
|
|
|
|
|
project_main.OPTIMIZATION_SPACE['capacity_kta'] = (capacity_min, capacity_max) |
|
|
|
|
|
project_main.OPTIMIZATION_SPACE['technology'] = ["Engro_Pakistan", "Shin_Etsu_2004"] if technology not in ["Engro_Pakistan", "Shin_Etsu_2004"] else [technology] |
|
|
project_main.OPTIMIZATION_SPACE['sourcing_strategy'] = ['Integrated_Production'] |
|
|
project_main.OPTIMIZATION_SPACE['export_market_mix'] = (0.6, 0.8) |
|
|
project_main.OPTIMIZATION_SPACE['sell_byproducts'] = [bool(sell_byproducts)] |
|
|
|
|
|
project_main.TECHNOLOGY_DATA = safe_update_dict_from_json(project_main.TECHNOLOGY_DATA, tech_json) |
|
|
project_main.PRODUCT_PRICES_USD_PER_TON = safe_update_dict_from_json(project_main.PRODUCT_PRICES_USD_PER_TON, prices_json) |
|
|
except Exception as e: |
|
|
flash("خطا در اعمال پارامترها: " + str(e), "danger") |
|
|
return redirect(url_for("index")) |
|
|
|
|
|
try: |
|
|
flash("محاسبات شروع شد — صبر کنید تا عملیات به پایان برسد...", "info") |
|
|
results = project_main.run_optimizations_without_ml() |
|
|
df_results = pd.DataFrame(results).sort_values(by="irr", ascending=False).reset_index(drop=True) |
|
|
df_results = df_results.round(2) |
|
|
|
|
|
RESULTS_CSV = Path.cwd() / "results_flask.csv" |
|
|
df_results.to_csv(RESULTS_CSV, index=False, encoding='utf-8-sig') |
|
|
|
|
|
try: |
|
|
project_main.display_and_save_results(df_results) |
|
|
project_main.create_kpi_comparison_dashboard(df_results) |
|
|
except Exception: |
|
|
pass |
|
|
|
|
|
if not df_results.empty: |
|
|
best = df_results.iloc[0] |
|
|
top_kpis = { |
|
|
"irr": round(float(best['irr']), 2), |
|
|
"annual_profit_M": round(float(best['annual_profit'])/1_000_000, 2), |
|
|
"capex_M": round(float(best['total_capex'])/1_000_000, 2), |
|
|
"payback": round(float(best['payback_period']), 2) |
|
|
} |
|
|
else: |
|
|
top_kpis = None |
|
|
|
|
|
charts_data = df_results.to_dict(orient="records") |
|
|
|
|
|
flash("محاسبات با موفقیت تکمیل شد.", "success") |
|
|
|
|
|
kpi_img = Path("static/images/kpi_dashboard.png") if Path("static/images/kpi_dashboard.png").exists() else None |
|
|
tornado_img = Path("static/images/sensitivity_analysis_tornado.png") if Path("static/images/sensitivity_analysis_tornado.png").exists() else None |
|
|
|
|
|
return render_template( |
|
|
"index.html", |
|
|
project=project_main, |
|
|
techs=list(project_main.TECHNOLOGY_DATA.keys()), |
|
|
defaults={"inflation": project_main.INFLATION_RATE, "tax": project_main.TAX_RATE}, |
|
|
table_html = df_results.to_html( |
|
|
classes='table table-striped table-dark', |
|
|
index=False, |
|
|
justify='center', |
|
|
float_format=lambda x: f"{x:.2f}" |
|
|
), |
|
|
top_kpis=top_kpis, |
|
|
charts_json=json.dumps(charts_data, default=str), |
|
|
kpi_img="images/kpi_dashboard.png" if kpi_img else None, |
|
|
tornado_img="images/sensitivity_analysis_tornado.png" if tornado_img else None |
|
|
) |
|
|
|
|
|
except Exception as e: |
|
|
tb = traceback.format_exc() |
|
|
flash("خطا در اجرای الگوریتمها. لاگ: " + str(e), "danger") |
|
|
return render_template("index.html", import_error=tb, project=project_main) |
|
|
|
|
|
@app.route("/download") |
|
|
def download_results(): |
|
|
if RESULTS_CSV.exists(): |
|
|
return send_file(str(RESULTS_CSV), as_attachment=True) |
|
|
flash("فایل نتایج آماده نیست.", "warning") |
|
|
return redirect(url_for("index")) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
|
app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7860))) |