MTeguri commited on
Commit
cd0375c
·
1 Parent(s): 32c8275

Implement check_thresholds function and enhance run_troubleshooting: Add alert generation for threshold violations, improve empty checks, and ensure timestamp consistency with timezone handling.

Browse files
Files changed (1) hide show
  1. app.py +98 -36
app.py CHANGED
@@ -94,84 +94,146 @@ import pytz # Import pytz for timezone conversion
94
  # Assuming the data loading and check_thresholds function from the previous cell are available
95
 
96
  # トラブルシューティング実行関数の定義
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  def run_troubleshooting():
98
  try:
99
- # Get current time and calculate the time 24 hours ago
100
  current_time_utc = datetime.datetime.now(datetime.timezone.utc)
101
-
102
- # 24時間前のUTC
103
  time_24_hours_ago_utc = current_time_utc - datetime.timedelta(hours=24)
104
 
105
- # Filter sensor data for the last 24 hours
106
- # Use the globally available sensor_df and filter it each time the function is called
107
- global sensor_df
108
  recent_sensor_df = sensor_df[
109
- (sensor_df['datetime'] >= time_24_hours_ago_utc) &
110
- (sensor_df['datetime'] <= current_time_utc)
111
  ].copy()
112
 
113
- # Ensure other dataframes are accessible (they are loaded globally once)
114
- global threshold_df
115
- global troubleshooting_df
 
 
116
 
 
 
 
117
 
118
- # しきい値チェックの実行
119
- alerts_df = check_thresholds(recent_sensor_df, threshold_df) # Pass the filtered data
 
 
 
120
 
121
- # タイムスタンプごとのユニークなデータ番号の数をカウント
122
  grouped_alerts = alerts_df.groupby('timestamp')['data no.'].nunique()
123
- # 複数のデータ番号を持つタイムスタンプを抽出
124
  multiple_data_nos_timestamps = grouped_alerts[grouped_alerts > 1].index.tolist()
125
 
126
- # 複数のデータ番号を持つタイムスタンプに該当するアラートをフィルタリング
127
  filtered_alerts_df = alerts_df[alerts_df['timestamp'].isin(multiple_data_nos_timestamps)]
128
 
129
- # タイムスタンプごとにデータ番号をリスト化
 
 
 
130
  data_nos_by_timestamp = filtered_alerts_df.groupby('timestamp')['data no.'].unique().apply(list)
131
 
132
- # 結果リストの作成
133
  result_list = []
134
  for timestamp, data_nos in data_nos_by_timestamp.items():
135
  data_nos_str = ', '.join(map(str, data_nos))
136
  result_list.append({"timestamp": timestamp, "data_nos": data_nos_str})
137
 
138
- # 結果データフレームの作成
139
- result_df = pd.DataFrame(result_list)
140
-
141
- # Convert timestamp to JST 時間変換
142
- if not result_df.empty and 'timestamp' in result_df.columns:
143
- JST = pytz.timezone('Asia/Tokyo')
144
- result_df['timestamp'] = result_df['timestamp'].dt.tz_convert(JST)
145
 
 
 
 
146
 
147
- # If no alerts, return "異常ありません"
148
  if result_df.empty:
149
  return "過去24時間 異常ありません"
150
 
151
- # トラブルシューティングデータフレームの指標番号リストを整数リストに変換
152
- troubleshooting_indicator_lists = troubleshooting_df['指標No.'].str.split(',').apply(lambda x: [int(i) for i in x])
153
- # 結果データフレームのデータ番号リストを整数リストに変換
154
- result_data_nos_lists = result_df['data_nos'].str.split(', ').apply(lambda x: [int(i) for i in x])
 
 
 
 
 
 
155
 
156
- # 出力テキストの生成
157
  output_text = ""
158
  for i, result_nos in enumerate(result_data_nos_lists):
159
  result_timestamp = result_df.loc[i, 'timestamp']
160
  for j, troubleshooting_nos in enumerate(troubleshooting_indicator_lists):
161
- # 結果のデータ番号がトラブルシューティングの指標番号のスーパーセットであるか確認
162
  if set(troubleshooting_nos).issubset(set(result_nos)):
