czty's picture
Add files using upload-large-folder tool
a9e46a4 verified
Raw
History Blame Contribute Delete
7.06 kB
from __future__ import annotations
from pathlib import Path
from typing import Any
import json
from .schemas import ExperimentReport, Hypothesis, Insight, PipelineConfiguration, ValidationReport
class SharedKnowledgeSpace:
"""File-based bridge between V1 and T1."""
def __init__(self, root: str | Path):
self.root = Path(root)
self.reports_dir = self.root / "experiment_reports"
self.insights_dir = self.root / "insights"
self.configs_dir = self.root / "pipeline_configs"
self.hypotheses_dir = self.root / "hypotheses"
self.validation_reports_dir = self.root / "validation_reports"
self.summary_stats_file = self.root / "summary_statistics.json"
for d in (
self.reports_dir,
self.insights_dir,
self.configs_dir,
self.hypotheses_dir,
self.validation_reports_dir,
):
d.mkdir(parents=True, exist_ok=True)
@staticmethod
def _write_json(path: Path, payload: dict[str, Any]) -> None:
path.write_text(json.dumps(payload, indent=2, ensure_ascii=True), encoding="utf-8")
@staticmethod
def _read_json(path: Path) -> dict[str, Any]:
return json.loads(path.read_text(encoding="utf-8"))
def save_report(self, report: ExperimentReport) -> Path:
fp = self.reports_dir / f"{report.run_id}.json"
self._write_json(fp, report.to_dict())
return fp
def save_insight(self, insight: Insight) -> Path:
fp = self.insights_dir / f"{insight.insight_id}.json"
self._write_json(fp, insight.to_dict())
return fp
def save_pipeline_config(self, config: PipelineConfiguration) -> Path:
fp = self.configs_dir / f"{config.config_id}.json"
self._write_json(fp, config.to_dict())
return fp
def save_hypothesis(self, hypothesis: Hypothesis) -> Path:
fp = self.hypotheses_dir / f"{hypothesis.hypothesis_id}.json"
self._write_json(fp, hypothesis.to_dict())
return fp
def save_validation_report(self, report: ValidationReport) -> Path:
fp = self.validation_reports_dir / f"{report.validation_id}.json"
self._write_json(fp, report.to_dict())
return fp
def list_reports(self) -> list[dict[str, Any]]:
items: list[dict[str, Any]] = []
for fp in sorted(self.reports_dir.glob("*.json")):
items.append(self._read_json(fp))
return items
def list_insights(self) -> list[dict[str, Any]]:
items: list[dict[str, Any]] = []
for fp in sorted(self.insights_dir.glob("*.json")):
items.append(self._read_json(fp))
return items
def list_configs(self) -> list[dict[str, Any]]:
items: list[dict[str, Any]] = []
for fp in sorted(self.configs_dir.glob("*.json")):
items.append(self._read_json(fp))
return items
def list_hypotheses(self) -> list[dict[str, Any]]:
items: list[dict[str, Any]] = []
for fp in sorted(self.hypotheses_dir.glob("*.json")):
items.append(self._read_json(fp))
return items
def list_validation_reports(self) -> list[dict[str, Any]]:
items: list[dict[str, Any]] = []
for fp in sorted(self.validation_reports_dir.glob("*.json")):
items.append(self._read_json(fp))
return items
def latest_config_for_task(self, task_scope: str) -> dict[str, Any] | None:
matched = [cfg for cfg in self.list_configs() if cfg.get("task_scope") == task_scope]
return matched[-1] if matched else None
def get_hypothesis_context(self, domain: str, top_k: int = 5) -> list[dict[str, Any]]:
domain_l = domain.strip().lower()
hypotheses = self.list_hypotheses()
validations = self.list_validation_reports()
by_hid = {}
for vr in validations:
hid = vr.get("hypothesis_id", "")
if not hid:
continue
by_hid.setdefault(hid, []).append(vr)
scored: list[dict[str, Any]] = []
for h in hypotheses:
h_domain = str(h.get("domain", "")).lower()
if domain_l and domain_l not in h_domain and domain_l not in " ".join(h.get("tags", [])).lower():
continue
reports = by_hid.get(h.get("hypothesis_id", ""), [])
if reports:
avg_score = sum(float(r.get("score", 0.0)) for r in reports) / len(reports)
avg_conf = sum(float(r.get("confidence", 0.0)) for r in reports) / len(reports)
else:
avg_score = 0.0
avg_conf = 0.0
scored.append(
{
"hypothesis": h,
"validation_reports": reports,
"avg_score": avg_score,
"avg_confidence": avg_conf,
}
)
scored.sort(key=lambda x: (x["avg_score"], x["avg_confidence"]), reverse=True)
return scored[: max(0, top_k)]
def update_summary_statistics(self) -> dict[str, Any]:
validations = self.list_validation_reports()
tag_stats: dict[str, dict[str, float]] = {}
failure_reason_counter: dict[str, int] = {}
success_scores: list[float] = []
hypotheses = {h.get("hypothesis_id", ""): h for h in self.list_hypotheses()}
for r in validations:
status = r.get("status", "inconclusive")
score = float(r.get("score", 0.0))
if status == "success":
success_scores.append(score)
reason = str(r.get("failure_reason", "")).strip()
if status == "failed" and reason:
failure_reason_counter[reason] = failure_reason_counter.get(reason, 0) + 1
hid = r.get("hypothesis_id", "")
h = hypotheses.get(hid, {})
for tag in h.get("tags", []):
s = tag_stats.setdefault(tag, {"count": 0.0, "success": 0.0, "score_sum": 0.0})
s["count"] += 1
if status == "success":
s["success"] += 1
s["score_sum"] += score
tag_summary = {}
for tag, s in tag_stats.items():
count = max(1.0, s["count"])
tag_summary[tag] = {
"count": int(s["count"]),
"success_rate": s["success"] / count,
"avg_score": s["score_sum"] / count,
}
payload = {
"total_validation_reports": len(validations),
"overall_avg_success_score": (sum(success_scores) / len(success_scores)) if success_scores else 0.0,
"tag_summary": tag_summary,
"failure_reason_counter": failure_reason_counter,
}
self._write_json(self.summary_stats_file, payload)
return payload
def get_summary_statistics(self) -> dict[str, Any]:
if not self.summary_stats_file.exists():
return self.update_summary_statistics()
return self._read_json(self.summary_stats_file)