Aoi785 commited on
Commit
3bf2af4
Β·
verified Β·
1 Parent(s): fdc1657

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +114 -127
app.py CHANGED
@@ -1,15 +1,18 @@
1
  import time
2
  import gradio as gr
3
 
4
- # -------------------- λͺ¨λΈ/둜직 --------------------
5
  DEFAULTS = dict(
6
- Hn=8.0, Qn=3.5,
7
- rain_thr=40.0, # κ³ μœ λŸ‰ νŒμ • κ°•μˆ˜λŸ‰ (mm/24h)
8
- dp_limit=3.0, # νŠΈλž˜μ‹œλž™ ν—ˆμš© ν•œκ³„ (kPa) -> μ •λΉ„
9
- soc_limit=90.0, # ESS SoC ν—ˆμš© ν•œκ³„ (%) -> μ •λΉ„
10
- rho=1000.0, g=9.80665
 
 
11
  )
12
 
 
13
  def electrical_power_kw(Q, H, eta, rho=DEFAULTS["rho"], g=DEFAULTS["g"]):
14
  if Q <= 0 or H <= 0 or eta <= 0:
15
  return 0.0
@@ -69,31 +72,35 @@ def mode_badge(mode:str)->str:
69
  col=colors.get(mode,"#6b7280")
70
  icon = "●" if mode!="μ •λΉ„" else "⚠️"
71
  return f"""
72
- <div style="padding:6px 10px;border-radius:10px;background:{col};
73
- color:#fff;font-weight:800;display:inline-flex;gap:8px;align-items:center;font-size:13px">
74
- <span>{icon}</span><span>{'μ •λΉ„ λͺ¨λ“œ' if mode=='μ •λΉ„' else 'μš΄μ „ λͺ¨λ“œ : '+mode}</span>
75
  </div>"""
76
 
77
- # μ΄ˆμ†Œν˜• 도넛(110px) β€” 숫자 가독성 보강
78
  def donut(label:str, value:float, maxv:float, unit:str=""):
79
  disp_val = round(float(value), 1)
80
  maxv = max(1e-6, float(maxv))
81
  pct = max(0.0, min(float(value)/maxv, 1.0))
82
- size, r, stroke = 110, 44, 12
 
 
 
83
  C = 2*3.14159*r
84
  offset = C*(1-pct)
 
85
  return f"""
86
- <div style="display:flex;flex-direction:column;align-items:center;gap:6px;">
87
  <svg width="{size}" height="{size}" viewBox="0 0 {size} {size}">
88
  <circle cx="{size/2}" cy="{size/2}" r="{r}" stroke="#e5e7eb" stroke-width="{stroke}" fill="none"/>
89
  <circle cx="{size/2}" cy="{size/2}" r="{r}" stroke="#3b82f6" stroke-width="{stroke}" fill="none"
90
  stroke-dasharray="{C:.1f}" stroke-dashoffset="{offset:.1f}"
91
  stroke-linecap="round" transform="rotate(-90 {size/2} {size/2})"/>
92
- <text x="{size/2}" y="{size/2 - 3}" text-anchor="middle" dominant-baseline="middle"
93
- font-size="18" font-weight="800"
94
- fill="#ffffff" stroke="#111111" stroke-width="1.3" paint-order="stroke">{disp_val:.1f}{unit}</text>
95
- <text x="{size/2}" y="{size/2 + 14}" text-anchor="middle" dominant-baseline="middle"
96
- font-size="11" fill="#64748b">{label}</text>
97
  </svg>
98
  </div>"""
99
 
@@ -101,163 +108,143 @@ def chip(label:str, on:bool, on_color="#10b981"):
101
  bg=on_color if on else "#e5e7eb"
102
  fg="#fff" if on else "#111827"
103
  txt="ON" if on else "OFF"
104
- return f"""<div style="padding:4px 8px;border-radius:999px;background:{bg};color:{fg};
105
- font-size:11px;font-weight:700;display:inline-block;">{label}: {txt}</div>"""
106
 
