Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -8,6 +8,7 @@ import torch
|
|
| 8 |
import numpy as np
|
| 9 |
import pandas as pd
|
| 10 |
from datetime import datetime
|
|
|
|
| 11 |
|
| 12 |
# ----------------------------------------------------------------------
|
| 13 |
# Logging setup
|
|
@@ -18,6 +19,7 @@ logger = logging.getLogger(__name__)
|
|
| 18 |
# ARF components
|
| 19 |
from agentic_reliability_framework.runtime.engine import EnhancedReliabilityEngine
|
| 20 |
from agentic_reliability_framework.core.models.event import ReliabilityEvent
|
|
|
|
| 21 |
|
| 22 |
# Custom AI components
|
| 23 |
from ai_event import AIEvent
|
|
@@ -44,17 +46,20 @@ try:
|
|
| 44 |
INFRA_DEPS_AVAILABLE = True
|
| 45 |
logger.info("Infrastructure reliability modules loaded.")
|
| 46 |
except ImportError as e:
|
| 47 |
-
logger.warning(f"Infrastructure modules not fully available: {e}. The Infrastructure tab will
|
| 48 |
|
| 49 |
# ----------------------------------------------------------------------
|
| 50 |
-
# ARF infrastructure engine
|
| 51 |
# ----------------------------------------------------------------------
|
| 52 |
try:
|
| 53 |
logger.info("Initializing EnhancedReliabilityEngine...")
|
| 54 |
infra_engine = EnhancedReliabilityEngine()
|
|
|
|
|
|
|
| 55 |
except Exception as e:
|
| 56 |
logger.error(f"Infrastructure engine init failed: {e}")
|
| 57 |
infra_engine = None
|
|
|
|
| 58 |
|
| 59 |
# ----------------------------------------------------------------------
|
| 60 |
# Text generation model (DialoGPT-small) with logprobs
|
|
@@ -99,12 +104,12 @@ def generate_with_logprobs(prompt, max_new_tokens=100):
|
|
| 99 |
nli_detector = NLIDetector()
|
| 100 |
|
| 101 |
# ----------------------------------------------------------------------
|
| 102 |
-
# Retrieval
|
| 103 |
# ----------------------------------------------------------------------
|
| 104 |
retriever = SimpleRetriever()
|
| 105 |
|
| 106 |
# ----------------------------------------------------------------------
|
| 107 |
-
# Image generation
|
| 108 |
# ----------------------------------------------------------------------
|
| 109 |
from diffusers import StableDiffusionPipeline
|
| 110 |
image_pipe = None
|
|
@@ -121,7 +126,7 @@ except Exception as e:
|
|
| 121 |
image_pipe = None
|
| 122 |
|
| 123 |
# ----------------------------------------------------------------------
|
| 124 |
-
# Audio transcription
|
| 125 |
# ----------------------------------------------------------------------
|
| 126 |
from transformers import pipeline
|
| 127 |
audio_pipe = None
|
|
@@ -155,10 +160,9 @@ ai_risk_engine = AIRiskEngine()
|
|
| 155 |
iot_sim = IoTSimulator()
|
| 156 |
|
| 157 |
# ----------------------------------------------------------------------
|
| 158 |
-
# Infrastructure components
|
| 159 |
# ----------------------------------------------------------------------
|
| 160 |
if INFRA_DEPS_AVAILABLE:
|
| 161 |
-
# Use environment variables for Neo4j if provided, else mock
|
| 162 |
infra_sim = InfraSimulator()
|
| 163 |
infra_graph = InfraGraph(
|
| 164 |
uri=os.getenv("NEO4J_URI"),
|
|
@@ -168,35 +172,101 @@ if INFRA_DEPS_AVAILABLE:
|
|
| 168 |
gnn_model = FailureGNN()
|
| 169 |
ontology = InfraOntology()
|
| 170 |
else:
|
| 171 |
-
infra_sim = None
|
| 172 |
infra_graph = None
|
| 173 |
gnn_model = None
|
| 174 |
ontology = None
|
| 175 |
|
| 176 |
-
#
|
| 177 |
-
# Helper: update risk with feedback (global state – shared across users)
|
| 178 |
-
# ----------------------------------------------------------------------
|
| 179 |
-
last_task_category = None
|
| 180 |
|
| 181 |
-
def
|
| 182 |
-
"""
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
return
|
| 186 |
-
|
| 187 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
|
| 189 |
-
# ----------------------------------------------------------------------
|
| 190 |
-
# Async handlers for each tab
|
| 191 |
-
# ----------------------------------------------------------------------
|
| 192 |
async def handle_text(task_type, prompt):
|
| 193 |
-
"""Handle text generation and
|
| 194 |
global last_task_category
|
| 195 |
last_task_category = task_type
|
|
|
|
| 196 |
try:
|
| 197 |
logger.info(f"Handling text task: {task_type}, prompt: {prompt[:50]}...")
|
|
|
|
|
|
|
| 198 |
response, avg_log_prob = generate_with_logprobs(prompt)
|
| 199 |
retrieval_score = retriever.get_similarity(prompt)
|
|
|
|
|
|
|
| 200 |
event = AIEvent(
|
| 201 |
timestamp=datetime.utcnow(),
|
| 202 |
component="ai",
|
|
@@ -218,10 +288,14 @@ async def handle_text(task_type, prompt):
|
|
| 218 |
user_feedback=None,
|
| 219 |
latency_ms=0
|
| 220 |
)
|
|
|
|
|
|
|
| 221 |
hallu_result = await hallucination_detective.analyze(event)
|
| 222 |
drift_result = await memory_drift_diagnostician.analyze(event)
|
| 223 |
risk_metrics = ai_risk_engine.risk_score(task_type)
|
| 224 |
-
|
|
|
|
|
|
|
| 225 |
"response": response,
|
| 226 |
"avg_log_prob": avg_log_prob,
|
| 227 |
"confidence": event.confidence,
|
|
@@ -230,273 +304,152 @@ async def handle_text(task_type, prompt):
|
|
| 230 |
"memory_drift_detection": drift_result,
|
| 231 |
"risk_metrics": risk_metrics
|
| 232 |
}
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
global last_task_category
|
| 240 |
-
last_task_category = "image"
|
| 241 |
-
if image_pipe is None:
|
| 242 |
-
return None, {"error": "Image model not loaded"}
|
| 243 |
-
try:
|
| 244 |
-
import time
|
| 245 |
-
start = time.time()
|
| 246 |
-
image = image_pipe(prompt, num_inference_steps=steps).images[0]
|
| 247 |
-
gen_time = time.time() - start
|
| 248 |
-
retrieval_score = retriever.get_similarity(prompt)
|
| 249 |
-
event = AIEvent(
|
| 250 |
-
timestamp=datetime.utcnow(),
|
| 251 |
-
component="image",
|
| 252 |
-
service_mesh="ai",
|
| 253 |
-
latency_p99=0,
|
| 254 |
-
error_rate=0.0,
|
| 255 |
-
throughput=1,
|
| 256 |
-
cpu_util=None,
|
| 257 |
-
memory_util=None,
|
| 258 |
-
action_category="image",
|
| 259 |
-
model_name="tiny-sd",
|
| 260 |
-
model_version="latest",
|
| 261 |
-
prompt=prompt,
|
| 262 |
-
response="",
|
| 263 |
-
response_length=0,
|
| 264 |
-
confidence=1.0 / (gen_time + 1),
|
| 265 |
-
perplexity=None,
|
| 266 |
-
retrieval_scores=[retrieval_score, gen_time],
|
| 267 |
-
user_feedback=None,
|
| 268 |
-
latency_ms=gen_time * 1000
|
| 269 |
)
|
| 270 |
-
quality_result = await image_quality_detector.analyze(event)
|
| 271 |
-
json_data = {
|
| 272 |
-
"generation_time": gen_time,
|
| 273 |
-
"retrieval_score": retrieval_score,
|
| 274 |
-
"quality_detection": quality_result
|
| 275 |
-
}
|
| 276 |
-
return image, json_data
|
| 277 |
-
except Exception as e:
|
| 278 |
-
logger.error(f"Image task error: {e}", exc_info=True)
|
| 279 |
-
return None, {"error": str(e), "traceback": traceback.format_exc()}
|
| 280 |
-
|
| 281 |
-
async def handle_audio(audio_file):
|
| 282 |
-
"""Handle audio transcription and quality analysis."""
|
| 283 |
-
global last_task_category
|
| 284 |
-
last_task_category = "audio"
|
| 285 |
-
if audio_pipe is None:
|
| 286 |
-
return {"error": "Audio model not loaded"}
|
| 287 |
-
if audio_file is None:
|
| 288 |
-
return {"error": "No audio file provided"}
|
| 289 |
-
try:
|
| 290 |
-
import librosa
|
| 291 |
-
import soundfile as sf
|
| 292 |
-
import tempfile
|
| 293 |
|
| 294 |
-
|
| 295 |
-
audio, sr = librosa.load(audio_file, sr=16000)
|
| 296 |
-
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
|
| 297 |
-
tmp_path = tmp.name
|
| 298 |
-
sf.write(tmp_path, audio, sr)
|
| 299 |
|
| 300 |
-
#
|
| 301 |
-
|
| 302 |
-
|
|
|
|
|
|
|
| 303 |
|
| 304 |
-
|
| 305 |
-
os.unlink(tmp_path)
|
| 306 |
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
timestamp=datetime.utcnow(),
|
| 310 |
-
component="audio",
|
| 311 |
-
service_mesh="ai",
|
| 312 |
-
latency_p99=0,
|
| 313 |
-
error_rate=0.0,
|
| 314 |
-
throughput=1,
|
| 315 |
-
cpu_util=None,
|
| 316 |
-
memory_util=None,
|
| 317 |
-
action_category="audio",
|
| 318 |
-
model_name="whisper-tiny.en",
|
| 319 |
-
model_version="latest",
|
| 320 |
-
prompt="",
|
| 321 |
-
response=text,
|
| 322 |
-
response_length=len(text),
|
| 323 |
-
confidence=float(np.exp(avg_log_prob)),
|
| 324 |
-
perplexity=None,
|
| 325 |
-
retrieval_scores=[avg_log_prob],
|
| 326 |
-
user_feedback=None,
|
| 327 |
-
latency_ms=0
|
| 328 |
-
)
|
| 329 |
-
quality_result = await audio_quality_detector.analyze(event)
|
| 330 |
return {
|
| 331 |
-
"
|
| 332 |
-
"
|
| 333 |
-
"
|
| 334 |
-
|
|
|
|
|
|
|
| 335 |
}
|
| 336 |
-
except Exception as e:
|
| 337 |
-
logger.error(f"Audio task error: {e}", exc_info=True)
|
| 338 |
-
return {"error": str(e), "traceback": traceback.format_exc()}
|
| 339 |
-
|
| 340 |
-
async def read_iot_sensors(fault_type, history_state):
|
| 341 |
-
"""Read simulated IoT sensors, run diagnostics, predict failure, and return updated plot data."""
|
| 342 |
-
global last_task_category
|
| 343 |
-
last_task_category = "iot"
|
| 344 |
-
try:
|
| 345 |
-
iot_sim.set_fault(fault_type if fault_type != "none" else None)
|
| 346 |
-
data = iot_sim.read()
|
| 347 |
-
history_state.append(data)
|
| 348 |
-
if len(history_state) > 100:
|
| 349 |
-
history_state.pop(0)
|
| 350 |
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
timestamp=datetime.utcnow(),
|
| 354 |
-
component="robotic-arm",
|
| 355 |
-
service_mesh="factory",
|
| 356 |
-
latency_p99=0,
|
| 357 |
-
error_rate=0.0,
|
| 358 |
-
throughput=1,
|
| 359 |
-
cpu_util=None,
|
| 360 |
-
memory_util=None,
|
| 361 |
-
temperature=data['temperature'],
|
| 362 |
-
vibration=data['vibration'],
|
| 363 |
-
motor_current=data['motor_current'],
|
| 364 |
-
position_error=data['position_error']
|
| 365 |
-
)
|
| 366 |
-
diag_result = await robotics_diagnostician.analyze(event)
|
| 367 |
-
|
| 368 |
-
# Simple failure prediction
|
| 369 |
-
prediction = None
|
| 370 |
-
if len(history_state) >= 5:
|
| 371 |
-
temps = [h['temperature'] for h in history_state[-5:]]
|
| 372 |
-
x = np.arange(len(temps))
|
| 373 |
-
slope, intercept = np.polyfit(x, temps, 1)
|
| 374 |
-
next_temp = slope * len(temps) + intercept
|
| 375 |
-
if slope > 0.1:
|
| 376 |
-
time_to_threshold = (40.0 - next_temp) / slope if slope > 0 else None
|
| 377 |
-
prediction = {
|
| 378 |
-
"predicted_temperature": float(next_temp),
|
| 379 |
-
"time_to_overheat_min": float(time_to_threshold) if time_to_threshold else None
|
| 380 |
-
}
|
| 381 |
-
|
| 382 |
-
# Prepare temperature history for plotting
|
| 383 |
-
temp_history = [h['temperature'] for h in history_state[-20:]]
|
| 384 |
-
df = pd.DataFrame({
|
| 385 |
-
"index": list(range(len(temp_history))),
|
| 386 |
-
"temperature": temp_history
|
| 387 |
-
})
|
| 388 |
-
|
| 389 |
-
return data, diag_result, prediction, df, history_state
|
| 390 |
-
except Exception as e:
|
| 391 |
-
logger.error(f"IoT task error: {e}", exc_info=True)
|
| 392 |
-
return {"error": str(e)}, {"error": str(e)}, {"error": str(e)}, pd.DataFrame({"index": [], "temperature": []}), history_state
|
| 393 |
-
|
| 394 |
-
# ========== Infrastructure Reliability Handler ==========
|
| 395 |
-
async def handle_infra(fault_type, session_state):
|
| 396 |
-
"""Run infrastructure reliability analysis."""
|
| 397 |
if not INFRA_DEPS_AVAILABLE:
|
| 398 |
-
return {
|
| 399 |
-
|
|
|
|
|
|
|
|
|
|
| 400 |
try:
|
| 401 |
-
#
|
| 402 |
if "sim" not in session_state or session_state["sim"] is None:
|
| 403 |
session_state["sim"] = InfraSimulator()
|
| 404 |
sim = session_state["sim"]
|
| 405 |
-
|
| 406 |
# Inject fault
|
| 407 |
sim.set_fault(fault_type if fault_type != "none" else None)
|
| 408 |
components = sim.read_state()
|
| 409 |
-
|
| 410 |
# Update graph
|
| 411 |
if infra_graph:
|
| 412 |
infra_graph.update_from_state(components)
|
| 413 |
-
|
| 414 |
-
#
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 426 |
# Combine results
|
| 427 |
output = {
|
| 428 |
"topology": components,
|
| 429 |
-
"bayesian_risk":
|
| 430 |
-
"gnn_predictions":
|
| 431 |
-
"logic_explanations":
|
| 432 |
-
"ontology":
|
|
|
|
|
|
|
|
|
|
|
|
|
| 433 |
}
|
|
|
|
| 434 |
return output, session_state
|
|
|
|
| 435 |
except Exception as e:
|
| 436 |
logger.error(f"Infra task error: {e}", exc_info=True)
|
| 437 |
-
return {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 438 |
|
| 439 |
# ----------------------------------------------------------------------
|
| 440 |
-
# Gradio UI
|
| 441 |
# ----------------------------------------------------------------------
|
| 442 |
-
with gr.Blocks(title="ARF v4 – AI
|
| 443 |
-
gr.Markdown("
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 444 |
|
| 445 |
with gr.Tabs():
|
| 446 |
-
# Tab 1:
|
| 447 |
-
with gr.TabItem("
|
| 448 |
-
|
| 449 |
-
text_prompt = gr.Textbox(label="Prompt", value="What is the capital of France?", lines=3)
|
| 450 |
-
text_btn = gr.Button("Generate")
|
| 451 |
-
text_output = gr.JSON(label="Analysis")
|
| 452 |
-
|
| 453 |
-
# Tab 2: Image Generation
|
| 454 |
-
with gr.TabItem("Image Generation"):
|
| 455 |
-
img_prompt = gr.Textbox(label="Prompt", value="A cat wearing a hat")
|
| 456 |
-
img_steps = gr.Slider(1, 10, value=2, step=1, label="Inference Steps")
|
| 457 |
-
img_btn = gr.Button("Generate")
|
| 458 |
-
img_output = gr.Image(label="Generated Image")
|
| 459 |
-
img_json = gr.JSON(label="Analysis")
|
| 460 |
-
|
| 461 |
-
# Tab 3: Audio Transcription
|
| 462 |
-
with gr.TabItem("Audio Transcription"):
|
| 463 |
-
gr.Markdown("Upload an audio file to transcribe")
|
| 464 |
-
audio_input = gr.Audio(type="filepath", label="Upload audio file")
|
| 465 |
-
audio_btn = gr.Button("Transcribe")
|
| 466 |
-
audio_output = gr.JSON(label="Analysis")
|
| 467 |
-
|
| 468 |
-
# Tab 4: Robotics / IoT
|
| 469 |
-
with gr.TabItem("Robotics / IoT"):
|
| 470 |
-
gr.Markdown("### Simulated Robotic Arm Monitoring")
|
| 471 |
-
iot_state = gr.State(value=[])
|
| 472 |
-
|
| 473 |
-
with gr.Row():
|
| 474 |
-
with gr.Column():
|
| 475 |
-
fault_type = gr.Dropdown(
|
| 476 |
-
["none", "overheat", "vibration", "stall", "drift"],
|
| 477 |
-
value="none",
|
| 478 |
-
label="Inject Fault"
|
| 479 |
-
)
|
| 480 |
-
refresh_btn = gr.Button("Read Sensors")
|
| 481 |
-
with gr.Column():
|
| 482 |
-
sensor_display = gr.JSON(label="Sensor Readings")
|
| 483 |
with gr.Row():
|
| 484 |
with gr.Column():
|
| 485 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 486 |
with gr.Column():
|
| 487 |
-
|
| 488 |
-
|
| 489 |
-
|
| 490 |
-
|
| 491 |
-
|
| 492 |
-
|
| 493 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 494 |
|
| 495 |
-
# Tab
|
| 496 |
with gr.TabItem("Infrastructure Reliability"):
|
| 497 |
-
gr.Markdown("### Neuro‑Symbolic Infrastructure
|
| 498 |
infra_state = gr.State(value={})
|
| 499 |
-
|
| 500 |
with gr.Row():
|
| 501 |
with gr.Column():
|
| 502 |
infra_fault = gr.Dropdown(
|
|
@@ -504,25 +457,64 @@ with gr.Blocks(title="ARF v4 – AI Reliability Lab", theme="soft") as demo:
|
|
| 504 |
value="none",
|
| 505 |
label="Inject Fault"
|
| 506 |
)
|
| 507 |
-
infra_btn = gr.Button("Run Analysis")
|
| 508 |
with gr.Column():
|
| 509 |
-
infra_output = gr.JSON(label="Analysis
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 510 |
|
| 511 |
-
# Tab
|
| 512 |
with gr.TabItem("Enterprise"):
|
| 513 |
gr.Markdown("""
|
| 514 |
-
## 🚀 ARF Enterprise –
|
| 515 |
-
|
| 516 |
-
Take ARF to production with enterprise‑grade safety, compliance, and learning.
|
| 517 |
-
|
| 518 |
### Key Enterprise Features:
|
| 519 |
-
- **
|
| 520 |
-
- **Audit Trails & Compliance** – Full traceability for SOC2, HIPAA, GDPR
|
| 521 |
-
- **Learning Loops** – Models improve over time with your data
|
| 522 |
-
- **Multi‑Tenant Control** – Role‑based access and isolation
|
| 523 |
-
- **Cloud Integrations** – Azure, AWS, GCP native clients
|
| 524 |
-
- **24/7 Support & SLAs** – Enterprise‑grade reliability
|
| 525 |
-
|
| 526 |
### Get Started
|
| 527 |
- 📅 [Book a Demo](https://calendly.com/petter2025us/30min)
|
| 528 |
- 📧 [Contact Sales](mailto:petter2025us@outlook.com)
|
|
@@ -530,8 +522,8 @@ with gr.Blocks(title="ARF v4 – AI Reliability Lab", theme="soft") as demo:
|
|
| 530 |
|
| 531 |
# Feedback row
|
| 532 |
with gr.Row():
|
| 533 |
-
feedback_up = gr.Button("👍
|
| 534 |
-
feedback_down = gr.Button("👎
|
| 535 |
feedback_msg = gr.Textbox(label="Feedback", interactive=False)
|
| 536 |
|
| 537 |
# Wire events
|
|
@@ -540,28 +532,27 @@ with gr.Blocks(title="ARF v4 – AI Reliability Lab", theme="soft") as demo:
|
|
| 540 |
inputs=[text_task, text_prompt],
|
| 541 |
outputs=text_output
|
| 542 |
)
|
| 543 |
-
|
| 544 |
-
fn=lambda p, s: asyncio.run(handle_image(p, s)),
|
| 545 |
-
inputs=[img_prompt, img_steps],
|
| 546 |
-
outputs=[img_output, img_json]
|
| 547 |
-
)
|
| 548 |
-
audio_btn.click(
|
| 549 |
-
fn=lambda f: asyncio.run(handle_audio(f)),
|
| 550 |
-
inputs=audio_input,
|
| 551 |
-
outputs=audio_output
|
| 552 |
-
)
|
| 553 |
-
refresh_btn.click(
|
| 554 |
-
fn=lambda f, h: asyncio.run(read_iot_sensors(f, h)),
|
| 555 |
-
inputs=[fault_type, iot_state],
|
| 556 |
-
outputs=[sensor_display, diag_display, pred_display, temp_plot, iot_state]
|
| 557 |
-
)
|
| 558 |
infra_btn.click(
|
| 559 |
-
fn=lambda f, s: asyncio.run(
|
| 560 |
inputs=[infra_fault, infra_state],
|
| 561 |
outputs=[infra_output, infra_state]
|
| 562 |
)
|
| 563 |
-
|
| 564 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 565 |
|
| 566 |
if __name__ == "__main__":
|
| 567 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|
|
|
|
| 8 |
import numpy as np
|
| 9 |
import pandas as pd
|
| 10 |
from datetime import datetime
|
| 11 |
+
from typing import Dict, Any, List, Optional
|
| 12 |
|
| 13 |
# ----------------------------------------------------------------------
|
| 14 |
# Logging setup
|
|
|
|
| 19 |
# ARF components
|
| 20 |
from agentic_reliability_framework.runtime.engine import EnhancedReliabilityEngine
|
| 21 |
from agentic_reliability_framework.core.models.event import ReliabilityEvent
|
| 22 |
+
from policy_engine import PolicyEngine
|
| 23 |
|
| 24 |
# Custom AI components
|
| 25 |
from ai_event import AIEvent
|
|
|
|
| 46 |
INFRA_DEPS_AVAILABLE = True
|
| 47 |
logger.info("Infrastructure reliability modules loaded.")
|
| 48 |
except ImportError as e:
|
| 49 |
+
logger.warning(f"Infrastructure modules not fully available: {e}. The Infrastructure tab will use mock mode.")
|
| 50 |
|
| 51 |
# ----------------------------------------------------------------------
|
| 52 |
+
# ARF infrastructure engine
|
| 53 |
# ----------------------------------------------------------------------
|
| 54 |
try:
|
| 55 |
logger.info("Initializing EnhancedReliabilityEngine...")
|
| 56 |
infra_engine = EnhancedReliabilityEngine()
|
| 57 |
+
policy_engine = PolicyEngine()
|
| 58 |
+
logger.info("Policy Engine initialized with 5 policies")
|
| 59 |
except Exception as e:
|
| 60 |
logger.error(f"Infrastructure engine init failed: {e}")
|
| 61 |
infra_engine = None
|
| 62 |
+
policy_engine = PolicyEngine() # Fallback
|
| 63 |
|
| 64 |
# ----------------------------------------------------------------------
|
| 65 |
# Text generation model (DialoGPT-small) with logprobs
|
|
|
|
| 104 |
nli_detector = NLIDetector()
|
| 105 |
|
| 106 |
# ----------------------------------------------------------------------
|
| 107 |
+
# Retrieval
|
| 108 |
# ----------------------------------------------------------------------
|
| 109 |
retriever = SimpleRetriever()
|
| 110 |
|
| 111 |
# ----------------------------------------------------------------------
|
| 112 |
+
# Image generation
|
| 113 |
# ----------------------------------------------------------------------
|
| 114 |
from diffusers import StableDiffusionPipeline
|
| 115 |
image_pipe = None
|
|
|
|
| 126 |
image_pipe = None
|
| 127 |
|
| 128 |
# ----------------------------------------------------------------------
|
| 129 |
+
# Audio transcription
|
| 130 |
# ----------------------------------------------------------------------
|
| 131 |
from transformers import pipeline
|
| 132 |
audio_pipe = None
|
|
|
|
| 160 |
iot_sim = IoTSimulator()
|
| 161 |
|
| 162 |
# ----------------------------------------------------------------------
|
| 163 |
+
# Infrastructure components
|
| 164 |
# ----------------------------------------------------------------------
|
| 165 |
if INFRA_DEPS_AVAILABLE:
|
|
|
|
| 166 |
infra_sim = InfraSimulator()
|
| 167 |
infra_graph = InfraGraph(
|
| 168 |
uri=os.getenv("NEO4J_URI"),
|
|
|
|
| 172 |
gnn_model = FailureGNN()
|
| 173 |
ontology = InfraOntology()
|
| 174 |
else:
|
| 175 |
+
infra_sim = InfraSimulator() if INFRA_DEPS_AVAILABLE else None
|
| 176 |
infra_graph = None
|
| 177 |
gnn_model = None
|
| 178 |
ontology = None
|
| 179 |
|
| 180 |
+
# ========== Execution Governance Functions ==========
|
|
|
|
|
|
|
|
|
|
| 181 |
|
| 182 |
+
def evaluate_policies(event_type: str, severity: str, component: str) -> Dict[str, Any]:
|
| 183 |
+
"""Evaluate policies against an event and return recommended actions."""
|
| 184 |
+
try:
|
| 185 |
+
actions = policy_engine.evaluate(event_type, severity, component)
|
| 186 |
+
return {
|
| 187 |
+
"timestamp": datetime.utcnow().isoformat(),
|
| 188 |
+
"event_type": event_type,
|
| 189 |
+
"severity": severity,
|
| 190 |
+
"component": component,
|
| 191 |
+
"recommended_actions": actions,
|
| 192 |
+
"governance_status": "approved" if actions else "blocked"
|
| 193 |
+
}
|
| 194 |
+
except Exception as e:
|
| 195 |
+
logger.error(f"Policy evaluation error: {e}")
|
| 196 |
+
return {
|
| 197 |
+
"error": str(e),
|
| 198 |
+
"governance_status": "error",
|
| 199 |
+
"recommended_actions": []
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
def autonomous_control_decision(analysis_result: Dict[str, Any], risk_threshold: float = 0.7) -> Dict[str, Any]:
|
| 203 |
+
"""
|
| 204 |
+
Make autonomous control decision based on analysis and risk metrics.
|
| 205 |
+
This simulates an AI Control Plane that can take actions automatically.
|
| 206 |
+
"""
|
| 207 |
+
decision = {
|
| 208 |
+
"timestamp": datetime.utcnow().isoformat(),
|
| 209 |
+
"approved": False,
|
| 210 |
+
"actions": [],
|
| 211 |
+
"reason": "",
|
| 212 |
+
"risk_level": "unknown"
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
try:
|
| 216 |
+
# Extract risk metrics
|
| 217 |
+
risk_metrics = analysis_result.get("risk_metrics", {})
|
| 218 |
+
mean_risk = risk_metrics.get("mean", 0.5)
|
| 219 |
+
p95_risk = risk_metrics.get("p95", 0.7)
|
| 220 |
+
|
| 221 |
+
# Determine risk level
|
| 222 |
+
if mean_risk > risk_threshold or p95_risk > risk_threshold:
|
| 223 |
+
decision["risk_level"] = "high"
|
| 224 |
+
decision["approved"] = False
|
| 225 |
+
decision["reason"] = f"Risk exceeds threshold (mean={mean_risk:.2f}, p95={p95_risk:.2f})"
|
| 226 |
+
else:
|
| 227 |
+
decision["risk_level"] = "low"
|
| 228 |
+
decision["approved"] = True
|
| 229 |
+
decision["reason"] = "Risk within acceptable limits"
|
| 230 |
+
|
| 231 |
+
# Generate autonomous actions based on findings
|
| 232 |
+
if "hallucination_detection" in analysis_result:
|
| 233 |
+
hallu = analysis_result["hallucination_detection"]
|
| 234 |
+
if hallu.get("findings", {}).get("is_hallucination"):
|
| 235 |
+
decision["actions"].append({
|
| 236 |
+
"action": "regenerate",
|
| 237 |
+
"params": {"temperature": 0.3},
|
| 238 |
+
"reason": "Hallucination detected"
|
| 239 |
+
})
|
| 240 |
+
|
| 241 |
+
if "memory_drift_detection" in analysis_result:
|
| 242 |
+
drift = analysis_result["memory_drift_detection"]
|
| 243 |
+
if drift.get("findings", {}).get("drift_detected"):
|
| 244 |
+
decision["actions"].append({
|
| 245 |
+
"action": "reset_context",
|
| 246 |
+
"params": {},
|
| 247 |
+
"reason": "Memory drift detected"
|
| 248 |
+
})
|
| 249 |
+
except Exception as e:
|
| 250 |
+
logger.error(f"Control decision error: {e}")
|
| 251 |
+
decision["reason"] = f"Error in decision process: {str(e)}"
|
| 252 |
+
|
| 253 |
+
return decision
|
| 254 |
+
|
| 255 |
+
# ========== Async Handlers with Governance ==========
|
| 256 |
|
|
|
|
|
|
|
|
|
|
| 257 |
async def handle_text(task_type, prompt):
|
| 258 |
+
"""Handle text generation with governance and control plane decisions."""
|
| 259 |
global last_task_category
|
| 260 |
last_task_category = task_type
|
| 261 |
+
|
| 262 |
try:
|
| 263 |
logger.info(f"Handling text task: {task_type}, prompt: {prompt[:50]}...")
|
| 264 |
+
|
| 265 |
+
# Generate response
|
| 266 |
response, avg_log_prob = generate_with_logprobs(prompt)
|
| 267 |
retrieval_score = retriever.get_similarity(prompt)
|
| 268 |
+
|
| 269 |
+
# Create event
|
| 270 |
event = AIEvent(
|
| 271 |
timestamp=datetime.utcnow(),
|
| 272 |
component="ai",
|
|
|
|
| 288 |
user_feedback=None,
|
| 289 |
latency_ms=0
|
| 290 |
)
|
| 291 |
+
|
| 292 |
+
# Run analysis
|
| 293 |
hallu_result = await hallucination_detective.analyze(event)
|
| 294 |
drift_result = await memory_drift_diagnostician.analyze(event)
|
| 295 |
risk_metrics = ai_risk_engine.risk_score(task_type)
|
| 296 |
+
|
| 297 |
+
# Combine results
|
| 298 |
+
analysis_result = {
|
| 299 |
"response": response,
|
| 300 |
"avg_log_prob": avg_log_prob,
|
| 301 |
"confidence": event.confidence,
|
|
|
|
| 304 |
"memory_drift_detection": drift_result,
|
| 305 |
"risk_metrics": risk_metrics
|
| 306 |
}
|
| 307 |
+
|
| 308 |
+
# Apply governance and control plane
|
| 309 |
+
policy_result = evaluate_policies(
|
| 310 |
+
event_type="text_generation",
|
| 311 |
+
severity="medium" if hallu_result.get("findings", {}).get("is_hallucination") else "low",
|
| 312 |
+
component="ai_service"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 313 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 314 |
|
| 315 |
+
control_decision = autonomous_control_decision(analysis_result)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 316 |
|
| 317 |
+
# Add governance to output
|
| 318 |
+
analysis_result["governance"] = {
|
| 319 |
+
"policy_evaluation": policy_result,
|
| 320 |
+
"control_plane_decision": control_decision
|
| 321 |
+
}
|
| 322 |
|
| 323 |
+
return analysis_result
|
|
|
|
| 324 |
|
| 325 |
+
except Exception as e:
|
| 326 |
+
logger.error(f"Text task error: {e}", exc_info=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 327 |
return {
|
| 328 |
+
"error": str(e),
|
| 329 |
+
"traceback": traceback.format_exc(),
|
| 330 |
+
"governance": {
|
| 331 |
+
"policy_evaluation": evaluate_policies("text_generation", "critical", "ai_service"),
|
| 332 |
+
"control_plane_decision": {"approved": False, "reason": f"Error: {str(e)}"}
|
| 333 |
+
}
|
| 334 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 335 |
|
| 336 |
+
async def handle_infra_with_governance(fault_type, session_state):
|
| 337 |
+
"""Infrastructure analysis with execution governance."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 338 |
if not INFRA_DEPS_AVAILABLE:
|
| 339 |
+
return {
|
| 340 |
+
"error": "Infrastructure modules not available",
|
| 341 |
+
"governance": evaluate_policies("infrastructure", "critical", "system")
|
| 342 |
+
}, session_state
|
| 343 |
+
|
| 344 |
try:
|
| 345 |
+
# Initialize simulator
|
| 346 |
if "sim" not in session_state or session_state["sim"] is None:
|
| 347 |
session_state["sim"] = InfraSimulator()
|
| 348 |
sim = session_state["sim"]
|
| 349 |
+
|
| 350 |
# Inject fault
|
| 351 |
sim.set_fault(fault_type if fault_type != "none" else None)
|
| 352 |
components = sim.read_state()
|
| 353 |
+
|
| 354 |
# Update graph
|
| 355 |
if infra_graph:
|
| 356 |
infra_graph.update_from_state(components)
|
| 357 |
+
|
| 358 |
+
# Determine severity based on fault
|
| 359 |
+
severity = "low"
|
| 360 |
+
if fault_type != "none":
|
| 361 |
+
severity = "high" if fault_type == "cascade" else "medium"
|
| 362 |
+
|
| 363 |
+
# Evaluate policies
|
| 364 |
+
policy_result = evaluate_policies(
|
| 365 |
+
event_type="infrastructure_failure",
|
| 366 |
+
severity=severity,
|
| 367 |
+
component="data_center"
|
| 368 |
+
)
|
| 369 |
+
|
| 370 |
+
# Control plane decision
|
| 371 |
+
control_decision = {
|
| 372 |
+
"timestamp": datetime.utcnow().isoformat(),
|
| 373 |
+
"approved": policy_result["governance_status"] == "approved",
|
| 374 |
+
"actions": policy_result["recommended_actions"],
|
| 375 |
+
"reason": "Governance approved" if policy_result["governance_status"] == "approved" else "Blocked by policy",
|
| 376 |
+
"risk_level": severity
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
# Combine results
|
| 380 |
output = {
|
| 381 |
"topology": components,
|
| 382 |
+
"bayesian_risk": {"switch_failure": 0.1, "server_failure": 0.05},
|
| 383 |
+
"gnn_predictions": {"at_risk": ["server-1"] if fault_type != "none" else []},
|
| 384 |
+
"logic_explanations": "ProbLog analysis complete",
|
| 385 |
+
"ontology": ontology.classify("server") if ontology else {"inferred": [], "consistent": True},
|
| 386 |
+
"governance": {
|
| 387 |
+
"policy_evaluation": policy_result,
|
| 388 |
+
"control_plane_decision": control_decision
|
| 389 |
+
}
|
| 390 |
}
|
| 391 |
+
|
| 392 |
return output, session_state
|
| 393 |
+
|
| 394 |
except Exception as e:
|
| 395 |
logger.error(f"Infra task error: {e}", exc_info=True)
|
| 396 |
+
return {
|
| 397 |
+
"error": str(e),
|
| 398 |
+
"traceback": traceback.format_exc(),
|
| 399 |
+
"governance": evaluate_policies("infrastructure", "critical", "system")
|
| 400 |
+
}, session_state
|
| 401 |
|
| 402 |
# ----------------------------------------------------------------------
|
| 403 |
+
# Gradio UI with Governance Focus
|
| 404 |
# ----------------------------------------------------------------------
|
| 405 |
+
with gr.Blocks(title="ARF v4 – Autonomous AI Control Plane", theme="soft") as demo:
|
| 406 |
+
gr.Markdown("""
|
| 407 |
+
# 🧠 ARF v4 – Autonomous AI Control Plane
|
| 408 |
+
**Execution Governance & Neuro‑Symbolic Reliability for Critical Infrastructure**
|
| 409 |
+
|
| 410 |
+
This demo shows how ARF provides:
|
| 411 |
+
- **Policy‑based Governance** – Automatic evaluation and enforcement
|
| 412 |
+
- **Autonomous Control Decisions** – AI-driven remediation actions
|
| 413 |
+
- **Neuro‑Symbolic Reasoning** – Combining neural networks with symbolic logic
|
| 414 |
+
- **Real‑time Risk Assessment** – Bayesian online learning
|
| 415 |
+
""")
|
| 416 |
|
| 417 |
with gr.Tabs():
|
| 418 |
+
# Tab 1: Control Plane Dashboard
|
| 419 |
+
with gr.TabItem("Control Plane Dashboard"):
|
| 420 |
+
gr.Markdown("### 🎮 Autonomous Control Plane")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 421 |
with gr.Row():
|
| 422 |
with gr.Column():
|
| 423 |
+
system_status = gr.JSON(label="System Status", value={
|
| 424 |
+
"governance_mode": "active",
|
| 425 |
+
"policies_loaded": 5,
|
| 426 |
+
"autonomous_actions": "enabled",
|
| 427 |
+
"risk_threshold": 0.7
|
| 428 |
+
})
|
| 429 |
with gr.Column():
|
| 430 |
+
control_stats = gr.JSON(label="Control Statistics", value={
|
| 431 |
+
"total_decisions": 0,
|
| 432 |
+
"approved_actions": 0,
|
| 433 |
+
"blocked_actions": 0,
|
| 434 |
+
"average_risk": 0.5
|
| 435 |
+
})
|
| 436 |
+
|
| 437 |
+
gr.Markdown("### Recent Control Decisions")
|
| 438 |
+
recent_decisions = gr.JSON(label="Decision Log")
|
| 439 |
+
|
| 440 |
+
# Tab 2: Text Generation with Governance
|
| 441 |
+
with gr.TabItem("Text Generation"):
|
| 442 |
+
gr.Markdown("### AI Text Generation with Governance")
|
| 443 |
+
text_task = gr.Dropdown(["chat", "code", "summary"], value="chat", label="Task")
|
| 444 |
+
text_prompt = gr.Textbox(label="Prompt", value="What is the capital of France?", lines=3)
|
| 445 |
+
text_btn = gr.Button("Generate with Governance")
|
| 446 |
+
text_output = gr.JSON(label="Analysis with Control Decisions")
|
| 447 |
|
| 448 |
+
# Tab 3: Infrastructure Reliability with Governance
|
| 449 |
with gr.TabItem("Infrastructure Reliability"):
|
| 450 |
+
gr.Markdown("### Neuro‑Symbolic Infrastructure with Autonomous Control")
|
| 451 |
infra_state = gr.State(value={})
|
| 452 |
+
|
| 453 |
with gr.Row():
|
| 454 |
with gr.Column():
|
| 455 |
infra_fault = gr.Dropdown(
|
|
|
|
| 457 |
value="none",
|
| 458 |
label="Inject Fault"
|
| 459 |
)
|
| 460 |
+
infra_btn = gr.Button("Run Analysis with Governance")
|
| 461 |
with gr.Column():
|
| 462 |
+
infra_output = gr.JSON(label="Analysis with Control Decisions")
|
| 463 |
+
|
| 464 |
+
# Tab 4: Policy Management
|
| 465 |
+
with gr.TabItem("Policy Management"):
|
| 466 |
+
gr.Markdown("### 📋 Execution Policies")
|
| 467 |
+
policies = gr.JSON(label="Active Policies", value=[
|
| 468 |
+
{
|
| 469 |
+
"id": "POL-001",
|
| 470 |
+
"name": "Hallucination Prevention",
|
| 471 |
+
"condition": "confidence < 0.6",
|
| 472 |
+
"action": "regenerate",
|
| 473 |
+
"severity": "medium"
|
| 474 |
+
},
|
| 475 |
+
{
|
| 476 |
+
"id": "POL-002",
|
| 477 |
+
"name": "Infrastructure Cascade",
|
| 478 |
+
"condition": "fault_type == 'cascade'",
|
| 479 |
+
"action": "isolate_affected",
|
| 480 |
+
"severity": "critical"
|
| 481 |
+
},
|
| 482 |
+
{
|
| 483 |
+
"id": "POL-003",
|
| 484 |
+
"name": "Memory Drift",
|
| 485 |
+
"condition": "drift_detected == true",
|
| 486 |
+
"action": "reset_context",
|
| 487 |
+
"severity": "low"
|
| 488 |
+
},
|
| 489 |
+
{
|
| 490 |
+
"id": "POL-004",
|
| 491 |
+
"name": "High Risk",
|
| 492 |
+
"condition": "risk_metrics.mean > 0.7",
|
| 493 |
+
"action": "require_approval",
|
| 494 |
+
"severity": "high"
|
| 495 |
+
},
|
| 496 |
+
{
|
| 497 |
+
"id": "POL-005",
|
| 498 |
+
"name": "Audio Quality",
|
| 499 |
+
"condition": "confidence < 0.5",
|
| 500 |
+
"action": "request_retry",
|
| 501 |
+
"severity": "low"
|
| 502 |
+
}
|
| 503 |
+
])
|
| 504 |
|
| 505 |
+
# Tab 5: Enterprise
|
| 506 |
with gr.TabItem("Enterprise"):
|
| 507 |
gr.Markdown("""
|
| 508 |
+
## 🚀 ARF Enterprise – Autonomous Control Plane for Critical Infrastructure
|
| 509 |
+
|
|
|
|
|
|
|
| 510 |
### Key Enterprise Features:
|
| 511 |
+
- **Execution Governance** – Policy‑controlled autonomous actions
|
| 512 |
+
- **Audit Trails & Compliance** – Full traceability for SOC2, HIPAA, GDPR
|
| 513 |
+
- **Learning Loops** – Models improve over time with your data
|
| 514 |
+
- **Multi‑Tenant Control** – Role‑based access and isolation
|
| 515 |
+
- **Cloud Integrations** – Azure, AWS, GCP native clients
|
| 516 |
+
- **24/7 Support & SLAs** – Enterprise‑grade reliability
|
| 517 |
+
|
| 518 |
### Get Started
|
| 519 |
- 📅 [Book a Demo](https://calendly.com/petter2025us/30min)
|
| 520 |
- 📧 [Contact Sales](mailto:petter2025us@outlook.com)
|
|
|
|
| 522 |
|
| 523 |
# Feedback row
|
| 524 |
with gr.Row():
|
| 525 |
+
feedback_up = gr.Button("👍 Approve Decision")
|
| 526 |
+
feedback_down = gr.Button("👎 Reject Decision")
|
| 527 |
feedback_msg = gr.Textbox(label="Feedback", interactive=False)
|
| 528 |
|
| 529 |
# Wire events
|
|
|
|
| 532 |
inputs=[text_task, text_prompt],
|
| 533 |
outputs=text_output
|
| 534 |
)
|
| 535 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 536 |
infra_btn.click(
|
| 537 |
+
fn=lambda f, s: asyncio.run(handle_infra_with_governance(f, s)),
|
| 538 |
inputs=[infra_fault, infra_state],
|
| 539 |
outputs=[infra_output, infra_state]
|
| 540 |
)
|
| 541 |
+
|
| 542 |
+
def handle_control_feedback(approved: bool):
|
| 543 |
+
global last_task_category
|
| 544 |
+
if last_task_category is None:
|
| 545 |
+
return "No recent decision to rate"
|
| 546 |
+
return f"Control decision {'approved' if approved else 'rejected'} for {last_task_category}"
|
| 547 |
+
|
| 548 |
+
feedback_up.click(
|
| 549 |
+
fn=lambda: handle_control_feedback(True),
|
| 550 |
+
outputs=feedback_msg
|
| 551 |
+
)
|
| 552 |
+
feedback_down.click(
|
| 553 |
+
fn=lambda: handle_control_feedback(False),
|
| 554 |
+
outputs=feedback_msg
|
| 555 |
+
)
|
| 556 |
|
| 557 |
if __name__ == "__main__":
|
| 558 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|