feat(confidence-engine): generate investigation report on demand
This commit is contained in:
@@ -1,18 +1,69 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { loadInvestigation } from "@/lib/storage/investigation-storage";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { loadInvestigation, saveInvestigation } from "@/lib/storage/investigation-storage";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function ReportPage() {
|
||||
const [existing, setExisting] = useState(null);
|
||||
const [hydrated, setHydrated] = useState(false);
|
||||
const [generationLoading, setGenerationLoading] = useState(false);
|
||||
const [generationError, setGenerationError] = useState(false);
|
||||
|
||||
const generationAttempted = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
setExisting(loadInvestigation());
|
||||
setHydrated(true);
|
||||
}, []);
|
||||
|
||||
// First-generation: create report when none persists (v0.58)
|
||||
useEffect(() => {
|
||||
if (!hydrated) return;
|
||||
if (existing?.investigationReport) return;
|
||||
if (generationAttempted.current) return;
|
||||
generationAttempted.current = true;
|
||||
|
||||
const situationGraph = existing?.situationGraph;
|
||||
const findings = existing?.findings ?? [];
|
||||
|
||||
if (!situationGraph) {
|
||||
setGenerationError(true);
|
||||
return;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
setGenerationLoading(true);
|
||||
try {
|
||||
const res = await fetch("/api/cases/overview", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ situationGraph, findings }),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
setGenerationError(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
setExisting((prev) => {
|
||||
const updated = { ...prev, investigationReport: { understanding: data.understanding, plausibleInterpretations: data.plausibleInterpretations, hasPlausibleInterpretations: true } };
|
||||
saveInvestigation(updated);
|
||||
return updated;
|
||||
});
|
||||
} else {
|
||||
setGenerationError(true);
|
||||
}
|
||||
} catch {
|
||||
setGenerationError(true);
|
||||
} finally {
|
||||
setGenerationLoading(false);
|
||||
}
|
||||
})();
|
||||
}, [hydrated, existing]);
|
||||
|
||||
const report = existing?.investigationReport || null;
|
||||
const scenario = hydrated ? (existing?.scenario || "") : null;
|
||||
|
||||
@@ -74,13 +125,20 @@ export default function ReportPage() {
|
||||
) : (
|
||||
/* Skeleton / loading state when no persisted report exists */
|
||||
<>
|
||||
<div className="mt-8 rounded-xl border-[2.5px] border-gray-200 bg-gray-50/50 px-8 pt-6 pb-7">
|
||||
<div className="mt-8 rounded-xl border-[2.5px] border-gray-200 bg-gray-50/50 px-8 pt-6 pb-7 shadow-sm">
|
||||
<h2 className="mb-3 text-[11px] font-bold tracking-[.18em] uppercase text-gray-400">
|
||||
What we understand
|
||||
</h2>
|
||||
<p className="text-base leading-relaxed text-gray-300 animate-pulse">
|
||||
Report generation pending. A summary will appear here once the investigation reaches milestone.
|
||||
</p>
|
||||
{generationLoading ? (
|
||||
<div className="flex flex-col gap-3 py-2" aria-live="polite">
|
||||
<span className="text-[11px] font-semibold tracking-wider text-gray-400 uppercase">Generating report…</span>
|
||||
{[0, 1, 2].map((i) => (
|
||||
<div key={i} className="h-4 w-full rounded animate-pulse" style={{ backgroundColor: "rgb(229 231 235)", animationDelay: `${i * 150}ms`, width: i === 1 ? "80%" : i === 2 ? "65%" : "90%" }} />
|
||||
))}
|
||||
</div>
|
||||
) : generationError ? (
|
||||
<p className="text-sm text-red-600">Report generation failed. You may try again from the Investigation page.</p>
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user