File size: 9,013 Bytes
cc2e1db
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
153
154
155
156
157
158
159
import os
import pandas as pd
from typing import Dict
from pathlib import Path

# Prefer HF router via OpenAI-compatible client. Use env `HF_TOKEN`.
# HF_TOKEN loaded lazily to allow dotenv loading after import
def get_hf_token():
    return os.environ.get('HF_TOKEN')

def openai_summary(text: str, verbosity: str = 'brief', model: str = 'meta-llama/Llama-3.1-8B-Instruct:novita') -> str:
    HF_TOKEN = get_hf_token()
    if not HF_TOKEN:
        return None
    try:
        # Import here to avoid requiring OpenAI client unless HF_TOKEN set
        from openai import OpenAI
        client = OpenAI(base_url="https://router.huggingface.co/v1", api_key=HF_TOKEN)
        if verbosity == 'analyze':
            instruction = 'วิเคราะห์สาเหตุไฟฟ้าจากข้อมูลนี้ สรุปไม่เกิน 3-4 บรรทัด (ไทย) ระบุสาเหตุทางเทคนิค ผลกระทบต่อลูกค้าและระบบ และช่วงเวลา:'
        elif verbosity == 'recommend':
            instruction = 'วิเคราะห์สาเหตุไฟฟ้าจากข้อมูลนี้ พร้อมแนะนำการแก้ไข สรุปไม่เกิน 3-4 บรรทัด (ไทย) ระบุสาเหตุทางเทคนิค ผลกระทบต่อลูกค้าและระบบ ช่วงเวลาและข้อเสนอแนะในการป้องกัน:'
        prompt = f"{instruction}\n\n{text}\n\nสรุป:"
        completion = client.chat.completions.create(
            model=model,
            messages=[{"role": "user", "content": prompt}],
            max_tokens=1000,
        )
        # Extract text from response
        choice = completion.choices[0]
        msg = choice.message
        content = msg.content
        return content.strip() if content else None
    except Exception:
        return None


