petter2025 commited on
Commit
4b27602
·
verified ·
1 Parent(s): a04bec8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +125 -134
app.py CHANGED
@@ -1,21 +1,49 @@
1
  import gradio as gr
 
 
 
 
 
2
  import numpy as np
3
  import pandas as pd
4
- import plotly.graph_objects as go
5
- import random
6
- import time
7
  import threading
8
  import urllib.request
9
- import os
10
- from datetime import datetime
11
- import logging
12
- from scipy.stats import beta, norm
13
 
14
  # ----------------------------------------------------------------------
15
- # Logging
16
  # ----------------------------------------------------------------------
17
- logging.basicConfig(level=logging.INFO)
18
- logger = logging.getLogger(__name__)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  # ----------------------------------------------------------------------
21
  # Keep‑alive (pings public URL every 5 minutes)
@@ -24,66 +52,56 @@ def keep_alive():
24
  space_id = os.environ.get('SPACE_ID')
25
  if space_id:
26
  url = f"https://{space_id.replace('/', '-')}.hf.space/"
 
27
  else:
28
  url = "http://127.0.0.1:7860/"
 
 
29
  while True:
30
  time.sleep(300)
31
  try:
32
  with urllib.request.urlopen(url, timeout=10) as response:
33
  status = response.getcode()
34
- logger.info(f"Keep‑alive ping: {status}")
35
  except Exception as e:
36
- logger.warning(f"Keep‑alive failed: {e}")
37
 
38
  threading.Thread(target=keep_alive, daemon=True).start()
39
 
40
  # ----------------------------------------------------------------------
41
- # Global history
42
  # ----------------------------------------------------------------------
43
- decision_history = [] # (timestamp, decision, risk)
44
- risk_history = [] # (timestamp, risk)
45
 
46
- def update_dashboard_data(decision, risk):
47
- decision_history.append((datetime.utcnow().isoformat(), decision, risk))
48
- risk_history.append((datetime.utcnow().isoformat(), risk))
49
- if len(decision_history) > 100:
50
- decision_history.pop(0)
51
- if len(risk_history) > 100:
52
- risk_history.pop(0)
53
 
54
  # ----------------------------------------------------------------------
55
- # Bayesian Risk Engine (Conjugate Beta-Binomial)
56
  # ----------------------------------------------------------------------
57
  class BayesianRiskEngine:
58
- """
59
- Implements a Beta-Binomial conjugate prior for binary failure events.
60
- - Prior: Beta(alpha, beta)
61
- - Posterior: Beta(alpha + failures, beta + successes)
62
- - Predictive risk = mean of posterior.
63
- """
64
  def __init__(self, alpha=1.0, beta=1.0):
65
  self.alpha = alpha
66
  self.beta = beta
67
 
68
  def update(self, failures, successes):
69
- """Update posterior with new observations."""
70
  self.alpha += failures
71
  self.beta += successes
72
 
73
  def risk(self):
74
- """Return current risk estimate (mean of posterior)."""
75
  return self.alpha / (self.alpha + self.beta)
76
 
77
  def risk_interval(self, prob=0.95):
78
- """Return credible interval for risk."""
79
- return beta.ppf((1-prob)/2, self.alpha, self.beta), beta.ppf((1+prob)/2, self.alpha, self.beta)
80
-
81
- def risk_distribution(self, x):
82
- """PDF of the posterior Beta distribution."""
83
- return beta.pdf(x, self.alpha, self.beta)
84
 
85
  # ----------------------------------------------------------------------
86
- # Policy Engine (threshold-based)
87
  # ----------------------------------------------------------------------
88
  class PolicyEngine:
89
  def __init__(self, thresholds={"low": 0.2, "high": 0.8}):
@@ -98,8 +116,19 @@ class PolicyEngine:
98
  return "escalate", f"Risk in escalation zone ({self.thresholds['low']}-{self.thresholds['high']})"
99
 
100
  # ----------------------------------------------------------------------
101
- # Autonomous Control Decision (approve/deny based on risk)
102
  # ----------------------------------------------------------------------
 
 
 
 
 
 
 
 
 
 
 
103
  def autonomous_control_decision(risk, risk_engine, policy_engine):
104
  action, reason = policy_engine.evaluate(risk)
