PMFlow/backend/app/services/experiment_sync/mixin_helpers.py

78 lines
2.9 KiB
Python

"""Low-level helper methods for experiment sync service."""
from __future__ import annotations
from .shared import Any, Dict, Experiment, ExperimentTruthNodeSync, Optional, TruthNode, and_, now_cn_aware, select
class ExperimentSyncHelpersMixin:
"""Fetchers and sync-data mutation helpers."""
async def _get_experiment(self, experiment_id: int, tenant_id: int) -> Optional[Experiment]:
result = await self.db.execute(
select(Experiment).where(
and_(Experiment.id == experiment_id, Experiment.tenant_id == tenant_id)
)
)
return result.scalar_one_or_none()
async def _get_truth_node(self, truth_node_id: int, tenant_id: int) -> Optional[TruthNode]:
result = await self.db.execute(
select(TruthNode).where(
and_(TruthNode.id == truth_node_id, TruthNode.tenant_id == tenant_id)
)
)
return result.scalar_one_or_none()
async def _get_sync_record(self, sync_id: int, tenant_id: int) -> Optional[ExperimentTruthNodeSync]:
result = await self.db.execute(
select(ExperimentTruthNodeSync).where(
and_(ExperimentTruthNodeSync.id == sync_id, ExperimentTruthNodeSync.tenant_id == tenant_id)
)
)
return result.scalar_one_or_none()
def _calc_confidence(self, current_score: Optional[float]) -> float:
score = float(current_score or 0.0)
if score > 1:
score /= 100.0
return round(max(0.0, min(1.0, score)), 2)
def _build_sync_data(
self,
experiment: Experiment,
truth_node: TruthNode,
sync_type: str,
) -> Dict[str, Any]:
return {
"sync_type": sync_type,
"experiment_summary": {
"id": experiment.id,
"title": experiment.title,
"status": experiment.status,
"target_metric": experiment.target_metric,
"current_score": experiment.current_score,
},
"previous_truth_content": truth_node.content,
}
async def _apply_sync_to_truth_node(
self,
record: ExperimentTruthNodeSync,
truth_node: TruthNode,
) -> None:
content = truth_node.content if isinstance(truth_node.content, dict) else {}
if not isinstance(content, dict):
content = {"raw": str(truth_node.content)}
sync_section = content.get("experiment_sync", {})
sync_section["last_sync"] = {
"sync_id": record.id,
"sync_type": record.sync_type,
"confidence_score": record.confidence_score,
"experiment_summary": (record.sync_data or {}).get("experiment_summary", {}),
"applied_at": now_cn_aware().isoformat(),
}
content["experiment_sync"] = sync_section
truth_node.content = content
truth_node.version = int(truth_node.version or 1) + 1