163
- troubleshooting_situation = troubleshooting_df.loc[j, 'シチュエーション\n(対応が必要な状況)']
164
- troubleshooting_action = troubleshooting_df.loc[j, 'sub goal到達のために必要な行動\n(解決策)']
 
 
 
 
 
 
165
 
166
  output_text += f"Timestamp: {result_timestamp}\n"
167
  output_text += f"Trouble: {troubleshooting_situation}\n"
168
  output_text += f"Troubleshooting: {troubleshooting_action}\n"
169
- output_text += "-" * 20 + "\n" # 区切り線
 
 
170
 
171
- return output_text
172
  except Exception as e:
173
  return f"エラーが発生しました: {type(e).__name__} - {e}"
174
 
 
175
  # Gradioインターフェースの設定
176
  iface = gr.Interface(
177
  fn=run_troubleshooting,
 
94
  # Assuming the data loading and check_thresholds function from the previous cell are available
95
 
96
  # トラブルシューティング実行関数の定義
97
+ # ① check_thresholds の戻り DataFrameは列を先に固定して作る
98
+ def check_thresholds(sensor_df_filtered, threshold_df):
99
+ alerts = []
100
+
101
+ threshold_df['下限'] = pd.to_numeric(threshold_df['下限'], errors='coerce')
102
+ threshold_df['上限'] = pd.to_numeric(threshold_df['上限'], errors='coerce')
103
+
104
+ for _, row in threshold_df.iterrows():
105
+ metric = row["指標名"]
106
+ min_val = row["下限"]
107
+ max_val = row["上限"]
108
+ data_no = row["No."]
109
+
110
+ if metric not in sensor_df_filtered.columns:
111
+ continue
112
+
113
+ sensor_metric_data = pd.to_numeric(sensor_df_filtered[metric], errors='coerce')
114
+
115
+ for index, value in sensor_metric_data.items():
116
+ if index not in sensor_df_filtered.index:
117
+ continue
118
+
119
+ # 常に 'datetime' 列を優先し、無ければ index を使う
120
+ timestamp = (
121
+ sensor_df_filtered.loc[index, "datetime"]
122
+ if "datetime" in sensor_df_filtered.columns else index
123
+ )
124
+
125
+ if pd.notna(min_val) and pd.notna(value) and value < min_val:
126
+ alerts.append({
127
+ "timestamp": timestamp,
128
+ "metric": metric,
129
+ "value": value,
130
+ "status": f"下限値 {min_val} 未満",
131
+ "data no.": data_no
132
+ })
133
+
134
+ if pd.notna(max_val) and pd.notna(value) and value > max_val:
135
+ alerts.append({
136
+ "timestamp": timestamp,
137
+ "metric": metric,
138
+ "value": value,
139
+ "status": f"上限値 {max_val} 超過",
140
+ "data no.": data_no
141
+ })
142
+
143
+ # ← ここで列を固定。空でも 'timestamp' などの列が存在するようにする
144
+ return pd.DataFrame(alerts, columns=["timestamp", "metric", "value", "status", "data no."])
145
+
146
+
147
+ # ② run_troubleshooting 内の空チェックとタイムゾーン担保
148
  def run_troubleshooting():
149
  try:
 
150
  current_time_utc = datetime.datetime.now(datetime.timezone.utc)
 
 
151
  time_24_hours_ago_utc = current_time_utc - datetime.timedelta(hours=24)
152
 
153
+ global sensor_df, threshold_df, troubleshooting_df
154
+
 
155
  recent_sensor_df = sensor_df[
156
+ (sensor_df['datetime'] >= time_24_hours_ago_utc) &
157
+ (sensor_df['datetime'] <= current_time_utc)
158
  ].copy()
159
 
160
+ alerts_df = check_thresholds(recent_sensor_df, threshold_df)
161
+
162
+ # まず空チェック(ここで 'timestamp' KeyError を根絶)
163
+ if alerts_df.empty:
164
+ return "過去24時間 異常ありません(アラート0件)"
165
 
166
+ # 'timestamp' 列が存在するか念のため防御(列固定しているので基本 True)
167
+ if 'timestamp' not in alerts_df.columns:
168
+ return "過去24時間 異常ありません(アラート0件/timestamp列なし)"
169
 
170
+ # 型とTZを担保:tz-naive → UTC を付与
171
+ if not pd.api.types.is_datetime64_any_dtype(alerts_df['timestamp']):
172
+ alerts_df['timestamp'] = pd.to_datetime(alerts_df['timestamp'], errors='coerce', utc=True)
173
+ elif alerts_df['timestamp'].dt.tz is None:
174
+ alerts_df['timestamp'] = alerts_df['timestamp'].dt.tz_localize('UTC')
175
 
 
176
  grouped_alerts = alerts_df.groupby('timestamp')['data no.'].nunique()
 
177
  multiple_data_nos_timestamps = grouped_alerts[grouped_alerts > 1].index.tolist()
178
 
 
179
  filtered_alerts_df = alerts_df[alerts_df['timestamp'].isin(multiple_data_nos_timestamps)]
180
 
181
+ # ここで空になるケースにも対応
182
+ if filtered_alerts_df.empty:
183
+ return "過去24時間 異常ありません(複数指標の同時異常なし)"
184
+
185
  data_nos_by_timestamp = filtered_alerts_df.groupby('timestamp')['data no.'].unique().apply(list)
186
 
 
187
  result_list = []
188
  for timestamp, data_nos in data_nos_by_timestamp.items():
189
  data_nos_str = ', '.join(map(str, data_nos))
190
  result_list.append({"timestamp": timestamp, "data_nos": data_nos_str})
191
 
192
+ result_df = pd.DataFrame(result_list, columns=["timestamp", "data_nos"])
 
 
 
 
 
 
193
 
194
+ # JST に変換(常に tz-aware 前提)
195
+ JST = pytz.timezone('Asia/Tokyo')
196
+ result_df['timestamp'] = result_df['timestamp'].dt.tz_convert(JST)
197
 
 
198
  if result_df.empty:
199
  return "過去24時間 異常ありません"
200
 
201
+ # 以下、トラブルシューティング照合
202
+ if '指標No.' not in troubleshooting_df.columns:
203
+ return "設定テーブルに『指標No.』列が見つかりません。"
204
+
205
+ troubleshooting_indicator_lists = troubleshooting_df['指標No.'].astype(str).str.split(',').apply(
206
+ lambda x: [int(i) for i in x if i.strip().isdigit()]
207
+ )
208
+ result_data_nos_lists = result_df['data_nos'].astype(str).str.split(', ').apply(
209
+ lambda x: [int(i) for i in x if i.strip().isdigit()]
210
+ )
211
 
 
212
  output_text = ""
213
  for i, result_nos in enumerate(result_data_nos_lists):
214
  result_timestamp = result_df.loc[i, 'timestamp']
215
  for j, troubleshooting_nos in enumerate(troubleshooting_indicator_lists):
 
216
  if set(troubleshooting_nos).issubset(set(result_nos)):
217
+ # 列の存在チェックも加える
218
+ if ('シチュエーション\n(対応が必要な状況)' in troubleshooting_df.columns and
219
+ 'sub goal到達のために必要な行動\n(解決策)' in troubleshooting_df.columns):
220
+ troubleshooting_situation = troubleshooting_df.loc[j, 'シチュエーション\n(対応が必要な状況)']
221
+ troubleshooting_action = troubleshooting_df.loc[j, 'sub goal到達のために必要な行動\n(解決策)']
222
+ else:
223
+ troubleshooting_situation = "(シチュエーション列なし)"
224
+ troubleshooting_action = "(解決策列なし)"
225
 
226
  output_text += f"Timestamp: {result_timestamp}\n"
227
  output_text += f"Trouble: {troubleshooting_situation}\n"
228
  output_text += f"Troubleshooting: {troubleshooting_action}\n"
229
+ output_text += "-" * 20 + "\n"
230
+
231
+ return output_text if output_text else "該当するトラブルシューティングの組み合わせはありませんでした。"
232
 
 
233
  except Exception as e:
234
  return f"エラーが発生しました: {type(e).__name__} - {e}"
235
 
236
+
237
  # Gradioインターフェースの設定
238
  iface = gr.Interface(
239
  fn=run_troubleshooting,