105
  decision = {
@@ -113,10 +142,55 @@ def autonomous_control_decision(risk, risk_engine, policy_engine):
113
  return decision
114
 
115
  # ----------------------------------------------------------------------
116
- # Simple Metropolis-Hastings MCMC sampler (for HMC tab)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  # ----------------------------------------------------------------------
118
  class MHMCMC:
119
- """A generic Metropolis-Hastings sampler for a target log-posterior."""
120
  def __init__(self, log_target, proposal_sd=0.1):
121
  self.log_target = log_target
122
  self.proposal_sd = proposal_sd
@@ -127,10 +201,8 @@ class MHMCMC:
127
  current_log = self.log_target(current)
128
  accepted = 0
129
  for i in range(n_samples + burn_in):
130
- # Propose
131
  proposal = current + np.random.normal(0, self.proposal_sd, size=len(current))
132
  proposal_log = self.log_target(proposal)
133
- # Acceptance ratio
134
  accept_prob = min(1, np.exp(proposal_log - current_log))
135
  if np.random.rand() < accept_prob:
136
  current = proposal
@@ -141,44 +213,28 @@ class MHMCMC:
141
  acceptance_rate = accepted / (n_samples + burn_in)
142
  return samples, acceptance_rate
143
 
144
- # ----------------------------------------------------------------------
145
- # HMC analysis (MCMC on a simple model)
146
- # ----------------------------------------------------------------------
147
  def run_hmc_mcmc(samples, warmup):
148
- """
149
- Simulate an HMC-like analysis using Metropolis-Hastings.
150
- Target: posterior of a Normal distribution with unknown mean.
151
- """
152
- # Generate some data: assume we observed 10 points with mean 0.5, std 0.2
153
  data = np.random.normal(0.5, 0.2, 10)
154
-
155
- # Prior: Normal(0, 1) on mu
156
  def log_prior(mu):
157
- return -0.5 * (mu ** 2) # ignoring constant
158
-
159
- # Likelihood: Normal(data | mu, sigma=0.2)
160
  def log_likelihood(mu):
161
- return -0.5 * np.sum(((data - mu) / 0.2) ** 2) # ignoring constant
162
-
163
  def log_posterior(mu):
164
  return log_prior(mu) + log_likelihood(mu)
165
 
166
- # Run MCMC
167
  sampler = MHMCMC(log_posterior, proposal_sd=0.05)
168
  mu_samples, acceptance = sampler.sample(samples, initial_state=[0.0], burn_in=warmup)
169
-
170
- # Summary
171
  mu_samples = mu_samples.flatten()
 
172
  mean = np.mean(mu_samples)
173
  median = np.median(mu_samples)
174
  credible_interval = np.percentile(mu_samples, [2.5, 97.5])
175
 
176
- # Trace plot
177
  fig_trace = go.Figure()
178
  fig_trace.add_trace(go.Scatter(y=mu_samples, mode='lines', name='μ', line=dict(width=1)))
179
  fig_trace.update_layout(title="Trace of μ (Metropolis-Hastings)", xaxis_title="Iteration", yaxis_title="μ")
180
 
181
- # Histogram
182
  fig_hist = go.Figure()
183
  fig_hist.add_trace(go.Histogram(x=mu_samples, nbinsx=50, name='Posterior'))
184
  fig_hist.update_layout(title="Posterior Distribution of μ", xaxis_title="μ", yaxis_title="Density")
@@ -191,59 +247,6 @@ def run_hmc_mcmc(samples, warmup):
191
  }
192
  return summary, fig_trace, fig_hist
193
 
