Ken-INOUE commited on
Commit
7fb00e2
·
1 Parent(s): b7aa901

Refactor diagnosis function to separate processing logic and improve Gradio UI for user input handling

Browse files
Files changed (1) hide show
  1. app.py +48 -52
app.py CHANGED
@@ -1,6 +1,6 @@
1
- import gradio as gr
2
  import pandas as pd
3
  import json
 
4
 
5
  # --- 状態判定関数 ---
6
  def judge_status(value, ll, l, h, hh):
@@ -16,41 +16,26 @@ def judge_status(value, ll, l, h, hh):
16
  return "OK"
17
 
18
  # --- 診断関数 ---
19
- def diagnose_app(csv_file, excel_file, process_name, datetime_str, window_minutes):
20
- if csv_file is None or excel_file is None:
21
- return "⚠ CSVとExcelを両方アップロードしてください", None, None, None, None
22
-
23
- # CSV読み込み(3行ヘッダー)
24
- df = pd.read_csv(csv_file, header=[0, 1, 2])
25
- timestamp_col = df.iloc[:, 0]
26
- df = df.drop(df.columns[0], axis=1)
27
- df.insert(0, "timestamp", timestamp_col)
28
- df["timestamp"] = pd.to_datetime(df["timestamp"], errors="coerce")
29
-
30
- # 閾値テーブル
31
- thresholds_df = pd.read_excel(excel_file)
32
- thresholds_df["Important"] = thresholds_df["Important"].astype(str).str.upper().map({"TRUE": True, "FALSE": False})
33
- for col in ["LL", "L", "H", "HH"]:
34
- if col in thresholds_df.columns:
35
- thresholds_df[col] = pd.to_numeric(thresholds_df[col], errors="coerce")
36
-
37
- # 入力日時
38
  try:
39
  target_time = pd.to_datetime(datetime_str)
40
  except Exception:
41
- return f"⚠ 入力した日時 {datetime_str} が無効です", None, None, None, None
 
42
 
43
  start_time = target_time - pd.Timedelta(minutes=window_minutes)
44
  end_time = target_time
45
  df_window = df[(df["timestamp"] >= start_time) & (df["timestamp"] <= end_time)]
 
46
  if df_window.empty:
47
- return "⚠ 指定時間幅にデータなし", None, None, None, None
 
48
 
49
  proc_thresholds = thresholds_df[thresholds_df["ProcessNo_ProcessName"] == process_name]
50
  if proc_thresholds.empty:
51
- return f"⚠ プロセス {process_name} の閾値が見つかりません", None, None, None, None
 
52
 
53
- # 全結果リスト
54
  all_results = []
55
  for _, row in df_window.iterrows():
56
  for _, thr in proc_thresholds.iterrows():
@@ -72,10 +57,7 @@ def diagnose_app(csv_file, excel_file, process_name, datetime_str, window_minute
72
  "時刻": str(row["timestamp"])
73
  })
74
 
75
- if not all_results:
76
- return f"⚠ 診断結果なし", None, None, None, None
77
-
78
- # --- 全項目集計 ---
79
  total = len(all_results)
