Ken-INOUE commited on
Commit
d7bc1e2
·
1 Parent(s): c743511

Refactor trend detection application to improve CSV loading and streamline trend analysis. Update Gradio UI for better user interaction and error handling.

Browse files
Files changed (1) hide show
  1. app.py +110 -120
app.py CHANGED
@@ -1,132 +1,122 @@
1
- # app_trend.py
2
- import os
3
- import json
4
  import pandas as pd
5
  import numpy as np
6
  from sklearn.linear_model import LinearRegression
7
- import gradio as gr
8
 
9
- # --- 傾向検出関数 ---
10
- def detect_trends(process_name, datetime_str, window_minutes, csv_file, excel_file):
 
 
11
  try:
12
- # CSV読み込み(3行ヘッダー維持)
13
- df = pd.read_csv(csv_file.name, header=[0, 1, 2])
14
  timestamp_col = df.iloc[:, 0]
15
  df = df.drop(df.columns[0], axis=1)
16
- df.insert(0, "timestamp", timestamp_col)
17
- df["timestamp"] = pd.to_datetime(df["timestamp"], errors="coerce")
18
-
19
- # 閾値テーブル読み込み
20
- thresholds_df = pd.read_excel(excel_file.name)
21
- thresholds_df["Important"] = thresholds_df["Important"].astype(str).str.upper().map({"TRUE": True, "FALSE": False})
22
- for col in ["LL", "L", "H", "HH"]:
23
- if col in thresholds_df.columns:
24
- thresholds_df[col] = pd.to_numeric(thresholds_df[col], errors="coerce")
25
-
26
- # --- 診断対象期間 ---
27
- target_time = pd.to_datetime(datetime_str)
28
- start_time = target_time - pd.Timedelta(minutes=window_minutes)
29
- end_time = target_time
30
- df_window = df[(df["timestamp"] >= start_time) & (df["timestamp"] <= end_time)]
31
-
32
- if df_window.empty:
33
- return pd.DataFrame(), f"⚠ 指定時間幅にデータなし", "{}"
34
-
35
- proc_thresholds = thresholds_df[(thresholds_df["ProcessNo_ProcessName"] == process_name) &
36
- (thresholds_df["Important"] == True)]
37
- if proc_thresholds.empty:
38
- return pd.DataFrame(), f"⚠ プロセス {process_name} の重要項目なし", "{}"
39
-
40
- results = []
41
- for _, thr in proc_thresholds.iterrows():
42
- col_tuple = (thr["ColumnID"], thr["ItemName"], thr["ProcessNo_ProcessName"])
43
- if col_tuple not in df.columns:
44
- continue
45
-
46
- series = df_window[col_tuple].dropna()
47
- if len(series) < 3:
48
- continue
49
-
50
- # 線形回帰
51
- x = np.arange(len(series)).reshape(-1, 1)
52
- y = series.values.reshape(-1, 1)
53
- model = LinearRegression().fit(x, y)
54
- slope = model.coef_[0][0]
55
-
56
- last_val = series.iloc[-1]
57
- l, ll, h, hh = thr.get("L"), thr.get("LL"), thr.get("H"), thr.get("HH")
58
-
59
- status = "安定"
60
- if slope < 0 and pd.notna(ll):
61
- if last_val > ll:
62
- status = "LL接近下降傾向"
63
- elif last_val <= ll:
64
- status = "LL逸脱下降傾向"
65
- if slope > 0 and pd.notna(hh):
66
- if last_val < hh:
67
- status = "HH接近上昇傾向"
68
- elif last_val >= hh:
69
- status = "HH逸脱上昇傾向"
70
-
71
- results.append({
72
- "ItemName": thr["ItemName"],
73
- "傾向": status,
74
- "傾き": round(float(slope), 4),
75
- "最終値": round(float(last_val), 3) if pd.notna(last_val) else None,
76
- "LL": ll, "L": l, "H": h, "HH": hh
77
- })
78
-
79
- if not results:
80
- return pd.DataFrame(), f"⚠ データ不足のため傾向検出不可", "{}"
81
-
82
- result_df = pd.DataFrame(results)
83
- result_json = json.dumps(results, ensure_ascii=False, indent=2)
84
-
85
- # JSONファイル保存(ダウンロード用)
86
- json_path = "trend_result.json"
87
- with open(json_path, "w", encoding="utf-8") as f:
88
- f.write(result_json)
89
-
90
- summary = f"✅ {process_name} の傾向検出完了({start_time} ~ {end_time})"
91
- return result_df, summary, json_path
92
-
93
  except Exception as e:
94
- return pd.DataFrame(), f"❌ エラー: {str(e)}", "{}"
95
-
96
 
97
- # --- Gradio UI ---
98
- def create_demo():
99
- with gr.Blocks(css=".gradio-container {overflow-y: auto;}") as demo:
100
- gr.Markdown("## 📈 傾向検出アプリ")
 
 
 
 
101
 
102
- with gr.Row():
103
- csv_input = gr.File(label="CSVファイルをアップロード", type="filepath")
104
- excel_input = gr.File(label="閾値テーブルExcelをアップロード", type="filepath")
105
-
106
- process_name = gr.Textbox(label="プロセス名 (例: E018-A012_除害RO)")
107
- datetime_input = gr.Textbox(label="基準日時 (例: 2025/8/1 0:05)")
108
- window_minutes = gr.Number(label="さかのぼる時間幅 (分)", value=60)
109
-
110
- run_btn = gr.Button("傾向検出を実行")
111
-
112
- result_table = gr.Dataframe(label="傾向検出結果", interactive=False)
113
- summary_out = gr.Textbox(label="サマリー")
114
- json_file = gr.File(label="結果JSONダウンロード", interactive=False)
115
-
116
- run_btn.click(
117
- detect_trends,
118
- inputs=[process_name, datetime_input, window_minutes, csv_input, excel_input],
119
- outputs=[result_table, summary_out, json_file]
120
- )
121
-
122
- return demo
123
-
124
-
125
- # --- 起動設定 ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  if __name__ == "__main__":
127
- demo = create_demo()
128
- if os.getenv("USE_MCP") == "1":
129
- demo.launch(server_name="0.0.0.0", mcp_server=True, ssr_mode=False)
 
130
  else:
131
- demo.launch(server_name="0.0.0.0", share=False, ssr_mode=False)
132
-
 
1
+ # 傾向検出アプリ(Gradio 単独版)
2
+
3
+ import gradio as gr
4
  import pandas as pd
5
  import numpy as np
6
  from sklearn.linear_model import LinearRegression
7
+ import json
8
 
9
+ # ===============================
10
+ # データ読み込み関数
11
+ # ===============================
12
+ def load_csv(file):
13
  try:
14
+ df = pd.read_csv(file.name, header=[0, 1, 2])
 
15
  timestamp_col = df.iloc[:, 0]
16
  df = df.drop(df.columns[0], axis=1)
17
+ df.insert(0, "timestamp", pd.to_datetime(timestamp_col, errors="coerce"))
18
+ return df, f"✅ CSVを読み込みました({df.shape[0]}行 × {df.shape[1]}列)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  except Exception as e:
20
+ return None, f"❌ 読み込みエラー: {str(e)}"
 
21
 
22
+ # ===============================
23
+ # 傾向検出関数
24
+ # ===============================
25
+ def detect_trend(csv_file, process_name, datetime_str, window_minutes=60):
26
+ # データ読み込み
27
+ df, msg = load_csv(csv_file)
28
+ if df is None:
29
+ return msg, None, None, None
30
 