194
- # ----------------------------------------------------------------------
195
- # Infrastructure Analysis (uses BayesianRiskEngine)
196
- # ----------------------------------------------------------------------
197
- async def handle_infra_with_governance(fault_type, context_window, session_state):
198
- # Map fault to simulated observations (failures, successes)
199
- fault_map = {
200
- "none": (1, 99),
201
- "switch_down": (20, 80),
202
- "server_overload": (35, 65),
203
- "cascade": (60, 40)
204
- }
205
- failures, successes = fault_map.get(fault_type, (1, 99))
206
- severity = "low" if failures < 10 else "medium" if failures < 40 else "high"
207
-
208
- # Create risk engine with prior Beta(1,1)
209
- risk_engine = BayesianRiskEngine(alpha=1, beta=1)
210
- # Update with observed data
211
- risk_engine.update(failures, successes)
212
- risk = risk_engine.risk()
213
- ci_low, ci_high = risk_engine.risk_interval(0.95)
214
-
215
- # Policy evaluation
216
- policy_engine = PolicyEngine(thresholds={"low": 0.2, "high": 0.8})
217
- action, reason = policy_engine.evaluate(risk)
218
-
219
- # Autonomous decision
220
- control_decision = autonomous_control_decision(risk, risk_engine, policy_engine)
221
-
222
- # Build output
223
- analysis_result = {
224
- "risk": risk,
225
- "risk_ci": [ci_low, ci_high],
226
- "decision": action,
227
- "justification": reason,
228
- "healing_actions": ["restart"] if action == "deny" else ["monitor"],
229
- "posterior_parameters": {
230
- "alpha": risk_engine.alpha,
231
- "beta": risk_engine.beta
232
- }
233
- }
234
- output = {
235
- **analysis_result,
236
- "governance": {
237
- "policy_evaluation": {
238
- "action": action,
239
- "reason": reason,
240
- "thresholds": policy_engine.thresholds
241
- },
242
- "control_plane_decision": control_decision
243
- }
244
- }
245
- return output, session_state
246
-
247
  # ----------------------------------------------------------------------
248
  # Dashboard plots
249
  # ----------------------------------------------------------------------
@@ -315,6 +318,11 @@ oss_caps = {
315
  "enterprise_features": ["Real-time HMC (using PyMC)", "Hyperpriors", "Decision Engine"]
316
  }
317
 
 
 
 
 
 
318
  # ----------------------------------------------------------------------
319
  # Gradio UI
320
  # ----------------------------------------------------------------------
@@ -329,11 +337,10 @@ with gr.Blocks(title="ARF v4 – Bayesian Risk Scoring Demo", theme="soft") as d
329
  - **Metropolis-Hastings MCMC** – sampling from a posterior distribution (simulating HMC concepts).
330
  - **Autonomous control decisions** – based on the current risk estimate.
331
 
332
- All components are implemented from first principles using only `numpy` and standard libraries.
333
  """)
334
 
335
  with gr.Tabs():
336
- # Tab 1: Control Plane Dashboard
337
  with gr.TabItem("Control Plane Dashboard"):
338
  gr.Markdown("### 🎮 Control Plane")
339
  with gr.Row():
@@ -364,16 +371,8 @@ with gr.Blocks(title="ARF v4 – Bayesian Risk Scoring Demo", theme="soft") as d
364
  outputs=[control_stats, risk_gauge, decision_pie, action_timeline]
365
  )
366
 
367
- # Tab 2: Infrastructure Reliability (Bayesian Risk Update)
368
  with gr.TabItem("Infrastructure Reliability"):
369
  gr.Markdown("### 🏗️ Infrastructure Intent Evaluation with Bayesian Risk")
370
- gr.Markdown("""
371
- This tab simulates evaluating an infrastructure change.
372
- The risk is computed using a **Beta-Binomial conjugate prior**:
373
- - Prior: Beta(α=1, β=1) (uniform)
374
- - Posterior: Beta(α + failures, β + successes)
375
- - Risk = mean of posterior
376
- """)
377
  infra_state = gr.State(value={})
378
  with gr.Row():
379
  with gr.Column():
@@ -386,13 +385,8 @@ with gr.Blocks(title="ARF v4 – Bayesian Risk Scoring Demo", theme="soft") as d
386
  with gr.Column():
387
  infra_output = gr.JSON(label="Analysis Result")
388
 
389
- # Tab 3: Deep Analysis (MCMC)
390
  with gr.TabItem("Deep Analysis (MCMC)"):
391
  gr.Markdown("### Markov Chain Monte Carlo (Metropolis‑Hastings)")
392
- gr.Markdown("""
393
- This sampler approximates the posterior distribution of a **normal mean** given 10 observations.
394
- It demonstrates how MCMC can be used for Bayesian inference without external libraries.
395
- """)
396
  with gr.Row():
397
  with gr.Column():
398
  hmc_samples = gr.Slider(500, 10000, value=5000, step=500, label="Number of Samples")
@@ -404,10 +398,8 @@ with gr.Blocks(title="ARF v4 – Bayesian Risk Scoring Demo", theme="soft") as d
404
  hmc_trace_plot = gr.Plot(label="Trace Plot")
405
  hmc_pair_plot = gr.Plot(label="Posterior Histogram")
406
 
407
- # Tab 4: Policy Management
408
  with gr.TabItem("Policy Management"):
409
  gr.Markdown("### 📋 Execution Policies")
410
- gr.Markdown("Policies define risk thresholds for autonomous actions.")
411
  policies_json = [
412
  {"name": "Low Risk Policy", "conditions": ["risk < 0.2"], "action": "approve", "priority": 1},
413
  {"name": "Medium Risk Policy", "conditions": ["0.2 ≤ risk ≤ 0.8"], "action": "escalate", "priority": 2},
@@ -415,7 +407,6 @@ with gr.Blocks(title="ARF v4 – Bayesian Risk Scoring Demo", theme="soft") as d
415
  ]
416
  gr.JSON(label="Active Policies", value=policies_json)
417
 
418
- # Tab 5: Enterprise / OSS Info
419
  with gr.TabItem("Enterprise / OSS"):
420
  gr.Markdown(f"""