80
  status_counts = pd.Series([r["判定"] for r in all_results]).value_counts().reindex(
81
  ["LOW-LOW", "LOW", "OK", "HIGH", "HIGH-HIGH"], fill_value=0
@@ -83,7 +65,7 @@ def diagnose_app(csv_file, excel_file, process_name, datetime_str, window_minute
83
  status_ratio = (status_counts / total * 100).round(1)
84
  result_df_all = pd.DataFrame({"状態": status_counts.index, "件数": status_counts.values, "割合(%)": status_ratio.values})
85
 
86
- # --- 重要項目全体 ---
87
  important_results = [r for r in all_results if r["重要項目"]]
88
  if important_results:
89
  total_imp = len(important_results)
@@ -95,10 +77,12 @@ def diagnose_app(csv_file, excel_file, process_name, datetime_str, window_minute
95
  else:
96
  result_df_imp = pd.DataFrame(columns=["状態", "件数", "割合(%)"])
97
 
98
- # --- 重要項目ごと ---
99
  result_per_item = []
100
- for item in {r["ItemName"] for r in important_results}:
101
  item_results = [r for r in important_results if r["ItemName"] == item]
 
 
102
  total_item = len(item_results)
103
  status_counts_item = pd.Series([r["判定"] for r in item_results]).value_counts().reindex(
104
  ["LOW-LOW", "LOW", "OK", "HIGH", "HIGH-HIGH"], fill_value=0
@@ -108,7 +92,7 @@ def diagnose_app(csv_file, excel_file, process_name, datetime_str, window_minute
108
  result_per_item.append({"ItemName": item, "状態": s, "件数": c, "割合(%)": r})
109
  result_df_imp_items = pd.DataFrame(result_per_item)
110
 
111
- # --- サマリー ---
112
  summary = (
113
  f"✅ {process_name} の診断完了({start_time} ~ {end_time})\n"
114
  + "[全項目] " + " / ".join([f"{s}:{r:.1f}%" for s, r in status_ratio.items()]) + "\n"
@@ -118,9 +102,26 @@ def diagnose_app(csv_file, excel_file, process_name, datetime_str, window_minute
118
  )
119
  )
120
 
121
- result_json = json.dumps(all_results, ensure_ascii=False, indent=2, default=str)
 
122
 
123
- return summary, result_df_all, result_df_imp, result_df_imp_items, result_json
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
  # --- Gradio UI ---
126
  with gr.Blocks() as demo:
@@ -128,29 +129,24 @@ with gr.Blocks() as demo:
128
 
129
  with gr.Row():
130
  csv_input = gr.File(label="CSVファイル", type="filepath")
131
- excel_input = gr.File(label="閾値テーブル", type="filepath")
132
-
133
- process_name = gr.Textbox(label="プロセス名", placeholder="例: E018-A012_除害RO")
134
- datetime_str = gr.Textbox(label="基準日(例: 2025/8/1 0:05)")
135
- window_minutes = gr.Number(label="さかのぼり時間幅 (分)", value=60)
136
 
137
  run_btn = gr.Button("診断実行")
138
 
139
- summary_out = gr.Textbox(label="サマリー")
140
- table_all_out = gr.Dataframe(label="全項目の状態集計結果")
141
- table_imp_out = gr.Dataframe(label="重要項目全体の状態集計結果")
142
- table_imp_items_out = gr.Dataframe(label="重要項目ごとの状態集計結果")
143
- json_out = gr.JSON(label="JSON出力")
144
 
145
  run_btn.click(
146
- diagnose_app,
147
- inputs=[csv_input, excel_input, process_name, datetime_str, window_minutes],
148
- outputs=[summary_out, table_all_out, table_imp_out, table_imp_items_out, json_out]
149
  )
150
 
151
  if __name__ == "__main__":
152
- import os
153
- if os.getenv("SPACE_ID"): # Hugging Face環境
154
- demo.launch(server_name="0.0.0.0")
155
- else: # ローカル
156
- demo.launch()
 
 
1
  import pandas as pd
2
  import json
3
+ import gradio as gr
4
 
5
  # --- 状態判定関数 ---
6
  def judge_status(value, ll, l, h, hh):
 
16
  return "OK"
17
 
18
  # --- 診断関数 ---
19
+ def diagnose_process_range(process_name, datetime_str, window_minutes, df, thresholds_df):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  try:
21
  target_time = pd.to_datetime(datetime_str)
22
  except Exception:
23
+ return (pd.DataFrame(), pd.DataFrame(), pd.DataFrame(),
24
+ f"⚠ 入力した日時 {datetime_str} が無効です。", "")
25
 
26
  start_time = target_time - pd.Timedelta(minutes=window_minutes)
27
  end_time = target_time
28
  df_window = df[(df["timestamp"] >= start_time) & (df["timestamp"] <= end_time)]
29
+
30
  if df_window.empty:
31
+ return (pd.DataFrame(), pd.DataFrame(), pd.DataFrame(),
32
+ "⚠ 指定した時間幅にデータが見つかりません。", "")
33
 
34
  proc_thresholds = thresholds_df[thresholds_df["ProcessNo_ProcessName"] == process_name]
35
  if proc_thresholds.empty:
36
+ return (pd.DataFrame(), pd.DataFrame(), pd.DataFrame(),
37
+ f"⚠ プロセス {process_name} の閾値が設定されていません。", "")
38
 
 
39
  all_results = []
40
  for _, row in df_window.iterrows():
41
  for _, thr in proc_thresholds.iterrows():
 
57
  "時刻": str(row["timestamp"])
58
  })
59
 
60
+ # 集計(全項目)
 
 
 
61
  total = len(all_results)
62
  status_counts = pd.Series([r["判定"] for r in all_results]).value_counts().reindex(
63
  ["LOW-LOW", "LOW", "OK", "HIGH", "HIGH-HIGH"], fill_value=0
 
65
  status_ratio = (status_counts / total * 100).round(1)
66
  result_df_all = pd.DataFrame({"状態": status_counts.index, "件数": status_counts.values, "割合(%)": status_ratio.values})
67
 
68
+ # 集計(重要項目全体
69
  important_results = [r for r in all_results if r["重要項目"]]
70
  if important_results:
71
  total_imp = len(important_results)
 
77
  else:
78
  result_df_imp = pd.DataFrame(columns=["状態", "件数", "割合(%)"])
79
 
80
+ # 集計(重要項目ごと
81
  result_per_item = []
82
+ for item in [r["ItemName"] for r in important_results]:
83
  item_results = [r for r in important_results if r["ItemName"] == item]
84
+ if not item_results:
85
+ continue
86
  total_item = len(item_results)
87
  status_counts_item = pd.Series([r["判定"] for r in item_results]).value_counts().reindex(
88
  ["LOW-LOW", "LOW", "OK", "HIGH", "HIGH-HIGH"], fill_value=0
 
92
  result_per_item.append({"ItemName": item, "状態": s, "件数": c, "割合(%)": r})
93
  result_df_imp_items = pd.DataFrame(result_per_item)
94
 
95
+ # サマリー
96
  summary = (
97
  f"✅ {process_name} の診断完了({start_time} ~ {end_time})\n"
98
  + "[全項目] " + " / ".join([f"{s}:{r:.1f}%" for s, r in status_ratio.items()]) + "\n"
 
102
  )
103
  )
104
 
105
+ result_json = json.dumps(all_results, ensure_ascii=False, indent=2,
106
+ default=lambda x: x.item() if hasattr(x, "item") else x)
107
 
108
+ return result_df_all, result_df_imp, result_df_imp_items, summary, result_json
109
+
110
+ # --- Gradio用ラッパ ---
111
+ def run_diagnosis(csv_file, excel_file, process_name, datetime_str, window_minutes):
112
+ df = pd.read_csv(csv_file.name, header=[0, 1, 2])
113
+ timestamp_col = df.iloc[:, 0]
114
+ df = df.drop(df.columns[0], axis=1)
115
+ df.insert(0, "timestamp", timestamp_col)
116
+ df["timestamp"] = pd.to_datetime(df["timestamp"], errors="coerce")
117
+
118
+ thresholds_df = pd.read_excel(excel_file.name)
119
+ thresholds_df["Important"] = thresholds_df["Important"].astype(str).str.upper().map({"TRUE": True, "FALSE": False})
120
+ for col in ["LL", "L", "H", "HH"]:
121
+ if col in thresholds_df.columns:
122
+ thresholds_df[col] = pd.to_numeric(thresholds_df[col], errors="coerce")
123
+
124
+ return diagnose_process_range(process_name, datetime_str, int(window_minutes), df, thresholds_df)
125
 
126
  # --- Gradio UI ---
127
  with gr.Blocks() as demo:
 
129
 
130
  with gr.Row():
131
  csv_input = gr.File(label="CSVファイル", type="filepath")
132
+ excel_input = gr.File(label="Excel閾値テーブル", type="filepath")
133
+ process_name_input = gr.Textbox(label="プロセス名", value="E018-A012_除害RO")
134
+ datetime_input = gr.Textbox(label="基準日時 (例: 2025/8/1 1:05)")
135
+ window_input = gr.Number(label="さかのぼり間幅(分)", value=60)
 
136
 
137
  run_btn = gr.Button("診断実行")
138
 
139
+ summary_out = gr.Textbox(label="診断サマリー")
140
+ all_df_out = gr.DataFrame(label="全項目の状態集計結果")
141
+ imp_df_out = gr.DataFrame(label="重要項目全体の状態集計結果")
142
+ imp_items_out = gr.DataFrame(label="重要項目ごとの状態集計結果")
143
+ json_out = gr.Code(label="JSON出力", language="json")
144
 
145
  run_btn.click(
146
+ fn=run_diagnosis,
147
+ inputs=[csv_input, excel_input, process_name_input, datetime_input, window_input],
148
+ outputs=[all_df_out, imp_df_out, imp_items_out, summary_out, json_out],
149
  )
150
 
151
  if __name__ == "__main__":
152
+ demo.launch(server_name="0.0.0.0", share=False, ssr_mode=False)