def summarize_overall(df: pd.DataFrame, use_hf: bool = False, model: str = 'meta-llama/Llama-3.1-8B-Instruct:novita', total_customers: float = None) -> Dict:
    """Summarize overall outage data with GenAI and reliability metrics."""
    # Basic statistics
    total_events = len(df)
    date_cols = ['OutageDateTime', 'FirstRestoDateTime', 'LastRestoDateTime', 'CreateEventDateTime', 'CloseEventDateTime']

    # Parse dates
    df_copy = df.copy()
    for col in date_cols:
        if col in df_copy.columns:
            df_copy[col] = pd.to_datetime(df_copy[col], dayfirst=True, errors='coerce')

    # Calculate basic metrics
    if 'OutageDateTime' in df_copy.columns:
        date_range = f"{df_copy['OutageDateTime'].min()} ถึง {df_copy['OutageDateTime'].max()}" if pd.notna(df_copy['OutageDateTime'].min()) else "ไม่ระบุ"
    else:
        date_range = "ไม่ระบุ"

    # Event types
    event_types = df_copy.get('EventType', pd.Series()).value_counts().head(5).to_dict()

    # Affected customers
    total_affected = 0
    if 'AffectedCustomer' in df_copy.columns:
        total_affected = pd.to_numeric(df_copy['AffectedCustomer'], errors='coerce').sum()

    # Create summary text for GenAI
    summary_text = f"""
ข้อมูลไฟฟ้าล้มทั้งหมด:
- จำนวนเหตุการณ์ทั้งหมด: {total_events}
- ช่วงเวลาที่เกิดเหตุการณ์: {date_range}
- ประเภทเหตุการณ์หลัก: {', '.join([f'{k}: {v}' for k, v in event_types.items()])}
- จำนวนลูกค้าที่ได้รับผลกระทบทั้งหมด: {int(total_affected) if not pd.isna(total_affected) else 'ไม่ระบุ'}
"""

    # Reliability metrics DataFrame
    reliability_df = pd.DataFrame()
    reliability_summary = ""

    if total_customers and total_customers > 0:
        try:
            from scripts.compute_reliability import compute_reliability
            import tempfile
            import os

            # Save df to temp CSV for compute_reliability
            with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f:
                df_copy.to_csv(f.name, index=False)
                temp_path = f.name

            try:
                reliability_results = compute_reliability(temp_path, total_customers=total_customers, exclude_planned=True)
                overall_metrics = reliability_results.get('overall', pd.DataFrame())
                if not overall_metrics.empty:
                    row = overall_metrics.iloc[0]

                    # Create reliability DataFrame with proper metric names
                    reliability_data = [
                        {
                            'Metric': 'SAIFI',
                            'Full Name': 'System Average Interruption Frequency Index',
                            'Value': f"{row.get('SAIFI', 'N/A'):.4f}",
                            'Unit': 'ครั้ง/ลูกค้า',
                            'Description': 'ความถี่เฉลี่ยของการขัดข้องต่อลูกค้า'
                        },
                        {
                            'Metric': 'SAIDI',
                            'Full Name': 'System Average Interruption Duration Index',
                            'Value': f"{row.get('SAIDI', 'N/A'):.2f}",
                            'Unit': 'นาที/ลูกค้า',
                            'Description': 'ระยะเวลาขัดข้องเฉลี่ยต่อลูกค้า'
                        },
                        {
                            'Metric': 'CAIDI',
                            'Full Name': 'Customer Average Interruption Duration Index',
                            'Value': f"{row.get('CAIDI', 'N/A'):.2f}",
                            'Unit': 'นาที/ครั้ง',
                            'Description': 'ระยะเวลาขัดข้องเฉลี่ยต่อครั้ง'
                        },
                        {
                            'Metric': 'MAIFI',
                            'Full Name': 'Momentary Average Interruption Frequency Index',
                            'Value': f"{row.get('MAIFI', 'N/A'):.4f}",
                            'Unit': 'ครั้ง/ลูกค้า',
                            'Description': 'ความถี่เฉลี่ยของการขัดข้องชั่วคราวต่อลูกค้า'
                        }
                    ]
                    reliability_df = pd.DataFrame(reliability_data)

                    reliability_summary = f"""
ดัชนีความน่าเชื่อถือ:
- SAIFI (System Average Interruption Frequency Index): {row.get('SAIFI', 'N/A'):.4f} ครั้ง/ลูกค้า
- SAIDI (System Average Interruption Duration Index): {row.get('SAIDI', 'N/A'):.2f} นาที/ลูกค้า
- CAIDI (Customer Average Interruption Duration Index): {row.get('CAIDI', 'N/A'):.2f} นาที/ครั้ง
- MAIFI (Momentary Average Interruption Frequency Index): {row.get('MAIFI', 'N/A'):.4f} ครั้ง/ลูกค้า
"""
                    summary_text += reliability_summary
            finally:
                os.unlink(temp_path)
        except Exception as e:
            reliability_summary = f"ไม่สามารถคำนวณดัชนีความน่าเชื่อถือได้: {str(e)}"

    # Use GenAI for overall summary
    ai_summary = None
    if use_hf and get_hf_token():
        try:
            instruction = "สรุปภาพรวมข้อมูลไฟฟ้าล้มจากข้อมูลนี้ สรุปเป็นย่อหน้าเดียว (ไทย) ระบุจำนวนเหตุการณ์ สาเหตุหลัก ผลกระทบ และข้อเสนอแนะในการปรับปรุงระบบไฟฟ้า:"
            prompt = f"{instruction}\n\n{summary_text}\n\nสรุปภาพรวม:"
            ai_summary = openai_summary(prompt, verbosity='recommend', model=model)
        except Exception as e:
            ai_summary = f"ไม่สามารถสร้างสรุปด้วย AI ได้: {str(e)}"

    return {
        'total_events': total_events,
        'date_range': date_range,
        'event_types': event_types,
        'total_affected_customers': int(total_affected) if not pd.isna(total_affected) else None,
        'basic_summary': summary_text.strip(),
        'reliability_summary': reliability_summary.strip() if reliability_summary else None,
        'reliability_df': reliability_df,
        'ai_summary': ai_summary,
    }