421
  ## 🚀 ARF {oss_caps['edition'].upper()} Edition
 
1
  import gradio as gr
2
+ import asyncio
3
+ import json
4
+ import logging
5
+ import traceback
6
+ import os
7
  import numpy as np
8
  import pandas as pd
9
+ from datetime import datetime
10
+ from typing import Dict, Any, List, Optional
 
11
  import threading
12
  import urllib.request
13
+ import time
14
+ from scipy.stats import beta # only beta is used
 
 
15
 
16
  # ----------------------------------------------------------------------
17
+ # Memory monitoring (no external dependencies)
18
  # ----------------------------------------------------------------------
19
+ def get_memory_usage():
20
+ """Return current process memory usage in MB (RSS)."""
21
+ try:
22
+ import resource
23
+ rss = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
24
+ if rss < 1e9:
25
+ return rss / 1024.0
26
+ else:
27
+ return rss / (1024.0 * 1024.0)
28
+ except ImportError:
29
+ try:
30
+ with open("/proc/self/status") as f:
31
+ for line in f:
32
+ if line.startswith("VmRSS:"):
33
+ parts = line.split()
34
+ if len(parts) >= 2:
35
+ return int(parts[1]) / 1024.0
36
+ except Exception:
37
+ pass
38
+ return None
39
+
40
+ def log_memory_usage():
41
+ mem_mb = get_memory_usage()
42
+ if mem_mb is not None:
43
+ logging.info(f"Process memory: {mem_mb:.1f} MB")
44
+ else:
45
+ logging.info("Process memory: unknown")
46
+ threading.Timer(60, log_memory_usage).start()
47
 
48
  # ----------------------------------------------------------------------
49
  # Keep‑alive (pings public URL every 5 minutes)
 
52
  space_id = os.environ.get('SPACE_ID')
53
  if space_id:
54
  url = f"https://{space_id.replace('/', '-')}.hf.space/"
55
+ logging.info(f"Using external URL for keep‑alive: {url}")
56
  else:
57
  url = "http://127.0.0.1:7860/"
58
+ logging.warning("No SPACE_ID found, using localhost – will not prevent sleep!")
59
+
60
  while True:
61
  time.sleep(300)
62
  try:
63
  with urllib.request.urlopen(url, timeout=10) as response:
64
  status = response.getcode()
65
+ logging.info(f"Keep‑alive ping: {status}")
66
  except Exception as e:
67
+ logging.warning(f"Keep‑alive failed: {e}")
68
 
69
  threading.Thread(target=keep_alive, daemon=True).start()
70
 
71
  # ----------------------------------------------------------------------
72
+ # Plotly
73
  # ----------------------------------------------------------------------
74
+ import plotly.graph_objects as go
 
75
 
76
+ # ----------------------------------------------------------------------
77
+ # Logging
78
+ # ----------------------------------------------------------------------
79
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
80
+ logger = logging.getLogger(__name__)
 
 
81
 
82
  # ----------------------------------------------------------------------
83
+ # Bayesian Risk Engine (BetaBinomial)
84
  # ----------------------------------------------------------------------
85
  class BayesianRiskEngine:
 
 
 
 
 
 
86
  def __init__(self, alpha=1.0, beta=1.0):
87
  self.alpha = alpha
88
  self.beta = beta
89
 
90
  def update(self, failures, successes):
 
91
  self.alpha += failures
92
  self.beta += successes
93
 
94
  def risk(self):
 
95
  return self.alpha / (self.alpha + self.beta)