31
+ try:
32
+ target_time = pd.to_datetime(datetime_str)
33
+ except Exception:
34
+ return f"⚠ 入力した日時 {datetime_str} が無効です。", None, None, None
35
+
36
+ start_time = target_time - pd.Timedelta(minutes=window_minutes)
37
+ df_window = df[(df["timestamp"] >= start_time) & (df["timestamp"] <= target_time)]
38
+
39
+ if df_window.empty:
40
+ return f"⚠ 指定した時間幅にデータが見つかりません。", None, None, None
41
+
42
+ # 対象プロセスのカラムを抽出
43
+ proc_cols = [col for col in df_window.columns if isinstance(col, tuple) and col[2] == process_name]
44
+ if not proc_cols:
45
+ return f"⚠ プロセス {process_name} のカラムが見つかりません。", None, None, None
46
+
47
+ results = []
48
+ for col in proc_cols:
49
+ series = df_window[col].dropna()
50
+ if len(series) < 3:
51
+ continue
52
+
53
+ X = np.arange(len(series)).reshape(-1, 1)
54
+ y = series.values
55
+ model = LinearRegression().fit(X, y)
56
+ slope = model.coef_[0]
57
+
58
+ trend = "上昇" if slope > 0 else "下降" if slope < 0 else "横ばい"
59
+ results.append({"ItemName": col[1], "傾き": slope, "傾向": trend})
60
+
61
+ if not results:
62
+ return f"⚠ 傾向を検出できるデータがありません。", None, None, None
63
+
64
+ df_results = pd.DataFrame(results)
65
+
66
+ # サマリー
67
+ trend_counts = df_results["傾向"].value_counts().to_dict()
68
+ summary = f"✅ {process_name} の傾向検出完了({start_time} ~ {target_time})\n"
69
+ summary += " / ".join([f"{k}:{v}" for k, v in trend_counts.items()])
70
+
71
+ # JSON
72
+ result_json = json.dumps(results, ensure_ascii=False, indent=2)
73
+
74
+ return "✅ 診断完了", df_results, summary, result_json
75
+
76
+
77
+ # ===============================
78
+ # Gradio アプリ UI
79
+ # ===============================
80
+ custom_css = """
81
+ body, html, #root, [data-testid="block-container"] {
82
+ height: auto !important;
83
+ overflow-y: auto !important;
84
+ }
85
+ """
86
+
87
+ with gr.Blocks(css=custom_css) as demo:
88
+ gr.Markdown("## 📈 傾向検出アプリ")
89
+
90
+ with gr.Row():
91
+ csv_input = gr.File(label="CSVファイルをアップロード", type="filepath")
92
+ process_input = gr.Textbox(label="プロセス名 (例: E018-A012_除害RO)")
93
+ datetime_input = gr.Textbox(label="診断基準日時 (例: 2025/8/1 1:05)")
94
+ window_input = gr.Number(label="時間幅 (分)", value=60)
95
+
96
+ run_button = gr.Button("傾向検出を実行")
97
+
98
+ with gr.Row():
99
+ msg_output = gr.Textbox(label="メッセージ")
100
+ with gr.Row():
101
+ table_output = gr.Dataframe(label="傾向検出結果", wrap=True)
102
+ with gr.Row():
103
+ summary_output = gr.Textbox(label="サマリー")
104
+ with gr.Row():
105
+ json_output = gr.JSON(label="JSON出力")
106
+
107
+ run_button.click(
108
+ detect_trend,
109
+ inputs=[csv_input, process_input, datetime_input, window_input],
110
+ outputs=[msg_output, table_output, summary_output, json_output]
111
+ )
112
+
113
+ # ===============================
114
+ # 実行
115
+ # ===============================
116
  if __name__ == "__main__":
117
+ import os
118
+ use_mcp = os.getenv("USE_MCP", "0") == "1"
119
+ if use_mcp:
120
+ demo.launch(server_name="0.0.0.0", mcp_server=True)
121
  else:
122
+ demo.launch(server_name="0.0.0.0", share=False)