Spaces:
Running
Running
Upload app/services/audit_engine.py with huggingface_hub
Browse files- app/services/audit_engine.py +78 -0
app/services/audit_engine.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import logging
|
| 3 |
+
import os
|
| 4 |
+
from app.services.supabase import get_supabase
|
| 5 |
+
from app.config import settings
|
| 6 |
+
|
| 7 |
+
logger = logging.getLogger(__name__)
|
| 8 |
+
|
| 9 |
+
AUDIT_MODEL = "groq/llama-3.3-70b-versatile"
|
| 10 |
+
|
| 11 |
+
ANALYSIS_PROMPT = """
|
| 12 |
+
You are an intelligent observability engine for BioNexus, a bioinformatics SaaS platform.
|
| 13 |
+
Below is the ordered sequence of events from a user session.
|
| 14 |
+
|
| 15 |
+
Your job:
|
| 16 |
+
1. Identify what the user is trying to accomplish
|
| 17 |
+
2. Find any steps that failed, produced unexpected output, or took unusually long
|
| 18 |
+
3. Detect patterns — e.g. user retried the same step 3 times, or a tool returned 0 results silently
|
| 19 |
+
4. Output a JSON object with this exact shape:
|
| 20 |
+
|
| 21 |
+
{
|
| 22 |
+
"severity": "info" | "warning" | "critical",
|
| 23 |
+
"insight": "Plain-language summary of what happened in this session",
|
| 24 |
+
"affected_steps": ["step_name_1", "step_name_2"],
|
| 25 |
+
"suggestion": "What should be fixed or what the user should try next",
|
| 26 |
+
"anomalies": ["list of specific anomalies detected"]
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
Session events:
|
| 30 |
+
{events_json}
|
| 31 |
+
|
| 32 |
+
Return ONLY the JSON object. No markdown, no preamble.
|
| 33 |
+
"""
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def run_audit(session_id: str, triggered_by: str | None = None) -> None:
|
| 37 |
+
sb = get_supabase()
|
| 38 |
+
resp = sb.table("audit_events") \
|
| 39 |
+
.select("*") \
|
| 40 |
+
.eq("session_id", session_id) \
|
| 41 |
+
.order("timestamp") \
|
| 42 |
+
.execute()
|
| 43 |
+
|
| 44 |
+
events = resp.data
|
| 45 |
+
if not events:
|
| 46 |
+
return
|
| 47 |
+
|
| 48 |
+
try:
|
| 49 |
+
import litellm
|
| 50 |
+
response = litellm.completion(
|
| 51 |
+
model=AUDIT_MODEL,
|
| 52 |
+
messages=[{
|
| 53 |
+
"role": "user",
|
| 54 |
+
"content": ANALYSIS_PROMPT.format(
|
| 55 |
+
events_json=json.dumps(events, indent=2, default=str)
|
| 56 |
+
),
|
| 57 |
+
}],
|
| 58 |
+
max_tokens=1000,
|
| 59 |
+
temperature=0.1,
|
| 60 |
+
api_key=settings.GROQ_API_KEY,
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
raw = response.choices[0].message.content.strip()
|
| 64 |
+
insight_data = json.loads(raw)
|
| 65 |
+
|
| 66 |
+
sb.table("audit_insights").insert({
|
| 67 |
+
"session_id": session_id,
|
| 68 |
+
"triggered_by": triggered_by,
|
| 69 |
+
"severity": insight_data.get("severity", "info"),
|
| 70 |
+
"insight": insight_data.get("insight", ""),
|
| 71 |
+
"affected_steps": insight_data.get("affected_steps", []),
|
| 72 |
+
"suggestion": insight_data.get("suggestion", ""),
|
| 73 |
+
"raw_audit": {"events": events, "anomalies": insight_data.get("anomalies", [])},
|
| 74 |
+
}).execute()
|
| 75 |
+
|
| 76 |
+
logger.info(f"Audit insight stored for session {session_id[:8]}...")
|
| 77 |
+
except Exception as e:
|
| 78 |
+
logger.warning(f"Audit engine failed for session {session_id[:8]}...: {e}")
|