96
 
97
  def risk_interval(self, prob=0.95):
98
+ """Return credible interval using scipy.stats.beta."""
99
+ lo = beta.ppf((1 - prob) / 2, self.alpha, self.beta)
100
+ hi = beta.ppf((1 + prob) / 2, self.alpha, self.beta)
101
+ return lo, hi
 
 
102
 
103
  # ----------------------------------------------------------------------
104
+ # Policy Engine
105
  # ----------------------------------------------------------------------
106
  class PolicyEngine:
107
  def __init__(self, thresholds={"low": 0.2, "high": 0.8}):
 
116
  return "escalate", f"Risk in escalation zone ({self.thresholds['low']}-{self.thresholds['high']})"
117
 
118
  # ----------------------------------------------------------------------
119
+ # History
120
  # ----------------------------------------------------------------------
121
+ decision_history = []
122
+ risk_history = []
123
+
124
+ def update_dashboard_data(decision, risk):
125
+ decision_history.append((datetime.utcnow().isoformat(), decision, risk))
126
+ risk_history.append((datetime.utcnow().isoformat(), risk))
127
+ if len(decision_history) > 100:
128
+ decision_history.pop(0)
129
+ if len(risk_history) > 100:
130
+ risk_history.pop(0)
131
+
132
  def autonomous_control_decision(risk, risk_engine, policy_engine):
133
  action, reason = policy_engine.evaluate(risk)
134
  decision = {
 
142
  return decision
143
 
144
  # ----------------------------------------------------------------------
145
+ # Infrastructure analysis
146
+ # ----------------------------------------------------------------------
147
+ async def handle_infra_with_governance(fault_type, context_window, session_state):
148
+ fault_map = {
149
+ "none": (1, 99),
150
+ "switch_down": (20, 80),
151
+ "server_overload": (35, 65),
152
+ "cascade": (60, 40)
153
+ }
154
+ failures, successes = fault_map.get(fault_type, (1, 99))
155
+ severity = "low" if failures < 10 else "medium" if failures < 40 else "high"
156
+
157
+ risk_engine = BayesianRiskEngine(alpha=1, beta=1)
158
+ risk_engine.update(failures, successes)
159
+ risk = risk_engine.risk()
160
+ ci_low, ci_high = risk_engine.risk_interval(0.95)
161
+
162
+ policy_engine = PolicyEngine(thresholds={"low": 0.2, "high": 0.8})
163
+ action, reason = policy_engine.evaluate(risk)
164
+ control_decision = autonomous_control_decision(risk, risk_engine, policy_engine)
165
+
166
+ analysis_result = {
167
+ "risk": risk,
168
+ "risk_ci": [ci_low, ci_high],
169
+ "decision": action,
170
+ "justification": reason,
171
+ "healing_actions": ["restart"] if action == "deny" else ["monitor"],
172
+ "posterior_parameters": {
173
+ "alpha": risk_engine.alpha,
174
+ "beta": risk_engine.beta
175
+ }
176
+ }
177
+ output = {
178
+ **analysis_result,
179
+ "governance": {
180
+ "policy_evaluation": {
181
+ "action": action,
182
+ "reason": reason,
183
+ "thresholds": policy_engine.thresholds
184
+ },
185
+ "control_plane_decision": control_decision
186
+ }
187
+ }
188
+ return output, session_state
189
+
190
+ # ----------------------------------------------------------------------
191
+ # MCMC (Metropolis‑Hastings) – no scipy needed
192
  # ----------------------------------------------------------------------
193
  class MHMCMC:
 
194
  def __init__(self, log_target, proposal_sd=0.1):
195
  self.log_target = log_target
196
  self.proposal_sd = proposal_sd
 
201
  current_log = self.log_target(current)
202
  accepted = 0
203
  for i in range(n_samples + burn_in):
 
204
  proposal = current + np.random.normal(0, self.proposal_sd, size=len(current))
205
  proposal_log = self.log_target(proposal)
 
206
  accept_prob = min(1, np.exp(proposal_log - current_log))
207
  if np.random.rand() < accept_prob:
208
  current = proposal
 
213
  acceptance_rate = accepted / (n_samples + burn_in)
214
  return samples, acceptance_rate
215
 
 
 
 
216
  def run_hmc_mcmc(samples, warmup):
217
+ # Generate data: 10 observations with mean 0.5, std 0.2
 
 
 
 
218
  data = np.random.normal(0.5, 0.2, 10)
 
 
219
  def log_prior(mu):
220
+ return -0.5 * (mu ** 2) # prior N(0,1)
 
 
221
  def log_likelihood(mu):
222
+ return -0.5 * np.sum(((data - mu) / 0.2) ** 2)
 
223
  def log_posterior(mu):
224
  return log_prior(mu) + log_likelihood(mu)
225
 
 
226
  sampler = MHMCMC(log_posterior, proposal_sd=0.05)
227
  mu_samples, acceptance = sampler.sample(samples, initial_state=[0.0], burn_in=warmup)
 
 
228
  mu_samples = mu_samples.flatten()
229
+
230
  mean = np.mean(mu_samples)
231
  median = np.median(mu_samples)
232
  credible_interval = np.percentile(mu_samples, [2.5, 97.5])
233
 
 
234
  fig_trace = go.Figure()
235
  fig_trace.add_trace(go.Scatter(y=mu_samples, mode='lines', name='μ', line=dict(width=1)))
236
  fig_trace.update_layout(title="Trace of μ (Metropolis-Hastings)", xaxis_title="Iteration", yaxis_title="μ")
237
 
 
238
  fig_hist = go.Figure()
239
  fig_hist.add_trace(go.Histogram(x=mu_samples, nbinsx=50, name='Posterior'))
240
  fig_hist.update_layout(title="Posterior Distribution of μ", xaxis_title="μ", yaxis_title="Density")
 
247
  }
