kawaiipeace's picture
NEW: Major change and analyze the data to forecast and summary
6d2f083
Raw
History Blame
15.3 kB
# app.py
import gradio as gr
import pandas as pd
from fastapi import FastAPI
from gradio.routes import mount_gradio_app
import uvicorn
import os
import numpy as np
from typing import Tuple
from utils.preprocessing import preprocess_load_data, preprocess_temperature_data, preprocess_measurement_data
from utils.merge_data import aggregate_daily_max, merge_load_temp, merge_with_measurements, calculate_capacity_analysis
from utils.excel_loader import load_submarine_forecast_data
from models.forecast import TimeSeriesForecaster
from models.regression import LoadLimitRegressor, CapacityAnalyzer
from utils.simulate import simulate_with_model
# --- FastAPI app ---
app = FastAPI()
# --- Globals ---
df_merged = None
df_with_analysis = None
forecast_model = None
reg_model = None
capacity_analyzer = None
# --- Model option lists ---
forecast_models = ['PatchTST', 'LSTM', 'BiLSTM', 'GRU', 'RNN', 'ARIMA', 'Prophet']
regression_models = ['linear', 'xgb', 'mlp']
input_types = ['📊 Excel File (4 sheets)', '📁 CSV Files (separate)']
def process_excel_file(excel_file) -> Tuple[pd.DataFrame, pd.DataFrame]:
"""
โหลดและ process ไฟล์ Excel ที่มี 4 sheets
"""
global df_merged, df_with_analysis
# โหลดข้อมูล 4 sheets
data = load_submarine_forecast_data(excel_file.name)
df_load_raw = data['load']
df_temp_raw = data['temp']
df_tepr = data['tepr']
df_strr = data['strr']
print("✅ โหลดข้อมูล Excel สำเร็จ")
print(f"Load shape: {df_load_raw.shape}, Temp shape: {df_temp_raw.shape}")
print(f"TEPR shape: {df_tepr.shape}, STRR shape: {df_strr.shape}")
# Preprocess
df_load = preprocess_load_data(df_load_raw)
df_temp = preprocess_temperature_data(df_temp_raw)
df_tepr_agg = preprocess_measurement_data(df_tepr, param_type='TEPR')
df_strr_agg = preprocess_measurement_data(df_strr, param_type='STRR')
print("✅ Preprocess สำเร็จ")
# Aggregate & merge
df_daily = aggregate_daily_max(df_load)
df_merged = merge_load_temp(df_daily, df_temp)
df_merged = merge_with_measurements(df_merged, df_tepr, df_strr)
# Calculate capacity analysis
df_with_analysis = calculate_capacity_analysis(df_merged)
print(f"✅ Merge สำเร็จ: {df_with_analysis.shape}")
return df_merged, df_with_analysis
def process_csv_files(load_file, temp_file) -> Tuple[pd.DataFrame, pd.DataFrame]:
"""
โหลดและ process ไฟล์ CSV แยกกัน
"""
global df_merged, df_with_analysis
# โหลดข้อมูล
df_load_raw = pd.read_csv(load_file.name)
df_temp_raw = pd.read_csv(temp_file.name)
# Preprocess
df_load = preprocess_load_data(df_load_raw)
df_temp = preprocess_temperature_data(df_temp_raw)
# Aggregate & merge
df_daily = aggregate_daily_max(df_load)
df_merged = merge_load_temp(df_daily, df_temp)
# Calculate capacity analysis (ไม่มี measurement data)
df_with_analysis = calculate_capacity_analysis(df_merged)
print(f"✅ Merge สำเร็จ: {df_with_analysis.shape}")
return df_merged, df_with_analysis
def forecast_and_analyze_ui(input_type: str,
excel_file=None,
load_file=None,
temp_file=None,
forecast_model_type: str = 'PatchTST',
regression_model_type: str = 'xgb',
forecast_horizon: int = 7,
delta_temp: float = 1.0) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:
"""
Main UI function สำหรับ forecast และ capacity analysis
"""
global df_merged, df_with_analysis, forecast_model, reg_model, capacity_analyzer
try:
# 1. โหลด process ข้อมูล ตามประเภท input
if input_type == '📊 Excel File (4 sheets)':
if excel_file is None:
return "❌ กรุณาเลือกไฟล์ Excel", pd.DataFrame(), pd.DataFrame()
df_merged, df_with_analysis = process_excel_file(excel_file)
else: # CSV Files
if load_file is None or temp_file is None:
return "❌ กรุณาเลือกไฟล์ Load และ Temperature", pd.DataFrame(), pd.DataFrame()
df_merged, df_with_analysis = process_csv_files(load_file, temp_file)
# 2. Train forecasting model
try:
forecast_model = TimeSeriesForecaster(model_type=forecast_model_type, horizon=forecast_horizon)
forecast_model.fit(df_merged, value_col='mw_max')
forecast_pred = forecast_model.predict(future_steps=forecast_horizon)
# Validate forecast results (should be within reasonable range)
if np.any(forecast_pred < 0) or np.any(forecast_pred > 200):
print(f"⚠️ Forecast validation warning: pred range = [{forecast_pred.min():.2f}, {forecast_pred.max():.2f}]")
# Fallback to simple linear trend if forecast seems invalid
if np.mean(np.abs(forecast_pred)) > 1000:
last_values = df_merged['mw_max'].tail(7).values
trend = np.polyfit(np.arange(len(last_values)), last_values, 1)
forecast_pred = np.array([last_values[-1] + trend[0] * (i+1) for i in range(forecast_horizon)])
print(f" Fallback to trend: {forecast_pred[:3]}")
except Exception as e:
print(f"⚠️ Forecast model error: {e}, using simple average")
forecast_pred = np.full(forecast_horizon, df_merged['mw_max'].mean())
# 3. Train regression model (Load Limit)
reg_model = LoadLimitRegressor(model_type=regression_model_type)
reg_model.fit(df_merged, temp_col='MaxTemp', load_col='mw_max')
# 4. Train capacity analyzer (ถ้ามี measurement data)
if 'tepr_mean' in df_with_analysis.columns or 'strr_mean' in df_with_analysis.columns:
capacity_analyzer = CapacityAnalyzer(model_type=regression_model_type)
try:
capacity_analyzer.fit(df_with_analysis, target_col='mw_max')
print("✅ Capacity analyzer trained")
except Exception as e:
print(f"⚠️ Capacity analyzer error: {e}")
# 5. Simulate load limit with delta_temp
df_simulated = simulate_with_model(df_merged, delta_temp=delta_temp, model=reg_model)
# 6. เตรียมผลลัพธ์สำหรับแสดง
# Forecast results
forecast_df = pd.DataFrame({
'Step': np.arange(1, forecast_horizon + 1),
'Forecast Load (MW)': forecast_pred
})
# Capacity Analysis
analysis_df = df_with_analysis[[
'date', 'mw_max', 'mw_theoretical_80pct', 'mw_theoretical_100pct',
'mw_available_margin', 'MaxTemp', 'temp_margin_available',
'load_pct_of_80', 'margin_pct'
]].copy()
analysis_df = analysis_df.sort_values('date').tail(30) # แสดง 30 วันล่าสุด
analysis_df.columns = [
'Date', 'Load Max (MW)', '80% Theoretical', '100% Theoretical (Calc)',
'Available Margin (MW)', 'Water Temp (°C)', 'Thermal Margin (°C)',
'Load % of 80%', 'Margin %'
]
# Simulation results
sim_df_show = df_simulated[[
'date', 'MaxTemp', 'mw_max', 'MaxTemp_simulated', 'Load_simulated'
]].copy()
sim_df_show.columns = ['Date', 'Current Temp', 'Current Load', 'Simulated Temp', 'Simulated Load']
summary = f"""
🔍 **การวิเคราะห์สายเคเบิลใต้น้ำ - สรุปผล**
📊 **ข้อมูล Diagnostics:**
- Data points: {len(df_with_analysis)} วัน
- Load MW: min={df_with_analysis['mw_max'].min():.2f}, max={df_with_analysis['mw_max'].max():.2f}, avg={df_with_analysis['mw_max'].mean():.2f}
- Temp °C: min={df_with_analysis['MaxTemp'].min():.2f}, max={df_with_analysis['MaxTemp'].max():.2f}, avg={df_with_analysis['MaxTemp'].mean():.2f}
- ✅ Data quality: OK (reasonable ranges)
⚡ **Capacity Analysis (ปัจจุบัน 80% ทฤษฏี):**
- โหลดจริง vs 80% ทฤษฏี: {df_with_analysis['load_pct_of_80'].mean():.2f}%
- Margin ที่ปล่อยเพิ่มได้เฉลี่ย: {df_with_analysis['mw_available_margin'].mean():.2f} MW ({df_with_analysis['margin_pct'].mean():.2f}%)
- Margin สูงสุด: {df_with_analysis['mw_available_margin'].max():.2f} MW
- Margin ต่ำสุด: {df_with_analysis['mw_available_margin'].min():.2f} MW
🌡️ **Thermal Analysis:**
- Fiber Temperature: 30°C (constant, safe max)
- Water Temp avg: {df_with_analysis['MaxTemp'].mean():.2f}°C
- Thermal Margin avg: {df_with_analysis['temp_margin_available'].mean():.2f}°C ✅ (เพียงพอ)
- Thermal Safety: 30°C - {df_with_analysis['MaxTemp'].max():.2f}°C = {30.0 - df_with_analysis['MaxTemp'].max():.2f}°C min margin
📈 **Cable Health Indicators:**
- TEPR (Temp/Power): mean={df_with_analysis['tepr_mean'].mean():.2f} (variation degree)
- STRR (Strain/Stress): mean={df_with_analysis['strr_mean'].mean():.2f} (mechanical stress level)
- ℹ️ สถิติเหล่านี้บ่งบอก cable state ไม่ใช่ load
📋 **Interpretation Guide:**
- **load_pct_of_80 < 100%**: โหลดจริง < 80% ทฤษฏี → มีโอกาสปล่อยเพิ่ม ✅
- **load_pct_of_80 ≥ 100%**: โหลดจริง ≥ 80% ทฤษฏี → ต้องระวัง ⚠️
- **Thermal Margin > 5°C**: ความมั่นคง thermal OK ✅
- **Available Margin > 0**: สามารถปล่อยเพิ่ม MW ได้ ✅
"""
return summary, analysis_df, forecast_df
except Exception as e:
error_msg = f"❌ เกิดข้อผิดพลาด: {str(e)}"
print(error_msg)
return error_msg, pd.DataFrame(), pd.DataFrame()
# --- Gradio UI ---
demo = gr.Blocks(title="Submarine Cable Forecast & Capacity Analysis")
with demo:
gr.Markdown("""
# 🌊 Submarine Cable Load Forecast & Real Capacity Analysis
## วัตถุประสงค์:
วิเคราะห์**โหลดที่สายเคเบิลใต้น้ำสามารถปล่อยได้** (MW) เทียบกับระดับทฤษฏี 80%
เพื่อหาโอกาสการปล่อยเพิ่มเติมและ margin ด้านความปลอดภัย
## ลักษณะสำคัญ:
- 📊 **4 ชนิดข้อมูล**: โหลด (MW) + อุณหภูมิ + พารามิเตอร์สายเคเบิล (TEPR/STRR)
- 🔄 **Time Series Forecast**: พยากรณ์โหลดอนาคต 7-30 วัน
- ⚡ **Capacity Analysis**: คำนวณ margin ที่ปล่อยเพิ่มได้ เทียบกับ 80% ทฤษฏี
- 🌡️ **Thermal Analysis**: วิเคราะห์ความเสี่ยงจาก temperature
""")
with gr.Tabs():
with gr.Tab("📥 Data Input"):
gr.Markdown("### เลือกวิธีการ Upload ข้อมูล")
with gr.Row():
input_type = gr.Radio(
choices=input_types,
value='📊 Excel File (4 sheets)',
label="📁 ประเภท Input"
)
with gr.Row():
with gr.Column():
excel_file = gr.File(
label="📊 Submarine Forecast Excel (4 sheets)",
file_count="single",
file_types=[".xlsx"]
)
with gr.Column():
load_file = gr.File(
label="📈 Load File (CSV)",
file_count="single",
file_types=[".csv"]
)
temp_file = gr.File(
label="🌡️ Temperature File (CSV)",
file_count="single",
file_types=[".csv"]
)
with gr.Tab("⚙️ Model Settings"):
gr.Markdown("### ตั้งค่า Forecast & Analysis Models")
with gr.Row():
forecast_model_type = gr.Dropdown(
choices=forecast_models,
value='PatchTST',
label="🔮 Forecast Model"
)
regression_model_type = gr.Dropdown(
choices=regression_models,
value='xgb',
label="📊 Regression Model"
)
with gr.Row():
forecast_horizon = gr.Slider(
minimum=1,
maximum=30,
step=1,
value=7,
label="📅 Forecast Horizon (days)"
)
delta_temp = gr.Slider(
minimum=-5.0,
maximum=5.0,
step=0.5,
value=1.0,
label="🌡️ Temperature Change (ΔTemp °C)"
)
with gr.Tab("🚀 Analysis & Results"):
gr.Markdown("### ผลลัพธ์วิเคราะห์ Capacity จริง")
with gr.Row():
run_btn = gr.Button("🔄 Run Analysis", size="lg", variant="primary")
with gr.Column():
summary_output = gr.Markdown(label="📊 Summary")
with gr.Row():
with gr.Column():
capacity_table = gr.Dataframe(
label="📈 Capacity Analysis (Last 30 days)",
interactive=False
)
with gr.Column():
forecast_table = gr.Dataframe(
label="🔮 Forecast Results",
interactive=False
)
# Event handler
run_btn.click(
fn=forecast_and_analyze_ui,
inputs=[
input_type, excel_file, load_file, temp_file,
forecast_model_type, regression_model_type,
forecast_horizon, delta_temp
],
outputs=[summary_output, capacity_table, forecast_table]
)
demo.launch(
server_name=os.getenv("SERVER_NAME", "0.0.0.0"),
server_port=int(os.getenv("PORT", 7860)),
)