File size: 6,885 Bytes
e6b76e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195ad08
e6b76e7
 
 
 
 
 
 
 
 
 
 
 
 
 
195ad08
e6b76e7
 
 
 
 
 
 
 
 
 
 
 
 
 
195ad08
 
 
e0359f8
e6b76e7
 
 
 
 
 
 
 
 
 
 
 
 
 
195ad08
e6b76e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e0359f8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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",  # FIX: default برای match IRR main.py
    }
    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")  # FIX: default Engro
        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)
        # FIX: هم‌خوانی با main.py (technology پرهزینه، sourcing صریح)
        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']  # FIX: صریح
        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"  # FIX: ذخیره در دایرکتوری فعلی
        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)))