Update hf_demo.py
Browse files- hf_demo.py +200 -0
hf_demo.py
CHANGED
|
@@ -16,6 +16,195 @@ from datetime import datetime, timedelta
|
|
| 16 |
from typing import Dict, List, Optional, Tuple, Any, Union
|
| 17 |
import numpy as np
|
| 18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
# ============== HUGGING FACE SPACES DETECTION ==============
|
| 20 |
def is_huggingface_spaces():
|
| 21 |
"""Detect if running in Hugging Face Spaces environment"""
|
|
@@ -973,6 +1162,17 @@ if __name__ == "__main__":
|
|
| 973 |
print("🌐 Environment:", "Hugging Face Spaces" if is_huggingface_spaces() else "Local Development")
|
| 974 |
print("="*80)
|
| 975 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 976 |
# Create the demo
|
| 977 |
demo = create_enhanced_demo()
|
| 978 |
|
|
|
|
| 16 |
from typing import Dict, List, Optional, Tuple, Any, Union
|
| 17 |
import numpy as np
|
| 18 |
|
| 19 |
+
# ============== FASTAPI INTEGRATION ==============
|
| 20 |
+
try:
|
| 21 |
+
from fastapi import FastAPI, HTTPException
|
| 22 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 23 |
+
from pydantic import BaseModel, Field
|
| 24 |
+
import uvicorn
|
| 25 |
+
FASTAPI_AVAILABLE = True
|
| 26 |
+
print("✅ FastAPI available")
|
| 27 |
+
except ImportError as e:
|
| 28 |
+
print(f"⚠️ FastAPI not available: {e}")
|
| 29 |
+
FASTAPI_AVAILABLE = False
|
| 30 |
+
|
| 31 |
+
# Create dummy classes if FastAPI not installed
|
| 32 |
+
class BaseModel:
|
| 33 |
+
def dict(self): return {}
|
| 34 |
+
class FastAPI: pass
|
| 35 |
+
class HTTPException(Exception): pass
|
| 36 |
+
class CORSMiddleware: pass
|
| 37 |
+
def Field(*args, **kwargs): return None
|
| 38 |
+
|
| 39 |
+
if FASTAPI_AVAILABLE:
|
| 40 |
+
# Create FastAPI app
|
| 41 |
+
api_app = FastAPI(title="ARF Mathematical Engine", version="3.3.9")
|
| 42 |
+
|
| 43 |
+
# Add CORS middleware
|
| 44 |
+
api_app.add_middleware(
|
| 45 |
+
CORSMiddleware,
|
| 46 |
+
allow_origins=["*"], # In production, restrict to your Replit domain
|
| 47 |
+
allow_credentials=True,
|
| 48 |
+
allow_methods=["*"],
|
| 49 |
+
allow_headers=["*"],
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
# Define Pydantic models
|
| 53 |
+
class ActionEvaluationRequest(BaseModel):
|
| 54 |
+
proposed_action: str = Field(..., description="The command the AI wants to execute")
|
| 55 |
+
confidence_score: float = Field(..., ge=0.0, le=1.0, description="AI confidence score")
|
| 56 |
+
risk_level: str = Field(..., description="Risk level (LOW/MEDIUM/HIGH/CRITICAL)")
|
| 57 |
+
requires_human: bool = Field(..., description="Whether action requires human oversight")
|
| 58 |
+
rollback_feasible: bool = Field(..., description="Whether action can be rolled back")
|
| 59 |
+
description: Optional[str] = Field(None, description="Optional action description")
|
| 60 |
+
incident_id: Optional[int] = Field(None, description="Optional incident ID")
|
| 61 |
+
|
| 62 |
+
class GateEvaluationResponse(BaseModel):
|
| 63 |
+
gate: str
|
| 64 |
+
reason: str
|
| 65 |
+
passed: bool
|
| 66 |
+
threshold: Optional[float] = None
|
| 67 |
+
actual: Optional[float] = None
|
| 68 |
+
metadata: Optional[dict] = None
|
| 69 |
+
|
| 70 |
+
class ActionEvaluationResponse(BaseModel):
|
| 71 |
+
allowed: bool
|
| 72 |
+
required_level: str
|
| 73 |
+
gates_triggered: list[GateEvaluationResponse]
|
| 74 |
+
should_escalate: bool
|
| 75 |
+
escalation_reason: Optional[str] = None
|
| 76 |
+
|
| 77 |
+
class ConfigResponse(BaseModel):
|
| 78 |
+
confidenceThreshold: float
|
| 79 |
+
maxAutonomousRisk: str
|
| 80 |
+
riskScoreThresholds: dict
|
| 81 |
+
|
| 82 |
+
# Add API endpoints
|
| 83 |
+
@api_app.get("/api/v1/config", response_model=ConfigResponse)
|
| 84 |
+
async def get_config():
|
| 85 |
+
"""Get current ARF configuration"""
|
| 86 |
+
return {
|
| 87 |
+
"confidenceThreshold": 0.9,
|
| 88 |
+
"maxAutonomousRisk": "MEDIUM",
|
| 89 |
+
"riskScoreThresholds": {
|
| 90 |
+
"LOW": 0.7,
|
| 91 |
+
"MEDIUM": 0.5,
|
| 92 |
+
"HIGH": 0.3,
|
| 93 |
+
"CRITICAL": 0.1
|
| 94 |
+
}
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
@api_app.post("/api/v1/evaluate", response_model=ActionEvaluationResponse)
|
| 98 |
+
async def evaluate_action(request: ActionEvaluationRequest):
|
| 99 |
+
"""Evaluate an action using mathematical Bayesian assessment"""
|
| 100 |
+
try:
|
| 101 |
+
# Simulate gate evaluations
|
| 102 |
+
gates = []
|
| 103 |
+
|
| 104 |
+
# Confidence gate
|
| 105 |
+
confidence_passed = request.confidence_score >= 0.9
|
| 106 |
+
gates.append(GateEvaluationResponse(
|
| 107 |
+
gate="confidence_threshold",
|
| 108 |
+
reason=f"Confidence {request.confidence_score:.2f} meets threshold 0.9" if confidence_passed
|
| 109 |
+
else f"Confidence {request.confidence_score:.2f} below threshold 0.9",
|
| 110 |
+
passed=confidence_passed,
|
| 111 |
+
threshold=0.9,
|
| 112 |
+
actual=request.confidence_score
|
| 113 |
+
))
|
| 114 |
+
|
| 115 |
+
# Risk gate
|
| 116 |
+
risk_passed = request.risk_level in ["LOW", "MEDIUM"]
|
| 117 |
+
gates.append(GateEvaluationResponse(
|
| 118 |
+
gate="risk_assessment",
|
| 119 |
+
reason=f"Risk level {request.risk_level} within autonomous range" if risk_passed
|
| 120 |
+
else f"Risk level {request.risk_level} exceeds autonomous threshold",
|
| 121 |
+
passed=risk_passed,
|
| 122 |
+
metadata={"maxAutonomousRisk": "MEDIUM", "actionRisk": request.risk_level}
|
| 123 |
+
))
|
| 124 |
+
|
| 125 |
+
# Rollback gate
|
| 126 |
+
destructive_keywords = ['delete', 'drop', 'terminate', 'remove', 'destroy']
|
| 127 |
+
is_destructive = any(keyword in request.proposed_action.lower() for keyword in destructive_keywords)
|
| 128 |
+
rollback_passed = not is_destructive or request.rollback_feasible
|
| 129 |
+
gates.append(GateEvaluationResponse(
|
| 130 |
+
gate="rollback_feasibility",
|
| 131 |
+
reason="Non-destructive operation" if not is_destructive
|
| 132 |
+
else "Has rollback plan" if request.rollback_feasible
|
| 133 |
+
else "Destructive operation lacks rollback plan",
|
| 134 |
+
passed=rollback_passed,
|
| 135 |
+
metadata={"isDestructive": is_destructive, "requiresRollback": is_destructive}
|
| 136 |
+
))
|
| 137 |
+
|
| 138 |
+
# Human review gate
|
| 139 |
+
human_passed = not request.requires_human
|
| 140 |
+
gates.append(GateEvaluationResponse(
|
| 141 |
+
gate="human_review",
|
| 142 |
+
reason="Human review not required" if human_passed else "Human review required by policy",
|
| 143 |
+
passed=human_passed,
|
| 144 |
+
metadata={"policyRequiresHuman": request.requires_human}
|
| 145 |
+
))
|
| 146 |
+
|
| 147 |
+
# License gate (always passes in this simulation)
|
| 148 |
+
gates.append(GateEvaluationResponse(
|
| 149 |
+
gate="license_check",
|
| 150 |
+
reason="No license violations detected",
|
| 151 |
+
passed=True,
|
| 152 |
+
metadata={"licenseSensitive": False}
|
| 153 |
+
))
|
| 154 |
+
|
| 155 |
+
all_passed = all(g.passed for g in gates)
|
| 156 |
+
|
| 157 |
+
# Determine required level
|
| 158 |
+
if all_passed:
|
| 159 |
+
if request.risk_level == "LOW":
|
| 160 |
+
required_level = "AUTONOMOUS_LOW"
|
| 161 |
+
elif request.risk_level == "MEDIUM":
|
| 162 |
+
required_level = "AUTONOMOUS_HIGH"
|
| 163 |
+
else:
|
| 164 |
+
required_level = "SUPERVISED"
|
| 165 |
+
else:
|
| 166 |
+
required_level = "OPERATOR_REVIEW"
|
| 167 |
+
|
| 168 |
+
return ActionEvaluationResponse(
|
| 169 |
+
allowed=all_passed,
|
| 170 |
+
required_level=required_level,
|
| 171 |
+
gates_triggered=gates,
|
| 172 |
+
should_escalate=not all_passed,
|
| 173 |
+
escalation_reason=None if all_passed else "Failed critical gates"
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
except Exception as e:
|
| 177 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 178 |
+
|
| 179 |
+
@api_app.post("/api/v1/process")
|
| 180 |
+
async def process_action(request: ActionEvaluationRequest):
|
| 181 |
+
"""Process action through full ARF pipeline"""
|
| 182 |
+
evaluation = await evaluate_action(request)
|
| 183 |
+
|
| 184 |
+
# Determine final status based on evaluation
|
| 185 |
+
if evaluation.allowed and not evaluation.should_escalate:
|
| 186 |
+
final_status = "executed"
|
| 187 |
+
elif evaluation.should_escalate:
|
| 188 |
+
final_status = "needs_approval"
|
| 189 |
+
else:
|
| 190 |
+
final_status = "blocked"
|
| 191 |
+
|
| 192 |
+
return {
|
| 193 |
+
"action": request.dict(),
|
| 194 |
+
"evaluation": evaluation.dict(),
|
| 195 |
+
"finalStatus": final_status
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
@api_app.post("/api/v1/simulate")
|
| 199 |
+
async def simulate_action(request: ActionEvaluationRequest, config: dict = None):
|
| 200 |
+
"""Simulate action with temporary configuration"""
|
| 201 |
+
evaluation = await evaluate_action(request)
|
| 202 |
+
return evaluation
|
| 203 |
+
|
| 204 |
+
def run_fastapi():
|
| 205 |
+
"""Run FastAPI server in background thread"""
|
| 206 |
+
uvicorn.run(api_app, host="0.0.0.0", port=8000, log_level="warning")
|
| 207 |
+
|
| 208 |
# ============== HUGGING FACE SPACES DETECTION ==============
|
| 209 |
def is_huggingface_spaces():
|
| 210 |
"""Detect if running in Hugging Face Spaces environment"""
|
|
|
|
| 1162 |
print("🌐 Environment:", "Hugging Face Spaces" if is_huggingface_spaces() else "Local Development")
|
| 1163 |
print("="*80)
|
| 1164 |
|
| 1165 |
+
# Start FastAPI in background thread if available
|
| 1166 |
+
if FASTAPI_AVAILABLE:
|
| 1167 |
+
fastapi_thread = threading.Thread(target=run_fastapi, daemon=True)
|
| 1168 |
+
fastapi_thread.start()
|
| 1169 |
+
print("✅ FastAPI server started on port 8000")
|
| 1170 |
+
print(" API endpoints available at:")
|
| 1171 |
+
print(" - GET /api/v1/config")
|
| 1172 |
+
print(" - POST /api/v1/evaluate")
|
| 1173 |
+
print(" - POST /api/v1/process")
|
| 1174 |
+
print(" - POST /api/v1/simulate")
|
| 1175 |
+
|
| 1176 |
# Create the demo
|
| 1177 |
demo = create_enhanced_demo()
|
| 1178 |
|