107
  def action_box(mode:str)->str:
108
  if mode=="μ •λΉ„":
109
- body="""<b>λ°œμ „ 쀑지</b> Β· <b>μ •λΉ„ ν•„μš”</b>"""
 
 
 
110
  style='border:1px solid #fecaca;background:#fef2f2;'
111
  elif mode=="κ³ μœ λŸ‰":
112
- body='<b>좜λ ₯ μ œν•œ</b> Β· <b>λ°”μ΄νŒ¨μŠ€</b>'
113
  style='border:1px solid #fde68a;background:#fffbeb;'
114
  elif mode=="μ €μœ λŸ‰":
115
- body='<b>좜λ ₯ μΆ•μ†Œ</b> Β· <b>효율 μ΅œμ ν™”</b>'
116
  style='border:1px solid #e5e7eb;background:#f9fafb;'
117
  else:
118
- body='<b>효율 졜적��� μš΄μ „</b>'
119
  style='border:1px solid #e5e7eb;background:#f9fafb;'
120
- return f"""<div style="padding:8px 10px;border-radius:8px;{style};font-size:12px">{body}</div>"""
121
 
122
  MODE_COLOR = {"정상":"#16a34a","μ €μœ λŸ‰":"#eab308","κ³ μœ λŸ‰":"#f59e0b","μ •λΉ„":"#dc2626"}
123
 
124
- def _evaluate(Q_in, rain_mm, dp_kpa, soc_pct, Hn, Qn, rain_thr, dp_limit, soc_limit):
 
 
125
  mode = decide_mode(Q_in, Qn, rain_mm, dp_kpa, soc_pct, rain_thr, dp_limit, soc_limit)
126
  st = mode_policy(mode, Q_in, Qn, Hn)
127
  p_ref = electrical_power_kw(Qn, Hn, 0.9)
128
 
129
  header = mode_badge(mode)
130
- donuts = f"""<div style="display:flex;gap:16px;align-items:center">
131
  {donut("효율(Ξ·)", st['eta']*100, 100, "%")}
132
  {donut("좜λ ₯(kW)", st['p_kw'], max(1.0, p_ref), " kW")}
133
  </div>"""
134
 
135
- chips = f"""<div style="display:flex;gap:6px;flex-wrap:wrap">
136
  {chip("좜λ ₯ μ œν•œ", st['curtail'])}
137
  {chip("λ°”μ΄νŒ¨μŠ€", st['bypass'])}
138
  {chip("μ •λΉ„ ν•„μš”", st['service'], on_color="#ef4444")}
139
  </div>"""
140
 
141
  color = MODE_COLOR.get(mode, "#111827")
142
- summary = (f"<div style='font-size:12px;line-height:1.35'>"
143
- f"<b style='color:{color}'>ν˜„μž¬ λͺ¨λ“œ: {mode}</b> Β· "
144
- f"Q={Q_in:.1f} mΒ³/s (Qβ‚™={Qn:.1f}) Β· "
145
- f"κ°•μˆ˜={rain_mm:.1f} (≀{rain_thr:.1f}) Β· "
146
- f"νŠΈλž˜μ‹œλž™={dp_kpa:.1f} kPa (≀{dp_limit:.1f}) Β· "
147
- f"SoC={soc_pct:.1f}% (≀{soc_limit:.1f}%)</div>")
148
-
149
- right = f"""
150
- <div style="display:flex;flex-direction:column;gap:8px">
151
- {header}
152
- {donuts}
153
- {chips}
154
- {action_box(mode)}
155
- {summary}
156
- </div>
157
- """
158
- return summary, right, "" # summaryλŠ” μœ μ§€(λ‹€μš΄λ‘œλ“œλ‚˜ 둜그용), 화면은 right νŒ¨λ„λ§Œ 써도 μΆ©λΆ„
159
-
160
- def run(Q_in, rain_mm, dp_kpa, soc_pct, Hn, Qn, rain_thr, dp_limit, soc_limit):
161
  try:
162
  Q_in=float(Q_in); rain_mm=float(rain_mm); dp_kpa=float(dp_kpa); soc_pct=float(soc_pct)
163
- Hn=float(Hn); Qn=float(Qn); rain_thr=float(rain_thr); dp_limit=float(dp_limit); soc_limit=float(soc_limit)
164
  except Exception:
165
  return "⚠️ μž…λ ₯ 였λ₯˜λ₯Ό ν™•μΈν•˜μ„Έμš”.","",""
166
- return _evaluate(Q_in, rain_mm, dp_kpa, soc_pct, Hn, Qn, rain_thr, dp_limit, soc_limit)
167
-
168
- # 프리셋 & μžλ™ μ‹œμ—°
169
- def preset_normal_and_run(Hn, Qn, rain_thr, dp_limit, soc_limit):
170
- Q=0.8*float(Qn); rain=10.0; dp=1.0; soc=50.0
171
- md, right, _ = _evaluate(Q, rain, dp, soc, float(Hn), float(Qn), float(rain_thr), float(dp_limit), float(soc_limit))
172
- return round(Q,1), round(rain,1), round(dp,1), round(soc,1), md, right, ""
173
-
174
- def preset_low_and_run(Hn, Qn, rain_thr, dp_limit, soc_limit):
175
- Q=0.3*float(Qn); rain=5.0; dp=1.0; soc=50.0
176
- md, right, _ = _evaluate(Q, rain, dp, soc, float(Hn), float(Qn), float(rain_thr), float(dp_limit), float(soc_limit))
177
- return round(Q,1), round(rain,1), round(dp,1), round(soc,1), md, right, ""
178
-
179
- def preset_high_and_run(Hn, Qn, rain_thr, dp_limit, soc_limit):
180
- Q=1.3*float(Qn); rain=max(50.0, float(rain_thr)); dp=1.0; soc=50.0
181
- md, right, _ = _evaluate(Q, rain, dp, soc, float(Hn), float(Qn), float(rain_thr), float(dp_limit), float(soc_limit))
182
- return round(Q,1), round(rain,1), round(dp,1), round(soc,1), md, right, ""
183
-
184
- def preset_maint_and_run(Hn, Qn, rain_thr, dp_limit, soc_limit):
185
- Q=0.8*float(Qn); rain=10.0; dp=float(dp_limit)+0.5; soc=50.0
186
- md, right, _ = _evaluate(Q, rain, dp, soc, float(Hn), float(Qn), float(rain_thr), float(dp_limit), float(soc_limit))
187
- return round(Q,1), round(rain,1), round(dp,1), round(soc,1), md, right, ""
188
-
189
- def autoplay(Hn, Qn, rain_thr, dp_limit, soc_limit):
190
- steps = [preset_normal_and_run, preset_low_and_run, preset_high_and_run, preset_maint_and_run]
191
- for fn in steps:
192
- Q, rain, dp, soc, md, right, _ = fn(Hn, Qn, rain_thr, dp_limit, soc_limit)
193
- yield (Q, rain, dp, soc, md, right, "")
194
- time.sleep(2.0)
195
 
196
- # -------------------- UI: 슀크둀 μ—†λŠ” 1νŽ˜μ΄μ§€ 콀팩트 --------------------
197
- CSS = """
198
- body, .gradio-container { font-size: 13px; }
199
- #title { margin-bottom: 6px; }
200
- #preset-row button { min-height: 30px; }
201
- """
202
 
203
- with gr.Blocks(theme=gr.themes.Soft(), title="μ†Œμˆ˜λ ₯ 슀마트 μš΄μ „λͺ¨λ“œ λŒ€μ‹œλ³΄λ“œ", css=CSS) as app:
204
- gr.Markdown("#### 🌊 μ†Œμˆ˜λ ₯ 슀마트 μš΄μ „λͺ¨λ“œ", elem_id="title")
 
 
205
 
