|
# retoor <retoor@molodetz.nl>
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import logging
|
|
from typing import Any
|
|
|
|
from devplacepy.services.jobs.isslop import store
|
|
from devplacepy.services.jobs.isslop.events import (
|
|
KIND_DOM,
|
|
KIND_DONE,
|
|
KIND_ERROR,
|
|
KIND_FILE,
|
|
KIND_IMAGE,
|
|
KIND_REPORT,
|
|
WorkerEvent,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
SCORE_FIELDS: tuple[str, ...] = (
|
|
"grade",
|
|
"slop_score",
|
|
"origin_score",
|
|
"human_percent",
|
|
"ai_percent",
|
|
"category",
|
|
"confidence",
|
|
"content_hash",
|
|
"source_kind",
|
|
"files_total",
|
|
"files_analyzed",
|
|
"detected_builder",
|
|
)
|
|
|
|
ERROR_MESSAGE_CAP = 2000
|
|
TELLS_CAP = 4000
|
|
DESCRIPTION_CAP = 2000
|
|
|
|
|
|
class EventPersister:
|
|
def __init__(self, analysis_uid: str) -> None:
|
|
self._analysis_uid = analysis_uid
|
|
self._seq = 0
|
|
|
|
@property
|
|
def seq(self) -> int:
|
|
return self._seq
|
|
|
|
@property
|
|
def analysis_uid(self) -> str:
|
|
return self._analysis_uid
|
|
|
|
def apply(self, event: WorkerEvent) -> dict[str, Any]:
|
|
self._seq += 1
|
|
payload_for_storage = dict(event.data)
|
|
if event.kind == KIND_REPORT:
|
|
markdown = str(payload_for_storage.pop("markdown", ""))
|
|
model_used = str(payload_for_storage.get("model_used", "unknown"))
|
|
store.save_report(self._analysis_uid, markdown, model_used)
|
|
store.insert_event(
|
|
self._analysis_uid,
|
|
self._seq,
|
|
event.kind,
|
|
event.message,
|
|
json.dumps(payload_for_storage, ensure_ascii=False),
|
|
)
|
|
if event.kind == KIND_FILE:
|
|
store.insert_file_result(
|
|
self._analysis_uid,
|
|
{
|
|
"path": str(event.data.get("path", "")),
|
|
"language": str(event.data.get("language", "unknown")),
|
|
"lines": int(event.data.get("sloc", 0)),
|
|
"origin_score": float(event.data.get("origin_score", 0.0)),
|
|
"quality_deficit_score": float(event.data.get("quality_deficit", 0.0)),
|
|
"category": str(event.data.get("category", "uncertain")),
|
|
"signals": json.dumps(event.data.get("signals", []), ensure_ascii=False)[: store.SIGNALS_CAP],
|
|
"source": str(event.data.get("source") or ""),
|
|
},
|
|
)
|
|
if event.kind == KIND_IMAGE:
|
|
store.insert_image_result(
|
|
self._analysis_uid,
|
|
{
|
|
"path": str(event.data.get("path", "")),
|
|
"ai_probability": float(event.data.get("ai_probability", 0.0)),
|
|
"grade": str(event.data.get("grade", "n/a")),
|
|
"verdict": str(event.data.get("verdict", "uncertain")),
|
|
"image_kind": str(event.data.get("image_kind", "image")),
|
|
"tells": json.dumps(event.data.get("tells", []), ensure_ascii=False)[:TELLS_CAP],
|
|
"description": str(event.data.get("description", ""))[:DESCRIPTION_CAP],
|
|
"thumb": str(event.data.get("thumb") or ""),
|
|
},
|
|
)
|
|
if event.kind == KIND_DOM:
|
|
store.insert_dom_result(
|
|
self._analysis_uid,
|
|
{
|
|
"url": str(event.data.get("url", "")),
|
|
"detected_builder": str(event.data.get("detected_builder") or ""),
|
|
"signal_count": int(event.data.get("signal_count", 0)),
|
|
"screenshot": str(event.data.get("screenshot") or ""),
|
|
"signals": json.dumps(event.data.get("signals", []), ensure_ascii=False)[: store.SIGNALS_CAP],
|
|
},
|
|
)
|
|
if event.kind == KIND_DONE:
|
|
updates: dict[str, Any] = {
|
|
key: event.data.get(key) for key in SCORE_FIELDS if key in event.data
|
|
}
|
|
updates["quality_deficit_score"] = event.data.get("quality_deficit")
|
|
updates["dom_slop_score"] = event.data.get("dom_slop_score")
|
|
updates["status"] = "completed"
|
|
updates["finished_at"] = store.utc_now()
|
|
store.update_analysis(self._analysis_uid, **updates)
|
|
if event.kind == KIND_ERROR:
|
|
store.update_analysis(
|
|
self._analysis_uid,
|
|
status="failed",
|
|
finished_at=store.utc_now(),
|
|
error_message_text=event.message[:ERROR_MESSAGE_CAP],
|
|
)
|
|
return {
|
|
"analysis": self._analysis_uid,
|
|
"seq": self._seq,
|
|
"kind": event.kind,
|
|
"message": event.message,
|
|
"data": payload_for_storage if event.kind != KIND_FILE else event.data,
|
|
"created_at": store.utc_now(),
|
|
}
|