Petro-Optima / app.py
GIGAParviz's picture
Update app.py
b21cd02 verified
import gradio as gr
import pandas as pd
import main as backend
import os
def process_data(project_years, base_capacity, inflation, tax, depr_years,
tech_data_df, strategy_data_df, product_prices_df,
opt_space_df, run_button_click):
if not run_button_click:
return None, None, None, "لطفاً برای شروع تحلیل، دکمه 'اجرا' را فشار دهید."
backend.PROJECT_YEARS = int(project_years)
backend.BASE_CAPACITY_KTA = int(base_capacity)
backend.INFLATION_RATE = float(inflation)
backend.TAX_RATE = float(tax)
backend.DEPRECIATION_YEARS = int(depr_years)
tech_data_df.rename(columns={
'CAPEX (M$)': 'capex_base_M',
'OPEX (cents/kg)': 'opex_base_cents_kg'
}, inplace=True)
backend.TECHNOLOGY_DATA = tech_data_df.set_index('Technology').to_dict('index')
strategy_dict = {}
for index, row in strategy_data_df.iterrows():
strategy_dict[row['Strategy']] = {
'sourcing_cost_per_ton_pvc': row['Sourcing Cost per Ton PVC'],
'byproducts': {
'caustic_soda_ton': row['Byproduct Caustic Soda (ton)'],
'surplus_edc_ton': row['Byproduct Surplus EDC (ton)']
}
}
backend.STRATEGY_DATA = strategy_dict
backend.PRODUCT_PRICES_USD_PER_TON = product_prices_df.set_index('Product')['Price (USD/ton)'].to_dict()
opt_space = {}
for _, row in opt_space_df.iterrows():
param = row['Parameter']
value_type = row['Type']
values = str(row['Values']).split(',')
if value_type == 'range':
opt_space[param] = (float(values[0]), float(values[1]))
elif value_type == 'list':
opt_space[param] = [v.strip() for v in values]
elif value_type == 'boolean':
opt_space[param] = [v.strip().lower() in ('true', '1', 't') for v in values]
backend.OPTIMIZATION_SPACE = opt_space
try:
for f in ["results.csv", "kpi_dashboard.png", "sensitivity_analysis_tornado.png"]:
if os.path.exists(f):
os.remove(f)
optimization_results_list = backend.run_optimizations_without_ml()
df_results = pd.DataFrame(optimization_results_list).sort_values(by="irr", ascending=False).reset_index(drop=True)
backend.display_and_save_results(df_results)
backend.create_kpi_comparison_dashboard(df_results)
if not df_results.empty:
best_scenario = df_results.iloc[0]
backend.run_sensitivity_analysis(best_scenario['Params'], best_scenario['irr'])
results_df = pd.read_csv("results.csv") if os.path.exists("results.csv") else pd.DataFrame()
kpi_dashboard_img = "kpi_dashboard.png" if os.path.exists("kpi_dashboard.png") else None
sensitivity_tornado_img = "sensitivity_analysis_tornado.png" if os.path.exists("sensitivity_analysis_tornado.png") else None
return results_df, kpi_dashboard_img, sensitivity_tornado_img, "✅ تحلیل بهینه‌سازی با موفقیت انجام شد!"
except Exception as e:
import traceback
print(traceback.format_exc())
return None, None, None, f"❌ خطا در اجرای تحلیل: {str(e)}"
def load_from_excel(file):
try:
xls = pd.ExcelFile(file.name)
assumptions = pd.read_excel(xls, 'Global_Assumptions').set_index('Parameter')['Value']
tech_data = pd.read_excel(xls, 'Technology_Data')
strategy_data = pd.read_excel(xls, 'Sourcing_Strategy')
prices = pd.read_excel(xls, 'Product_Prices')
opt_space = pd.read_excel(xls, 'Optimization_Space')
return (assumptions['PROJECT_YEARS'], assumptions['BASE_CAPACITY_KTA'],
assumptions['INFLATION_RATE'], assumptions['TAX_RATE'],
assumptions['DEPRECIATION_YEARS'], tech_data, strategy_data,
prices, opt_space, "فایل با موفقیت بارگذاری شد.")
except Exception as e:
return 0, 0, 0, 0, 0, pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), f"خطا در بارگذاری فایل: {e}"
css = """
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
.gradio-container { max-width: 1280px !important; margin: auto !important; }
.gr-button { background-color: #0056b3; color: white; border-radius: 8px; font-weight: bold; }
.gr-button:hover { background-color: #004494; }
footer { display: none !important; }
"""
def create_template_excel():
template_path = "data_template.xlsx"
if not os.path.exists(template_path):
with pd.ExcelWriter(template_path, engine='openpyxl') as writer:
pd.DataFrame([
{'Parameter': 'PROJECT_YEARS', 'Value': 15},
{'Parameter': 'BASE_CAPACITY_KTA', 'Value': 300},
{'Parameter': 'INFLATION_RATE', 'Value': 0.015},
{'Parameter': 'TAX_RATE', 'Value': 0.10},
{'Parameter': 'DEPRECIATION_YEARS', 'Value': 15}
]).to_excel(writer, sheet_name='Global_Assumptions', index=False)
pd.DataFrame(backend.TECHNOLOGY_DATA).T.reset_index().rename(columns={'index':'Technology', 'capex_base_M':'CAPEX (M$)', 'opex_base_cents_kg':'OPEX (cents/kg)'}).to_excel(writer, sheet_name='Technology_Data', index=False)
pd.DataFrame({
'Strategy': ['Integrated_Production', 'Purchase_VCM'],
'Sourcing Cost per Ton PVC': [450.0, 650.0],
'Byproduct Caustic Soda (ton)': [1.1, 0],
'Byproduct Surplus EDC (ton)': [0.523, 0]
}).to_excel(writer, sheet_name='Sourcing_Strategy', index=False)
pd.DataFrame(list(backend.PRODUCT_PRICES_USD_PER_TON.items()), columns=['Product', 'Price (USD/ton)']).to_excel(writer, sheet_name='Product_Prices', index=False)
pd.DataFrame([
{'Parameter': 'capacity_kta', 'Type': 'range', 'Values': '500,600'},
{'Parameter': 'technology', 'Type': 'list', 'Values': 'Engro_Pakistan,Shin_Etsu_2004'},
{'Parameter': 'sourcing_strategy', 'Type': 'list', 'Values': 'Integrated_Production'},
{'Parameter': 'export_market_mix', 'Type': 'range', 'Values': '0.6,0.8'},
{'Parameter': 'sell_byproducts', 'Type': 'boolean', 'Values': 'True'}
]).to_excel(writer, sheet_name='Optimization_Space', index=False)
return template_path
template_file_path = create_template_excel()
with gr.Blocks(theme=gr.themes.Soft(), css=css, title="داشبورد بهینه‌سازی پروژه") as demo:
with gr.Row(elem_id="header"):
logo_path = "logo.png"
if os.path.exists(logo_path):
gr.Image(logo_path, width=150, show_label=False, show_download_button=False, container=False)
else:
gr.Markdown("**(محل قرارگیری لوگو)**")
gr.Markdown("# داشبورد تحلیل و بهینه‌سازی پروژه مالی", elem_id="app-title")
gr.Markdown("---")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("## ۱. ورودی‌ها و تنظیمات مدل")
with gr.Accordion("بارگذاری داده‌ها از فایل", open=False):
gr.Markdown("می‌توانید تمام پارامترها را با آپلود یک فایل اکسل (`.xlsx`) بارگذاری کنید. لطفاً از فرمت فایل نمونه استفاده کنید.")
upload_button = gr.UploadButton("آپلود فایل اکسل", file_types=[".xlsx"], file_count="single")
gr.File(value=template_file_path, label="دانلود فایل نمونه (Template)")
upload_status = gr.Textbox(label="وضعیت بارگذاری", interactive=False)
with gr.Tabs() as tabs:
with gr.TabItem("الف) مفروضات اصلی پروژه", id=0):
project_years = gr.Slider(5, 30, value=backend.PROJECT_YEARS, step=1, label="سال‌های پروژه (Project Years)")
base_capacity = gr.Number(value=backend.BASE_CAPACITY_KTA, label="ظرفیت پایه (KTA)")
inflation_rate = gr.Slider(0, 0.1, value=backend.INFLATION_RATE, label="نرخ تورم سالانه (Inflation Rate)")
tax_rate = gr.Slider(0, 0.5, value=backend.TAX_RATE, label="نرخ مالیات (Tax Rate)")
depreciation_years = gr.Slider(5, 20, value=backend.DEPRECIATION_YEARS, step=1, label="سال‌های استهلاک (Depreciation Years)")
with gr.TabItem("ب) داده‌های تکنولوژی", id=1):
tech_df = gr.DataFrame(
value=pd.DataFrame(backend.TECHNOLOGY_DATA).T.reset_index().rename(columns={'index':'Technology', 'capex_base_M':'CAPEX (M$)', 'opex_base_cents_kg':'OPEX (cents/kg)'}),
headers=['Technology', 'CAPEX (M$)', 'OPEX (cents/kg)'],
label="داده‌های تکنولوژی‌های مختلف",
row_count=(5, 'dynamic'),
col_count=(3, 'fixed'),
interactive=True
)
with gr.TabItem("ج) استراتژی تأمین و محصولات جانبی", id=2):
strategy_df = gr.DataFrame(
value=pd.DataFrame({
'Strategy': ['Integrated_Production', 'Purchase_VCM'],
'Sourcing Cost per Ton PVC': [450.0, 650.0],
'Byproduct Caustic Soda (ton)': [1.1, 0],
'Byproduct Surplus EDC (ton)': [0.523, 0]
}),
label="داده‌های استراتژی تأمین مواد اولیه",
interactive=True
)
with gr.TabItem("د) قیمت محصولات", id=3):
prices_df = gr.DataFrame(
value=pd.DataFrame(list(backend.PRODUCT_PRICES_USD_PER_TON.items()), columns=['Product', 'Price (USD/ton)']),
label="قیمت فروش محصولات (دلار بر تن)",
interactive=True
)
with gr.TabItem("ه) فضای بهینه‌سازی", id=4):
opt_space_df = gr.DataFrame(
value=pd.DataFrame([
{'Parameter': 'capacity_kta', 'Type': 'range', 'Values': '500,600'},
{'Parameter': 'technology', 'Type': 'list', 'Values': 'Engro_Pakistan,Shin_Etsu_2004'},
{'Parameter': 'sourcing_strategy', 'Type': 'list', 'Values': 'Integrated_Production'},
{'Parameter': 'export_market_mix', 'Type': 'range', 'Values': '0.6,0.8'},
{'Parameter': 'sell_byproducts', 'Type': 'boolean', 'Values': 'True'}
]),
headers=['Parameter', 'Type', 'Values'],
label="پارامترهای مورد استفاده در الگوریتم بهینه‌سازی",
interactive=True
)
gr.Markdown("---")
run_button = gr.Button("🚀 اجرا و بهینه‌سازی", variant="primary")
run_status = gr.Textbox(label="وضعیت فرآیند", interactive=False)
with gr.Column(scale=2):
gr.Markdown("## ۲. نتایج تحلیل و نمودارها")
with gr.Tabs():
with gr.TabItem("خلاصه نتایج بهینه‌سازی"):
results_table = gr.DataFrame(label="جدول مقایسه سناریوهای بهینه", wrap=True)
with gr.TabItem("داشبورد شاخص‌های کلیدی (KPI)"):
kpi_dashboard = gr.Image(label="نمودار مقایسه KPI ها", show_label=True, type="filepath")
with gr.TabItem("تحلیل حساسیت (Tornado Chart)"):
sensitivity_chart = gr.Image(label="نمودار تحلیل حساسیت IRR", show_label=True, type="filepath")
run_click_trigger = gr.Checkbox(value=False, visible=False)
run_button.click(lambda: True, outputs=run_click_trigger)
upload_button.upload(
load_from_excel,
inputs=[upload_button],
outputs=[project_years, base_capacity, inflation_rate, tax_rate, depreciation_years,
tech_df, strategy_df, prices_df, opt_space_df, upload_status]
)
run_button.click(
process_data,
inputs=[project_years, base_capacity, inflation_rate, tax_rate, depreciation_years,
tech_df, strategy_df, prices_df, opt_space_df, run_click_trigger],
outputs=[results_table, kpi_dashboard, sensitivity_chart, run_status]
)
demo.launch(share=True)