206
- with gr.Row(equal_height=True):
207
- # 쒌츑: μž…λ ₯(2x2 κ·Έλ¦¬λ“œ + μž‘μ€ κ³ κΈ‰κ°’)
208
- with gr.Column(scale=6, min_width=420):
209
- with gr.Row():
210
- Q_in = gr.Number(label="μœ λŸ‰ Q (mΒ³/s)", value=2.0, scale=1, precision=1)
211
- rain = gr.Number(label="κ°•μˆ˜λŸ‰ (mm/24h)", value=10.0, scale=1, precision=1)
212
- with gr.Row():
213
- dp = gr.Number(label="νŠΈλž˜μ‹œλž™ (kPa)", value=1.0, scale=1, precision=1)
214
- soc = gr.Number(label="SoC (%)", value=50.0, scale=1, precision=1)
215
 
216
- # κ³ κΈ‰κ°’ 1행에 λͺ°μ•„μ„œ (라벨 짧게)
217
- with gr.Row():
218
- Hn = gr.Number(label="Hβ‚™(m)", value=DEFAULTS["Hn"], precision=1)
219
- Qn = gr.Number(label="Qβ‚™(mΒ³/s)", value=DEFAULTS["Qn"], precision=1)
220
- rain_thr = gr.Number(label="κ°•μˆ˜ν•œκ³„", value=DEFAULTS["rain_thr"], precision=0)
221
- dp_limit = gr.Number(label="μ°¨μ••ν•œκ³„", value=DEFAULTS["dp_limit"], precision=1)
222
- soc_limit= gr.Number(label="SoCν•œκ³„", value=DEFAULTS["soc_limit"], precision=0)
223
 
224
- with gr.Row():
225
- run_btn = gr.Button("β–Ά μ‹€ν–‰", variant="primary", scale=2)
226
- demo_btn = gr.Button("μžλ™ μ‹œμ—°", scale=1)
 
 
 
227
 
