Ken-INOUE commited on
Commit
19040f3
·
1 Parent(s): 73596a8

Refactor trend detection application to enhance CSV and Excel file handling, improve future forecasting logic, and update JSON output to use temporary files. Adjust Gradio UI for better user experience and output display.

Browse files
Files changed (1) hide show
  1. app.py +33 -17
app.py CHANGED
@@ -1,24 +1,29 @@
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
- import io
 
9
 
10
  # --- 状態判定&未来予測関数 ---
11
  def detect_trends_with_forecast(process_name, datetime_str, window_minutes, forecast_minutes, csv_file, excel_file):
12
  try:
 
 
 
 
13
  # CSV読み込み(3行ヘッダー)
14
- df = pd.read_csv(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", timestamp_col)
18
  df["timestamp"] = pd.to_datetime(df["timestamp"], errors="coerce")
19
 
20
  # 閾値テーブル読み込み
21
- thresholds_df = pd.read_excel(excel_file.name)
22
  thresholds_df["Important"] = thresholds_df["Important"].astype(str).str.upper().map({"TRUE": True, "FALSE": False})
23
  for col in ["LL", "L", "H", "HH"]:
24
  if col in thresholds_df.columns:
@@ -35,7 +40,7 @@ def detect_trends_with_forecast(process_name, datetime_str, window_minutes, fore
35
 
36
  # サンプリング間隔
37
  interval = df_window["timestamp"].diff().median()
38
- if pd.isna(interval):
39
  return None, "⚠ サンプリング間隔を検出できません", None
40
  interval_minutes = interval.total_seconds() / 60
41
 
@@ -64,8 +69,8 @@ def detect_trends_with_forecast(process_name, datetime_str, window_minutes, fore
64
  last_val = series.iloc[-1]
65
  n = len(series)
66
 
67
- # 未来予測
68
- forecast_steps = int(forecast_minutes / interval_minutes)
69
  forecast_index = n + forecast_steps
70
  forecast_val = model.predict([[forecast_index]])[0][0]
71
  forecast_time = target_time + pd.Timedelta(minutes=forecast_minutes)
@@ -95,22 +100,33 @@ def detect_trends_with_forecast(process_name, datetime_str, window_minutes, fore
95
  results.append({
96
  "ItemName": thr["ItemName"],
97
  "傾向": status,
98
- "傾き": round(slope, 4),
99
- "最終値": round(float(last_val), 3) if pd.notna(last_val) else None,
100
- "予測値": round(float(forecast_val), 3),
101
  "予測時刻": str(forecast_time),
102
  "予測傾向": forecast_status,
103
- "サンプリング間隔(分)": interval_minutes,
104
- "LL": ll, "L": l, "H": h, "HH": hh
 
 
 
105
  })
106
 
107
  result_df = pd.DataFrame(results)
 
 
108
  result_json = json.dumps(results, ensure_ascii=False, indent=2)
109
 
110
- # JSONをファイルして出力
111
- json_bytes = io.BytesIO(result_json.encode("utf-8"))
 
 
 
 
 
112
 
113
- return result_df, "✅ 傾向検+未来予測完了", json_bytes
 
114
 
115
  except Exception as e:
116
  return None, f"❌ エラー: {str(e)}", None
@@ -134,8 +150,9 @@ with gr.Blocks() as demo:
134
  run_btn = gr.Button("実行")
135
 
136
  with gr.Row():
137
- result_table = gr.Dataframe(label="傾向+未来予測結果")
138
  summary_output = gr.Textbox(label="サマリー")
 
139
  json_download = gr.File(label="JSON結果ダウンロード")
140
 
141
  run_btn.click(
@@ -145,7 +162,6 @@ with gr.Blocks() as demo:
145
  )
146
 
147
  if __name__ == "__main__":
148
- import os
149
  use_mcp = os.getenv("USE_MCP", "0") == "1"
150
  if use_mcp:
151
  demo.launch(server_name="0.0.0.0", mcp_server=True)
 
1
+ # 傾向検出アプリ(Gradio版・重要項目ごとの詳細+JSONダウンロード修正版
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
+ import tempfile
9
+ import os
10
 
11
  # --- 状態判定&未来予測関数 ---
12
  def detect_trends_with_forecast(process_name, datetime_str, window_minutes, forecast_minutes, csv_file, excel_file):
13
  try:
14
+ # ★ 修正ポイント: gr.File(type="filepath") は文字列パスが来る
15
+ csv_path = csv_file
16
+ excel_path = excel_file
17
+
18
  # CSV読み込み(3行ヘッダー)
19
+ df = pd.read_csv(csv_path, header=[0, 1, 2])
20
  timestamp_col = df.iloc[:, 0]
21
  df = df.drop(df.columns[0], axis=1)
22
  df.insert(0, "timestamp", timestamp_col)
23
  df["timestamp"] = pd.to_datetime(df["timestamp"], errors="coerce")
24
 
25
  # 閾値テーブル読み込み
26
+ thresholds_df = pd.read_excel(excel_path)
27
  thresholds_df["Important"] = thresholds_df["Important"].astype(str).str.upper().map({"TRUE": True, "FALSE": False})
28
  for col in ["LL", "L", "H", "HH"]:
29
  if col in thresholds_df.columns:
 
40
 
41
  # サンプリング間隔
42
  interval = df_window["timestamp"].diff().median()
43
+ if pd.isna(interval) or interval == pd.Timedelta(0):
44
  return None, "⚠ サンプリング間隔を検出できません", None
45
  interval_minutes = interval.total_seconds() / 60
46
 
 
69
  last_val = series.iloc[-1]
70
  n = len(series)
71
 
72
+ # 未来予測(最小1ステップ)
73
+ forecast_steps = max(1, int(round(forecast_minutes / interval_minutes)))
74
  forecast_index = n + forecast_steps
75
  forecast_val = model.predict([[forecast_index]])[0][0]
76
  forecast_time = target_time + pd.Timedelta(minutes=forecast_minutes)
 
100
  results.append({
101
  "ItemName": thr["ItemName"],
102
  "傾向": status,
103
+ "傾き": float(round(slope, 4)),
104
+ "最終値": float(round(float(last_val), 3)) if pd.notna(last_val) else None,
105
+ "予測値": float(round(float(forecast_val), 3)),
106
  "予測時刻": str(forecast_time),
107
  "予測傾向": forecast_status,
108
+ "サンプリング間隔(分)": float(interval_minutes),
109
+ "LL": None if pd.isna(ll) else float(ll),
110
+ "L": None if pd.isna(l) else float(l),
111
+ "H": None if pd.isna(h) else float(h),
112
+ "HH": None if pd.isna(hh) else float(hh)
113
  })
114
 
115
  result_df = pd.DataFrame(results)
116
+
117
+ # JSONテキスト
118
  result_json = json.dumps(results, ensure_ascii=False, indent=2)
119
 
120
+ # ★ 修正ポイント: BytesIO ではなく、一時ファイルに保存して「パス」を返す
121
+ fd, tmp_path = tempfile.mkstemp(suffix=".json", prefix="trend_result_")
122
+ os.close(fd)
123
+ with open(tmp_path, "w", encoding="utf-8") as f:
124
+ f.write(result_json)
125
+
126
+ summary = f"✅ {process_name} の傾向検出+未来予測完了({start_time}~{end_time}, 予測+{forecast_minutes}分)"
127
 
128
+ # gr.File力には「ファイルパス(文字列)」を返す
129
+ return result_df, summary, tmp_path
130
 
131
  except Exception as e:
132
  return None, f"❌ エラー: {str(e)}", None
 
150
  run_btn = gr.Button("実行")
151
 
152
  with gr.Row():
153
+ result_table = gr.Dataframe(label="傾向+未来予測結果", wrap=True)
154
  summary_output = gr.Textbox(label="サマリー")
155
+ # ★ 修正ポイント: gr.File の出力にはパスを渡す。type指定は不要(出力)
156
  json_download = gr.File(label="JSON結果ダウンロード")
157
 
158
  run_btn.click(
 
162
  )
163
 
164
  if __name__ == "__main__":
 
165
  use_mcp = os.getenv("USE_MCP", "0") == "1"
166
  if use_mcp:
167
  demo.launch(server_name="0.0.0.0", mcp_server=True)