248
  return summary, fig_trace, fig_hist
249
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
  # ----------------------------------------------------------------------
251
  # Dashboard plots
252
  # ----------------------------------------------------------------------
 
318
  "enterprise_features": ["Real-time HMC (using PyMC)", "Hyperpriors", "Decision Engine"]
319
  }
320
 
321
+ # ----------------------------------------------------------------------
322
+ # Start memory monitoring
323
+ # ----------------------------------------------------------------------
324
+ log_memory_usage()
325
+
326
  # ----------------------------------------------------------------------
327
  # Gradio UI
328
  # ----------------------------------------------------------------------
 
337
  - **Metropolis-Hastings MCMC** – sampling from a posterior distribution (simulating HMC concepts).
338
  - **Autonomous control decisions** – based on the current risk estimate.
339
 
340
+ All components are implemented with only `numpy`, `scipy`, and standard libraries.
341
  """)
342
 
343
  with gr.Tabs():
 
344
  with gr.TabItem("Control Plane Dashboard"):
345
  gr.Markdown("### 🎮 Control Plane")
346
  with gr.Row():
 
371
  outputs=[control_stats, risk_gauge, decision_pie, action_timeline]
372
  )
373
 
 
374
  with gr.TabItem("Infrastructure Reliability"):
375
  gr.Markdown("### 🏗️ Infrastructure Intent Evaluation with Bayesian Risk")
 
 
 
 
 
 
 
376
  infra_state = gr.State(value={})
377
  with gr.Row():
378
  with gr.Column():
 
385
  with gr.Column():
386
  infra_output = gr.JSON(label="Analysis Result")
387
 
 
388
  with gr.TabItem("Deep Analysis (MCMC)"):
389
  gr.Markdown("### Markov Chain Monte Carlo (Metropolis‑Hastings)")
 
 
 
 
390
  with gr.Row():
391
  with gr.Column():
392
  hmc_samples = gr.Slider(500, 10000, value=5000, step=500, label="Number of Samples")
 
398
  hmc_trace_plot = gr.Plot(label="Trace Plot")
399
  hmc_pair_plot = gr.Plot(label="Posterior Histogram")
400
 
 
401
  with gr.TabItem("Policy Management"):
402
  gr.Markdown("### 📋 Execution Policies")
 
403
  policies_json = [
404
  {"name": "Low Risk Policy", "conditions": ["risk < 0.2"], "action": "approve", "priority": 1},
405
  {"name": "Medium Risk Policy", "conditions": ["0.2 ≤ risk ≤ 0.8"], "action": "escalate", "priority": 2},
 
407
  ]
408
  gr.JSON(label="Active Policies", value=policies_json)
409
 
 
410
  with gr.TabItem("Enterprise / OSS"):
411
  gr.Markdown(f"""
412
  ## 🚀 ARF {oss_caps['edition'].upper()} Edition