Spaces:
Sleeping
Sleeping
app.py Static Label Fix #1
Browse files- server/app.py +51 -63
server/app.py
CHANGED
|
@@ -26,13 +26,12 @@ if _CURRENT_DIR not in sys.path:
|
|
| 26 |
sys.path.insert(0, _CURRENT_DIR)
|
| 27 |
|
| 28 |
try:
|
| 29 |
-
# 1. Import the environment AND the safely loaded C++ module
|
| 30 |
from fin_auditor_environment import FinAuditorEnvironment, hft_auditor
|
| 31 |
from models import AuditorAction, AuditorObservation
|
| 32 |
|
| 33 |
HAS_ENV = True
|
| 34 |
NATIVE_VERIFIED = hft_auditor is not None
|
| 35 |
-
hft_mod = hft_auditor
|
| 36 |
|
| 37 |
except ImportError as e:
|
| 38 |
HAS_ENV = False
|
|
@@ -44,11 +43,20 @@ except ImportError as e:
|
|
| 44 |
# ==============================================================================
|
| 45 |
# PHASE 2: SYSTEM STATE & AUTHORITY TRACKING
|
| 46 |
# ==============================================================================
|
| 47 |
-
env = FinAuditorEnvironment() if (HAS_ENV and NATIVE_VERIFIED) else None
|
| 48 |
|
| 49 |
-
#
|
| 50 |
-
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
else:
|
| 53 |
app = FastAPI(title="PayGorn (MOCK MODE)")
|
| 54 |
@app.post("/reset")
|
|
@@ -60,7 +68,6 @@ app_metrics = {"last_step_latency_us": 0.0}
|
|
| 60 |
|
| 61 |
@app.middleware("http")
|
| 62 |
async def capture_step_latency(request: Request, call_next):
|
| 63 |
-
"""TASK 1: Captures true end-to-end latency of the C++ bridge."""
|
| 64 |
if request.url.path == "/step":
|
| 65 |
start_ns = time.perf_counter_ns()
|
| 66 |
response = await call_next(request)
|
|
@@ -87,7 +94,7 @@ llm_session = {
|
|
| 87 |
}
|
| 88 |
|
| 89 |
class LLMConfig(BaseModel):
|
| 90 |
-
api_key: str = ""
|
| 91 |
model_name: Optional[str] = None
|
| 92 |
base_url: Optional[str] = None
|
| 93 |
|
|
@@ -134,13 +141,14 @@ async def execute_llm_step(api_key: str, base_url: str, model_name: str, batch_s
|
|
| 134 |
# ==============================================================================
|
| 135 |
@app.get("/state")
|
| 136 |
async def get_state():
|
| 137 |
-
|
|
|
|
| 138 |
return {"status": "FALLBACK_MOCK_MODE", "health": system_health, "accuracy": 0.0, "latency_us": 0.0, "throughput_m": 0.0, "buffer_saturation": 0.0, "active_count": 0, "total_ingested": 0, "step_count": 0, "difficulty": "EASY", "metrics": {"tp": 0, "tn": 0, "fp": 0, "fn": 0}}
|
| 139 |
|
| 140 |
-
tp = getattr(
|
| 141 |
-
fp = getattr(
|
| 142 |
-
tn = getattr(
|
| 143 |
-
fn = getattr(
|
| 144 |
|
| 145 |
accuracy = tp / (tp + fp) if (tp + fp) > 0 else 0.0
|
| 146 |
latency_us = app_metrics["last_step_latency_us"]
|
|
@@ -152,13 +160,13 @@ async def get_state():
|
|
| 152 |
"latency_us": round(latency_us, 3),
|
| 153 |
"latency_source": "grounded_app_middleware",
|
| 154 |
"throughput_m": round((40 * 1e6) / (latency_us * 1000), 2) if latency_us > 0 else 0.0,
|
| 155 |
-
"active_count":
|
| 156 |
-
"total_ingested":
|
| 157 |
-
"ring_buffer_size":
|
| 158 |
-
"buffer_saturation": (
|
| 159 |
-
"step_count":
|
| 160 |
"metrics": {"tp": tp, "tn": tn, "fp": fp, "fn": fn},
|
| 161 |
-
"difficulty": getattr(
|
| 162 |
}
|
| 163 |
|
| 164 |
@app.post("/dashboard/get_action")
|
|
@@ -167,12 +175,10 @@ async def get_dashboard_action(req: ActionRequest):
|
|
| 167 |
if req.action_type == "perfect":
|
| 168 |
decisions = [1] * batch_size
|
| 169 |
elif req.action_type == "llm":
|
| 170 |
-
# FIX: Read directly from llm_session memory to bypass OS environment sync issues
|
| 171 |
api_key = llm_session.get("api_key")
|
| 172 |
base_url = llm_session.get("base_url")
|
| 173 |
model_name = llm_session.get("model_name")
|
| 174 |
|
| 175 |
-
# Fallback to the first available model if none explicitly selected
|
| 176 |
if not model_name and llm_session.get("available_models"):
|
| 177 |
model_name = llm_session["available_models"][0]
|
| 178 |
|
|
@@ -187,14 +193,12 @@ async def get_dashboard_action(req: ActionRequest):
|
|
| 187 |
@app.post("/config/llm")
|
| 188 |
async def config_llm(cfg: LLMConfig):
|
| 189 |
api_key = cfg.api_key
|
| 190 |
-
# Fallback to session key if UI sends blank string and default token is active
|
| 191 |
if not api_key:
|
| 192 |
api_key = llm_session.get("api_key")
|
| 193 |
if not api_key:
|
| 194 |
raise HTTPException(status_code=400, detail="API Key cannot be blank")
|
| 195 |
|
| 196 |
base_url = "https://router.huggingface.co/v1"
|
| 197 |
-
|
| 198 |
if api_key.startswith("AIza"):
|
| 199 |
base_url = "https://generativelanguage.googleapis.com/v1beta/openai/"
|
| 200 |
elif api_key.startswith("sk-ant"):
|
|
@@ -202,7 +206,6 @@ async def config_llm(cfg: LLMConfig):
|
|
| 202 |
|
| 203 |
try:
|
| 204 |
client = AsyncOpenAI(base_url=base_url, api_key=api_key, max_retries=2)
|
| 205 |
-
|
| 206 |
try:
|
| 207 |
response = await client.models.list()
|
| 208 |
model_list = [m.id for m in response.data]
|
|
@@ -212,23 +215,17 @@ async def config_llm(cfg: LLMConfig):
|
|
| 212 |
else:
|
| 213 |
raise e
|
| 214 |
|
| 215 |
-
# Save baseline session variables
|
| 216 |
llm_session["api_key"] = api_key
|
| 217 |
llm_session["base_url"] = base_url
|
| 218 |
llm_session["available_models"] = model_list
|
| 219 |
-
|
| 220 |
system_health["key_validated"] = True
|
| 221 |
system_health["model_detected"] = len(model_list) > 0
|
| 222 |
|
| 223 |
if cfg.model_name and cfg.model_name in model_list:
|
| 224 |
-
# FIX: Explicitly save model_name into memory
|
| 225 |
llm_session["model_name"] = cfg.model_name
|
| 226 |
-
|
| 227 |
-
# (Optional) Keep OS environ for other scripts, but app.py won't rely on it
|
| 228 |
os.environ["MODEL_NAME"] = cfg.model_name
|
| 229 |
os.environ["LLM_API_KEY"] = api_key
|
| 230 |
os.environ["API_BASE_URL"] = base_url
|
| 231 |
-
|
| 232 |
system_health["connected"] = True
|
| 233 |
msg = f"Injected {cfg.model_name} credentials."
|
| 234 |
else:
|
|
@@ -251,14 +248,14 @@ async def config_default():
|
|
| 251 |
|
| 252 |
@app.post("/config/difficulty")
|
| 253 |
async def set_difficulty(cfg: DifficultyConfig):
|
| 254 |
-
if
|
| 255 |
os.environ["TASK_ID"] = cfg.level.lower()
|
| 256 |
if "easy" in cfg.level.lower():
|
| 257 |
-
|
| 258 |
elif "medium" in cfg.level.lower():
|
| 259 |
-
|
| 260 |
else:
|
| 261 |
-
|
| 262 |
return {"status": "success", "difficulty": cfg.level}
|
| 263 |
return {"status": "error", "message": "Engine not loaded"}
|
| 264 |
|
|
@@ -267,12 +264,12 @@ async def websocket_telemetry(websocket: WebSocket):
|
|
| 267 |
await websocket.accept()
|
| 268 |
try:
|
| 269 |
while True:
|
| 270 |
-
if
|
| 271 |
data = {
|
| 272 |
-
"active_count":
|
| 273 |
-
"total_ingested":
|
| 274 |
-
"ring_buffer_size":
|
| 275 |
-
"pool_capacity":
|
| 276 |
"latency_us": round(app_metrics["last_step_latency_us"], 3),
|
| 277 |
"status": "NATIVE_ACTIVE"
|
| 278 |
}
|
|
@@ -521,8 +518,6 @@ async def root_dashboard():
|
|
| 521 |
<script>
|
| 522 |
const consoleOut = document.getElementById('console-out');
|
| 523 |
const ledgerBody = document.getElementById('ledger-body');
|
| 524 |
-
|
| 525 |
-
// TRACKING STATE FOR ZERO-CONFIG
|
| 526 |
let usingDefaultToken = false;
|
| 527 |
|
| 528 |
function logMsg(msg, type='info') {
|
|
@@ -593,10 +588,7 @@ async def root_dashboard():
|
|
| 593 |
async function discoverModels() {
|
| 594 |
const key = document.getElementById('api-key').value;
|
| 595 |
if(!key) return;
|
| 596 |
-
|
| 597 |
-
// If user manually types a key, they are no longer using the default
|
| 598 |
usingDefaultToken = false;
|
| 599 |
-
|
| 600 |
logMsg("Validating key and mapping models...", "info");
|
| 601 |
const res = await fetch('/config/llm', {
|
| 602 |
method: 'POST',
|
|
@@ -604,7 +596,6 @@ async def root_dashboard():
|
|
| 604 |
body: JSON.stringify({api_key: key})
|
| 605 |
});
|
| 606 |
const data = await res.json();
|
| 607 |
-
|
| 608 |
if(data.status === 'success') {
|
| 609 |
const select = document.getElementById('model-select');
|
| 610 |
select.innerHTML = '';
|
|
@@ -623,13 +614,9 @@ async def root_dashboard():
|
|
| 623 |
async function saveConfig() {
|
| 624 |
const key = document.getElementById('api-key').value;
|
| 625 |
const model = document.getElementById('model-select').value;
|
| 626 |
-
|
| 627 |
-
// Check if model is missing, OR if both the input is empty AND the default token isn't active
|
| 628 |
if (!model || (!key && !usingDefaultToken)) {
|
| 629 |
-
logMsg("Key/Model missing.", "err");
|
| 630 |
-
return;
|
| 631 |
}
|
| 632 |
-
|
| 633 |
const res = await fetch('/config/llm', {
|
| 634 |
method: 'POST',
|
| 635 |
headers: {'Content-Type': 'application/json'},
|
|
@@ -637,8 +624,7 @@ async def root_dashboard():
|
|
| 637 |
});
|
| 638 |
const data = await res.json();
|
| 639 |
if(data.status === 'success') {
|
| 640 |
-
logMsg(data.message, "success");
|
| 641 |
-
updateState();
|
| 642 |
} else {
|
| 643 |
logMsg(data.message, "err");
|
| 644 |
}
|
|
@@ -657,8 +643,7 @@ async def root_dashboard():
|
|
| 657 |
opt.value = m; opt.innerText = m;
|
| 658 |
select.appendChild(opt);
|
| 659 |
});
|
| 660 |
-
logMsg("Zero-config active.", "success");
|
| 661 |
-
updateState();
|
| 662 |
} else {
|
| 663 |
logMsg(data.message, "err");
|
| 664 |
}
|
|
@@ -695,7 +680,6 @@ async def root_dashboard():
|
|
| 695 |
body: JSON.stringify({action_type: actionType})
|
| 696 |
});
|
| 697 |
|
| 698 |
-
// ADDED: Handle the 400 error cleanly if the API key is missing
|
| 699 |
if (!actionRes.ok) {
|
| 700 |
const errData = await actionRes.json();
|
| 701 |
logMsg("LLM Error: " + (errData.detail || "Failed to generate decisions"), "err");
|
|
@@ -703,14 +687,12 @@ async def root_dashboard():
|
|
| 703 |
}
|
| 704 |
|
| 705 |
const actionData = await actionRes.json();
|
| 706 |
-
|
| 707 |
if(!actionData.decisions) {
|
| 708 |
logMsg("Decision matrix generation failed.", "err"); return;
|
| 709 |
}
|
| 710 |
|
| 711 |
logMsg(`Executing Step with ${actionData.decisions.length} decisions...`, "info");
|
| 712 |
|
| 713 |
-
// FIX: Wrap the payload in the 'action' key required by OpenEnv
|
| 714 |
const res = await fetch('/step', {
|
| 715 |
method: 'POST',
|
| 716 |
headers: {'Content-Type': 'application/json'},
|
|
@@ -726,9 +708,10 @@ async def root_dashboard():
|
|
| 726 |
|
| 727 |
const data = await res.json();
|
| 728 |
|
| 729 |
-
|
| 730 |
-
const
|
| 731 |
-
const
|
|
|
|
| 732 |
|
| 733 |
logMsg(`[RECON] Reward: ${reward.toFixed(4)} | Success`, reward >= 0.8 ? 'success' : 'warn');
|
| 734 |
|
|
@@ -749,8 +732,14 @@ async def root_dashboard():
|
|
| 749 |
}
|
| 750 |
}
|
| 751 |
|
| 752 |
-
|
| 753 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 754 |
</script>
|
| 755 |
</body>
|
| 756 |
</html>
|
|
@@ -758,7 +747,6 @@ async def root_dashboard():
|
|
| 758 |
return HTMLResponse(content=html_content)
|
| 759 |
|
| 760 |
def main():
|
| 761 |
-
# Hugging Face Spaces expects traffic on port 7860
|
| 762 |
port = int(os.getenv("PORT", 7860))
|
| 763 |
uvicorn.run(app, host="0.0.0.0", port=port)
|
| 764 |
|
|
|
|
| 26 |
sys.path.insert(0, _CURRENT_DIR)
|
| 27 |
|
| 28 |
try:
|
|
|
|
| 29 |
from fin_auditor_environment import FinAuditorEnvironment, hft_auditor
|
| 30 |
from models import AuditorAction, AuditorObservation
|
| 31 |
|
| 32 |
HAS_ENV = True
|
| 33 |
NATIVE_VERIFIED = hft_auditor is not None
|
| 34 |
+
hft_mod = hft_auditor
|
| 35 |
|
| 36 |
except ImportError as e:
|
| 37 |
HAS_ENV = False
|
|
|
|
| 43 |
# ==============================================================================
|
| 44 |
# PHASE 2: SYSTEM STATE & AUTHORITY TRACKING
|
| 45 |
# ==============================================================================
|
|
|
|
| 46 |
|
| 47 |
+
# FIX: Global pointer to capture the OpenEnv-managed instance
|
| 48 |
+
active_env_instance = None
|
| 49 |
+
|
| 50 |
+
if HAS_ENV and NATIVE_VERIFIED:
|
| 51 |
+
class TrackedFinAuditorEnvironment(FinAuditorEnvironment):
|
| 52 |
+
"""Wrapper class to capture the environment instance created by OpenEnv"""
|
| 53 |
+
def __init__(self, *args, **kwargs):
|
| 54 |
+
super().__init__(*args, **kwargs)
|
| 55 |
+
global active_env_instance
|
| 56 |
+
active_env_instance = self
|
| 57 |
+
|
| 58 |
+
# OpenEnv creates the FastAPI app and instantiates TrackedFinAuditorEnvironment internally
|
| 59 |
+
app = create_app(TrackedFinAuditorEnvironment, AuditorAction, AuditorObservation)
|
| 60 |
else:
|
| 61 |
app = FastAPI(title="PayGorn (MOCK MODE)")
|
| 62 |
@app.post("/reset")
|
|
|
|
| 68 |
|
| 69 |
@app.middleware("http")
|
| 70 |
async def capture_step_latency(request: Request, call_next):
|
|
|
|
| 71 |
if request.url.path == "/step":
|
| 72 |
start_ns = time.perf_counter_ns()
|
| 73 |
response = await call_next(request)
|
|
|
|
| 94 |
}
|
| 95 |
|
| 96 |
class LLMConfig(BaseModel):
|
| 97 |
+
api_key: str = ""
|
| 98 |
model_name: Optional[str] = None
|
| 99 |
base_url: Optional[str] = None
|
| 100 |
|
|
|
|
| 141 |
# ==============================================================================
|
| 142 |
@app.get("/state")
|
| 143 |
async def get_state():
|
| 144 |
+
# FIX: Check the dynamically tracked instance instead of the old static one
|
| 145 |
+
if not active_env_instance:
|
| 146 |
return {"status": "FALLBACK_MOCK_MODE", "health": system_health, "accuracy": 0.0, "latency_us": 0.0, "throughput_m": 0.0, "buffer_saturation": 0.0, "active_count": 0, "total_ingested": 0, "step_count": 0, "difficulty": "EASY", "metrics": {"tp": 0, "tn": 0, "fp": 0, "fn": 0}}
|
| 147 |
|
| 148 |
+
tp = getattr(active_env_instance.state, 'last_tp', 0)
|
| 149 |
+
fp = getattr(active_env_instance.state, 'last_fp', 0)
|
| 150 |
+
tn = getattr(active_env_instance.state, 'last_tn', 0)
|
| 151 |
+
fn = getattr(active_env_instance.state, 'last_fn', 0)
|
| 152 |
|
| 153 |
accuracy = tp / (tp + fp) if (tp + fp) > 0 else 0.0
|
| 154 |
latency_us = app_metrics["last_step_latency_us"]
|
|
|
|
| 160 |
"latency_us": round(latency_us, 3),
|
| 161 |
"latency_source": "grounded_app_middleware",
|
| 162 |
"throughput_m": round((40 * 1e6) / (latency_us * 1000), 2) if latency_us > 0 else 0.0,
|
| 163 |
+
"active_count": active_env_instance.engine.active_count,
|
| 164 |
+
"total_ingested": active_env_instance.engine.total_ingested,
|
| 165 |
+
"ring_buffer_size": active_env_instance.engine.ring_buffer_size,
|
| 166 |
+
"buffer_saturation": (active_env_instance.engine.ring_buffer_size / active_env_instance.engine.pool_capacity) * 100,
|
| 167 |
+
"step_count": active_env_instance.state.step_count,
|
| 168 |
"metrics": {"tp": tp, "tn": tn, "fp": fp, "fn": fn},
|
| 169 |
+
"difficulty": getattr(active_env_instance, 'difficulty', "EASY")
|
| 170 |
}
|
| 171 |
|
| 172 |
@app.post("/dashboard/get_action")
|
|
|
|
| 175 |
if req.action_type == "perfect":
|
| 176 |
decisions = [1] * batch_size
|
| 177 |
elif req.action_type == "llm":
|
|
|
|
| 178 |
api_key = llm_session.get("api_key")
|
| 179 |
base_url = llm_session.get("base_url")
|
| 180 |
model_name = llm_session.get("model_name")
|
| 181 |
|
|
|
|
| 182 |
if not model_name and llm_session.get("available_models"):
|
| 183 |
model_name = llm_session["available_models"][0]
|
| 184 |
|
|
|
|
| 193 |
@app.post("/config/llm")
|
| 194 |
async def config_llm(cfg: LLMConfig):
|
| 195 |
api_key = cfg.api_key
|
|
|
|
| 196 |
if not api_key:
|
| 197 |
api_key = llm_session.get("api_key")
|
| 198 |
if not api_key:
|
| 199 |
raise HTTPException(status_code=400, detail="API Key cannot be blank")
|
| 200 |
|
| 201 |
base_url = "https://router.huggingface.co/v1"
|
|
|
|
| 202 |
if api_key.startswith("AIza"):
|
| 203 |
base_url = "https://generativelanguage.googleapis.com/v1beta/openai/"
|
| 204 |
elif api_key.startswith("sk-ant"):
|
|
|
|
| 206 |
|
| 207 |
try:
|
| 208 |
client = AsyncOpenAI(base_url=base_url, api_key=api_key, max_retries=2)
|
|
|
|
| 209 |
try:
|
| 210 |
response = await client.models.list()
|
| 211 |
model_list = [m.id for m in response.data]
|
|
|
|
| 215 |
else:
|
| 216 |
raise e
|
| 217 |
|
|
|
|
| 218 |
llm_session["api_key"] = api_key
|
| 219 |
llm_session["base_url"] = base_url
|
| 220 |
llm_session["available_models"] = model_list
|
|
|
|
| 221 |
system_health["key_validated"] = True
|
| 222 |
system_health["model_detected"] = len(model_list) > 0
|
| 223 |
|
| 224 |
if cfg.model_name and cfg.model_name in model_list:
|
|
|
|
| 225 |
llm_session["model_name"] = cfg.model_name
|
|
|
|
|
|
|
| 226 |
os.environ["MODEL_NAME"] = cfg.model_name
|
| 227 |
os.environ["LLM_API_KEY"] = api_key
|
| 228 |
os.environ["API_BASE_URL"] = base_url
|
|
|
|
| 229 |
system_health["connected"] = True
|
| 230 |
msg = f"Injected {cfg.model_name} credentials."
|
| 231 |
else:
|
|
|
|
| 248 |
|
| 249 |
@app.post("/config/difficulty")
|
| 250 |
async def set_difficulty(cfg: DifficultyConfig):
|
| 251 |
+
if active_env_instance and NATIVE_VERIFIED:
|
| 252 |
os.environ["TASK_ID"] = cfg.level.lower()
|
| 253 |
if "easy" in cfg.level.lower():
|
| 254 |
+
active_env_instance.difficulty = hft_mod.Difficulty.EASY
|
| 255 |
elif "medium" in cfg.level.lower():
|
| 256 |
+
active_env_instance.difficulty = hft_mod.Difficulty.MEDIUM
|
| 257 |
else:
|
| 258 |
+
active_env_instance.difficulty = hft_mod.Difficulty.HARD
|
| 259 |
return {"status": "success", "difficulty": cfg.level}
|
| 260 |
return {"status": "error", "message": "Engine not loaded"}
|
| 261 |
|
|
|
|
| 264 |
await websocket.accept()
|
| 265 |
try:
|
| 266 |
while True:
|
| 267 |
+
if active_env_instance and NATIVE_VERIFIED:
|
| 268 |
data = {
|
| 269 |
+
"active_count": active_env_instance.engine.active_count,
|
| 270 |
+
"total_ingested": active_env_instance.engine.total_ingested,
|
| 271 |
+
"ring_buffer_size": active_env_instance.engine.ring_buffer_size,
|
| 272 |
+
"pool_capacity": active_env_instance.engine.pool_capacity,
|
| 273 |
"latency_us": round(app_metrics["last_step_latency_us"], 3),
|
| 274 |
"status": "NATIVE_ACTIVE"
|
| 275 |
}
|
|
|
|
| 518 |
<script>
|
| 519 |
const consoleOut = document.getElementById('console-out');
|
| 520 |
const ledgerBody = document.getElementById('ledger-body');
|
|
|
|
|
|
|
| 521 |
let usingDefaultToken = false;
|
| 522 |
|
| 523 |
function logMsg(msg, type='info') {
|
|
|
|
| 588 |
async function discoverModels() {
|
| 589 |
const key = document.getElementById('api-key').value;
|
| 590 |
if(!key) return;
|
|
|
|
|
|
|
| 591 |
usingDefaultToken = false;
|
|
|
|
| 592 |
logMsg("Validating key and mapping models...", "info");
|
| 593 |
const res = await fetch('/config/llm', {
|
| 594 |
method: 'POST',
|
|
|
|
| 596 |
body: JSON.stringify({api_key: key})
|
| 597 |
});
|
| 598 |
const data = await res.json();
|
|
|
|
| 599 |
if(data.status === 'success') {
|
| 600 |
const select = document.getElementById('model-select');
|
| 601 |
select.innerHTML = '';
|
|
|
|
| 614 |
async function saveConfig() {
|
| 615 |
const key = document.getElementById('api-key').value;
|
| 616 |
const model = document.getElementById('model-select').value;
|
|
|
|
|
|
|
| 617 |
if (!model || (!key && !usingDefaultToken)) {
|
| 618 |
+
logMsg("Key/Model missing.", "err"); return;
|
|
|
|
| 619 |
}
|
|
|
|
| 620 |
const res = await fetch('/config/llm', {
|
| 621 |
method: 'POST',
|
| 622 |
headers: {'Content-Type': 'application/json'},
|
|
|
|
| 624 |
});
|
| 625 |
const data = await res.json();
|
| 626 |
if(data.status === 'success') {
|
| 627 |
+
logMsg(data.message, "success"); updateState();
|
|
|
|
| 628 |
} else {
|
| 629 |
logMsg(data.message, "err");
|
| 630 |
}
|
|
|
|
| 643 |
opt.value = m; opt.innerText = m;
|
| 644 |
select.appendChild(opt);
|
| 645 |
});
|
| 646 |
+
logMsg("Zero-config active.", "success"); updateState();
|
|
|
|
| 647 |
} else {
|
| 648 |
logMsg(data.message, "err");
|
| 649 |
}
|
|
|
|
| 680 |
body: JSON.stringify({action_type: actionType})
|
| 681 |
});
|
| 682 |
|
|
|
|
| 683 |
if (!actionRes.ok) {
|
| 684 |
const errData = await actionRes.json();
|
| 685 |
logMsg("LLM Error: " + (errData.detail || "Failed to generate decisions"), "err");
|
|
|
|
| 687 |
}
|
| 688 |
|
| 689 |
const actionData = await actionRes.json();
|
|
|
|
| 690 |
if(!actionData.decisions) {
|
| 691 |
logMsg("Decision matrix generation failed.", "err"); return;
|
| 692 |
}
|
| 693 |
|
| 694 |
logMsg(`Executing Step with ${actionData.decisions.length} decisions...`, "info");
|
| 695 |
|
|
|
|
| 696 |
const res = await fetch('/step', {
|
| 697 |
method: 'POST',
|
| 698 |
headers: {'Content-Type': 'application/json'},
|
|
|
|
| 708 |
|
| 709 |
const data = await res.json();
|
| 710 |
|
| 711 |
+
// FIX: Robust payload extraction handling regardless of OpenEnv wrapper depth
|
| 712 |
+
const reward = data.reward ?? data.observation?.reward ?? data.info?.reward ?? 0.0;
|
| 713 |
+
const done = data.done ?? data.observation?.done ?? data.info?.done ?? false;
|
| 714 |
+
const step = data.step_count ?? data.observation?.step_count ?? data.info?.step_count ?? data.observation?.metadata?.step_count ?? 'N/A';
|
| 715 |
|
| 716 |
logMsg(`[RECON] Reward: ${reward.toFixed(4)} | Success`, reward >= 0.8 ? 'success' : 'warn');
|
| 717 |
|
|
|
|
| 732 |
}
|
| 733 |
}
|
| 734 |
|
| 735 |
+
// FIX: Auto-Reset the environment on boot so it actually has data to process
|
| 736 |
+
window.addEventListener('DOMContentLoaded', async () => {
|
| 737 |
+
logMsg("Auto-initializing environment engine...", "info");
|
| 738 |
+
await executeReset();
|
| 739 |
+
setInterval(updateState, 1000);
|
| 740 |
+
updateState();
|
| 741 |
+
});
|
| 742 |
+
|
| 743 |
</script>
|
| 744 |
</body>
|
| 745 |
</html>
|
|
|
|
| 747 |
return HTMLResponse(content=html_content)
|
| 748 |
|
| 749 |
def main():
|
|
|
|
| 750 |
port = int(os.getenv("PORT", 7860))
|
| 751 |
uvicorn.run(app, host="0.0.0.0", port=port)
|
| 752 |
|