228
- with gr.Row(elem_id="preset-row"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  btn_norm = gr.Button("정상", variant="secondary")
230
  btn_low = gr.Button("μ €μœ λŸ‰", variant="secondary")
231
  btn_high = gr.Button("κ³ μœ λŸ‰", variant="secondary")
232
  btn_maint = gr.Button("μ •λΉ„", variant="stop")
233
 
234
- # 우츑: μ‹œκ°ν™” νŒ¨λ„(ν•œ ν™”λ©΄μš© μ΄ˆκ°„λ‹¨ 배치)
235
- with gr.Column(scale=6, min_width=420):
236
- out_md = gr.Markdown(visible=False) # λ‚΄λΆ€μ μœΌλ‘œ μœ μ§€λ§Œ
237
- out_vis = gr.HTML() # λͺ¨λ“œ/도넛/μΉ©/μš”μ•½
238
- out_extra = gr.HTML(visible=False) # μ‚¬μš© μ•ˆν•¨
 
 
239
 
240
- # 이벀트 바인딩
241
  run_btn.click(fn=run,
242
- inputs=[Q_in, rain, dp, soc, Hn, Qn, rain_thr, dp_limit, soc_limit],
243
  outputs=[out_md, out_vis, out_extra])
244
 
245
- demo_btn.click(fn=autoplay,
246
- inputs=[Hn, Qn, rain_thr, dp_limit, soc_limit],
247
- outputs=[Q_in, rain, dp, soc, out_md, out_vis, out_extra])
248
-
249
- btn_norm.click(fn=preset_normal_and_run,
250
- inputs=[Hn, Qn, rain_thr, dp_limit, soc_limit],
251
- outputs=[Q_in, rain, dp, soc, out_md, out_vis, out_extra])
252
- btn_low.click(fn=preset_low_and_run,
253
- inputs=[Hn, Qn, rain_thr, dp_limit, soc_limit],
254
- outputs=[Q_in, rain, dp, soc, out_md, out_vis, out_extra])
255
- btn_high.click(fn=preset_high_and_run,
256
- inputs=[Hn, Qn, rain_thr, dp_limit, soc_limit],
257
- outputs=[Q_in, rain, dp, soc, out_md, out_vis, out_extra])
258
- btn_maint.click(fn=preset_maint_and_run,
259
- inputs=[Hn, Qn, rain_thr, dp_limit, soc_limit],
260
- outputs=[Q_in, rain, dp, soc, out_md, out_vis, out_extra])
261
 
262
  if __name__ == "__main__":
263
  app.launch()
 
1
  import time
2
  import gradio as gr
3
 
4
+ # ----- κ³ μ • κΈ°λ³Έκ°’(ν™”λ©΄μ—λŠ” λ…ΈμΆœ μ•ˆ 함) -----
5
  DEFAULTS = dict(
6
+ Hn=8.0, # κΈ°μ€€ λ‚™μ°¨ (m)
7
+ Qn=3.5, # κΈ°μ€€ μœ λŸ‰ (m3/s)
8
+ rain_thr=40.0,# κ³ μœ λŸ‰ νŒμ • κ°•μˆ˜λŸ‰ (mm/24h)
9
+ dp_limit=3.0, # νŠΈλž˜μ‹œλž™ ν—ˆμš© ν•œκ³„ (kPa) -> μ •λΉ„
10
+ soc_limit=90.0, # ESS SoC ν—ˆμš© ν•œκ³„ (%) -> μ •λΉ„
11
+ rho=1000.0,
12
+ g=9.80665
13
  )
14
 
15
+ # ====== 계산 둜직 ======
16
  def electrical_power_kw(Q, H, eta, rho=DEFAULTS["rho"], g=DEFAULTS["g"]):
17
  if Q <= 0 or H <= 0 or eta <= 0:
18
  return 0.0
 
72
  col=colors.get(mode,"#6b7280")
73
  icon = "●" if mode!="μ •λΉ„" else "⚠️"
74
  return f"""
75
+ <div style="padding:12px 16px;border-radius:14px;background:{col};
76
+ color:#fff;font-weight:800;display:inline-flex;gap:10px;align-items:center;font-size:18px">
77
+ <span style="font-size:18px">{icon}</span><span>{'μ •λΉ„ λͺ¨λ“œ' if mode=='μ •λΉ„' else 'μš΄μ „ λͺ¨λ“œ : '+mode}</span>
78
  </div>"""
79
 
80
+ # --- 더 크게 보이도둝 도넛 κ²Œμ΄μ§€ ν™•λŒ€ ---
81
  def donut(label:str, value:float, maxv:float, unit:str=""):
82
  disp_val = round(float(value), 1)
83
  maxv = max(1e-6, float(maxv))
84
  pct = max(0.0, min(float(value)/maxv, 1.0))
85
+
86
+ size = 220 # ↑ ν™•λŒ€
87
+ r = 86
88
+ stroke = 18
89
  C = 2*3.14159*r
90
  offset = C*(1-pct)
91
+
92
  return f"""
93
+ <div style="display:flex;flex-direction:column;align-items:center;gap:12px;">
94
  <svg width="{size}" height="{size}" viewBox="0 0 {size} {size}">
95
  <circle cx="{size/2}" cy="{size/2}" r="{r}" stroke="#e5e7eb" stroke-width="{stroke}" fill="none"/>
96
  <circle cx="{size/2}" cy="{size/2}" r="{r}" stroke="#3b82f6" stroke-width="{stroke}" fill="none"
97
  stroke-dasharray="{C:.1f}" stroke-dashoffset="{offset:.1f}"
98
  stroke-linecap="round" transform="rotate(-90 {size/2} {size/2})"/>
99
+ <text x="{size/2}" y="{size/2 - 6}" text-anchor="middle" dominant-baseline="middle"
100
+ font-size="30" font-weight="800"
101
+ fill="#ffffff" stroke="#111111" stroke-width="2" paint-order="stroke">{disp_val:.1f}{unit}</text>
102
+ <text x="{size/2}" y="{size/2 + 28}" text-anchor="middle" dominant-baseline="middle"
103
+ font-size="15" fill="#64748b">{label}</text>
104
  </svg>
105
  </div>"""
106
 
 
108
  bg=on_color if on else "#e5e7eb"
109
  fg="#fff" if on else "#111827"
110
  txt="ON" if on else "OFF"
111
+ return f"""<div style="padding:8px 12px;border-radius:999px;background:{bg};color:{fg};
112
+ font-size:13px;font-weight:700;display:inline-block;">{label}: {txt}</div>"""
113
 
114
  def action_box(mode:str)->str:
115
  if mode=="μ •λΉ„":
116
+ body="""<ul style="margin:0;padding:0;list-style:disc inside;font-size:15px">
117
+ <li style="color:#000"><b>λ°œμ „ 쀑지</b></li>
118
+ <li style="color:#000"><b>μ •λΉ„ ν•„μš”</b></li>
119
+ </ul>"""
120
  style='border:1px solid #fecaca;background:#fef2f2;'
121
  elif mode=="κ³ μœ λŸ‰":
122
+ body='<div style="color:#000;font-size:15px"><b>좜λ ₯ μ œν•œΒ·λ°”μ΄νŒ¨μŠ€ 병행</b></div>'
123
  style='border:1px solid #fde68a;background:#fffbeb;'
124
  elif mode=="μ €μœ λŸ‰":
125
+ body='<div style="color:#000;font-size:15px"><b>좜λ ₯ μΆ•μ†ŒΒ·νš¨μœ¨ μ΅œμ ν™”</b></div>'
126
  style='border:1px solid #e5e7eb;background:#f9fafb;'
127
  else:
128
+ body='<div style="color:#000;font-size:15px"><b>효율 졜적점 μš΄μ „</b></div>'
129
  style='border:1px solid #e5e7eb;background:#f9fafb;'
130
+ return f"""<div style="padding:14px 16px;border-radius:10px;{style}">{body}</div>"""
131
 
132
  MODE_COLOR = {"정상":"#16a34a","μ €μœ λŸ‰":"#eab308","κ³ μœ λŸ‰":"#f59e0b","μ •λΉ„":"#dc2626"}
133
 
134
+ def _evaluate(Q_in, rain_mm, dp_kpa, soc_pct,
135
+ Hn=DEFAULTS["Hn"], Qn=DEFAULTS["Qn"],
136
+ rain_thr=DEFAULTS["rain_thr"], dp_limit=DEFAULTS["dp_limit"], soc_limit=DEFAULTS["soc_limit"]):
137
  mode = decide_mode(Q_in, Qn, rain_mm, dp_kpa, soc_pct, rain_thr, dp_limit, soc_limit)
138
  st = mode_policy(mode, Q_in, Qn, Hn)
139
  p_ref = electrical_power_kw(Qn, Hn, 0.9)
140
 
141
  header = mode_badge(mode)
142
+ donuts = f"""<div style="display:flex;gap:40px;flex-wrap:wrap;align-items:center">
143
  {donut("효율(Ξ·)", st['eta']*100, 100, "%")}
144
  {donut("좜λ ₯(kW)", st['p_kw'], max(1.0, p_ref), " kW")}
145
  </div>"""
146
 
147
+ chips = f"""<div style="display:flex;gap:10px;flex-wrap:wrap">
148
  {chip("좜λ ₯ μ œν•œ", st['curtail'])}
149
  {chip("λ°”μ΄νŒ¨μŠ€", st['bypass'])}
150
  {chip("μ •λΉ„ ν•„μš”", st['service'], on_color="#ef4444")}
151
  </div>"""
152
 
153
  color = MODE_COLOR.get(mode, "#111827")
154
+ summary = (f"<div style='font-size:16px'><b style='color:{color}'>ν˜„μž¬ λͺ¨λ“œ: {mode}</b></div>\n\n"
155
+ f"- ν˜„μž¬ μœ λŸ‰ Q: {Q_in:.1f} mΒ³/s (κΈ°μ€€ Qβ‚™={Qn:.1f})\n"
156
+ f"- κ°•μˆ˜λŸ‰: {rain_mm:.1f} mm/24h (ν—ˆμš© {rain_thr:.1f})\n"
157
+ f"- νŠΈλž˜μ‹œλž™: {dp_kpa:.1f} kPa (ν—ˆμš© {dp_limit:.1f})\n"
158
+ f"- ESS μΆ©μ „μƒνƒœ: {soc_pct:.1f}% (ν—ˆμš© {soc_limit:.1f}%)\n\n"
159
+ f"β–Ά {st['note']}")
160
+
161
+ panel = f"""<div style="display:flex;flex-direction:column;gap:18px">{header}{donuts}{chips}</div>"""
162
+ extra = action_box(mode)
163
+ return summary, panel, extra
164
+
165
+ # ====== μ™ΈλΆ€μ—μ„œ ν˜ΈμΆœλ˜λŠ” ν•¨μˆ˜λ“€(화면은 Q/rain/dp/soc만 λ°›μŒ) ======
166
+ def run(Q_in, rain_mm, dp_kpa, soc_pct):
 
 
 
 
 
 
167
  try:
168
  Q_in=float(Q_in); rain_mm=float(rain_mm); dp_kpa=float(dp_kpa); soc_pct=float(soc_pct)
 
169
  except Exception:
170
  return "⚠️ μž…λ ₯ 였λ₯˜λ₯Ό ν™•μΈν•˜μ„Έμš”.","",""
171
+ return _evaluate(Q_in, rain_mm, dp_kpa, soc_pct)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
+ def preset_normal_and_run():
174
+ Q=0.8*DEFAULTS["Qn"]; rain=10.0; dp=1.0; soc=50.0
175
+ md, panel, extra = _evaluate(Q, rain, dp, soc)
176
+ return round(Q,1), round(rain,1), round(dp,1), round(soc,1), md, panel, extra
 
 
177
 
178
+ def preset_low_and_run():
179
+ Q=0.3*DEFAULTS["Qn"]; rain=5.0; dp=1.0; soc=50.0
180
+ md, panel, extra = _evaluate(Q, rain, dp, soc)
181
+ return round(Q,1), round(rain,1), round(dp,1), round(soc,1), md, panel, extra
182
 
183
+ def preset_high_and_run():
184
+ Q=1.3*DEFAULTS["Qn"]; rain=max(50.0, DEFAULTS["rain_thr"]); dp=1.0; soc=50.0
185
+ md, panel, extra = _evaluate(Q, rain, dp, soc)
186
+ return round(Q,1), round(rain,1), round(dp,1), round(soc,1), md, panel, extra
 
 
 
 
 
187
 
188
+ def preset_maint_and_run():
189
+ Q=0.8*DEFAULTS["Qn"]; rain=10.0; dp=DEFAULTS["dp_limit"]+0.5; soc=50.0
190
+ md, panel, extra = _evaluate(Q, rain, dp, soc)
191
+ return round(Q,1), round(rain,1), round(dp,1), round(soc,1), md, panel, extra
 
 
 
192
 
193
+ def autoplay():
194
+ steps = [preset_normal_and_run, preset_low_and_run, preset_high_and_run, preset_maint_and_run]
195
+ for fn in steps:
196
+ Q, rain, dp, soc, md, panel, extra = fn()
197
+ yield (Q, rain, dp, soc, md, panel, extra)
198
+ time.sleep(2.0)
199
 
200
+ # ====== Gradio UI (ν•œ ν™”λ©΄, 우츑 좜λ ₯ 크게) ======
201
+ with gr.Blocks(theme=gr.themes.Soft(), title="μ†Œμˆ˜λ ₯ 슀마트 μš΄μ „λͺ¨λ“œ λŒ€μ‹œλ³΄λ“œ") as app:
202
+ # μ•½κ°„μ˜ μ „μ—­ μŠ€νƒ€μΌ(우츑 좜λ ₯ 가독성 ↑)
203
+ gr.HTML("""
204
+ <style>
205
+ .gradio-container {max-width: 1200px !important;}
206
+ .wrap-panel > div {font-size: 16px;}
207
+ </style>
208
+ """)
209
+
210
+ gr.Markdown("## 🌊 μ†Œμˆ˜λ ₯ 슀마트 μš΄μ „λͺ¨λ“œ λŒ€μ‹œλ³΄λ“œ")
211
+
212
+ with gr.Row():
213
+ # 쒌츑 μž…λ ₯(ν•„μš”ν•œ 4개만)
214
+ with gr.Column(scale=1):
215
+ Q_in = gr.Number(label="μœ λŸ‰ Q (mΒ³/s)", value=2.0)
216
+ rain = gr.Number(label="κ°•μˆ˜λŸ‰ (mm/24h)", value=10.0)
217
+ dp = gr.Number(label="νŠΈλž˜μ‹œλž™ (kPa)", value=1.0)
218
+ soc = gr.Number(label="SoC (%)", value=50.0)
219
+
220
+ run_btn = gr.Button("β–Ά μ‹€ν–‰", variant="primary")
221
+
222
+ gr.Markdown("πŸ”˜ μ¦‰μ‹œ μ‹€ν–‰")
223
+ with gr.Row():
224
  btn_norm = gr.Button("정상", variant="secondary")
225
  btn_low = gr.Button("μ €μœ λŸ‰", variant="secondary")
226
  btn_high = gr.Button("κ³ μœ λŸ‰", variant="secondary")
227
  btn_maint = gr.Button("μ •λΉ„", variant="stop")
228
 
229
+ demo_btn = gr.Button("μžλ™ μ‹œμ—°")
230
+
231
+ # 우츑 좜λ ₯(더 크게: scale=3)
232
+ with gr.Column(scale=3):
233
+ out_vis = gr.HTML(elem_classes=["wrap-panel"]) # 뱃지/도넛/μΉ© (크게)
234
+ out_md = gr.Markdown() # 상단 μš”μ•½
235
+ out_extra = gr.HTML() # ν•˜λ‹¨ β€˜λ™μž‘β€™ λ°•μŠ€
236
 
237
+ # 바인딩 (μž…λ ₯ 4개만 μ‚¬μš©)
238
  run_btn.click(fn=run,
239
+ inputs=[Q_in, rain, dp, soc],
240
  outputs=[out_md, out_vis, out_extra])
241
 
242
+ btn_norm.click(fn=preset_normal_and_run, outputs=[Q_in, rain, dp, soc, out_md, out_vis, out_extra])
243
+ btn_low.click(fn=preset_low_and_run, outputs=[Q_in, rain, dp, soc, out_md, out_vis, out_extra])
244
+ btn_high.click(fn=preset_high_and_run, outputs=[Q_in, rain, dp, soc, out_md, out_vis, out_extra])
245
+ btn_maint.click(fn=preset_maint_and_run,outputs=[Q_in, rain, dp, soc, out_md, out_vis, out_extra])
246
+
247
+ demo_btn.click(fn=autoplay, outputs=[Q_in, rain, dp, soc, out_md, out_vis, out_extra])
 
 
 
 
 
 
 
 
 
 
248
 
249
  if __name__ == "__main__":
250
  app.launch()