NODEDC_1C/llm_normalizer/frontend/src/components/OutputPanel.tsx

88 lines
3.7 KiB
TypeScript

import { PanelFrame } from "./PanelFrame";
import { JsonView } from "./JsonView";
import type { NormalizeResultState, TabKey } from "../state/types";
interface OutputPanelProps {
tab: TabKey;
onTabChange: (tab: TabKey) => void;
result: NormalizeResultState | null;
appLogs: string[];
}
const TAB_LABELS: Record<TabKey, string> = {
normalized: "Normalized JSON",
fragments: "Fragment View",
scope: "Scope View",
flags: "Flags View",
route: "Route Simulation",
raw: "Raw model output",
validation: "Validation",
logs: "Logs"
};
function asObject(value: unknown): Record<string, unknown> | null {
return value && typeof value === "object" ? (value as Record<string, unknown>) : null;
}
export function OutputPanel({ tab, onTabChange, result, appLogs }: OutputPanelProps) {
const tabs: TabKey[] = ["normalized", "fragments", "scope", "flags", "route", "raw", "validation", "logs"];
const normalized = asObject(result?.normalized);
const schemaVersion = String(normalized?.schema_version ?? "");
const isV2 =
schemaVersion === "normalized_query_v2" ||
schemaVersion === "normalized_query_v2_0_1" ||
schemaVersion === "normalized_query_v2_0_2";
const fragmentsView = isV2
? {
fragments: normalized?.fragments ?? [],
discarded_fragments: normalized?.discarded_fragments ?? []
}
: { note: "Fragment View доступен для normalized_query_v2." };
const scopeView = isV2
? {
message_in_scope: normalized?.message_in_scope ?? null,
scope_confidence: normalized?.scope_confidence ?? null,
contains_multiple_tasks: normalized?.contains_multiple_tasks ?? null,
global_notes: normalized?.global_notes ?? null
}
: { note: "Scope View доступен для normalized_query_v2." };
const flagsView = isV2
? Array.isArray(normalized?.fragments)
? (normalized?.fragments as Array<Record<string, unknown>>).map((fragment) => ({
fragment_id: fragment.fragment_id ?? null,
domain_relevance: fragment.domain_relevance ?? null,
candidate_labels: fragment.candidate_labels ?? [],
execution_readiness: fragment.execution_readiness ?? null,
clarification_reason: fragment.clarification_reason ?? null,
soft_assumption_used: fragment.soft_assumption_used ?? [],
route_status: fragment.route_status ?? null,
no_route_reason: fragment.no_route_reason ?? null,
flags: fragment.flags ?? {}
}))
: []
: { note: "Flags View доступен для normalized_query_v2." };
return (
<PanelFrame title="Выходные данные" subtitle="Structured output и диагностические вкладки.">
<div className="tab-row">
{tabs.map((item) => (
<button key={item} type="button" className={tab === item ? "tab active" : "tab"} onClick={() => onTabChange(item)}>
{TAB_LABELS[item]}
</button>
))}
</div>
{tab === "normalized" ? <JsonView value={result?.normalized ?? { note: "Нет данных." }} /> : null}
{tab === "fragments" ? <JsonView value={fragmentsView} /> : null}
{tab === "scope" ? <JsonView value={scopeView} /> : null}
{tab === "flags" ? <JsonView value={flagsView} /> : null}
{tab === "route" ? <JsonView value={result?.route_hint_summary ?? { note: "Нет данных." }} /> : null}
{tab === "raw" ? <JsonView value={result?.raw_model_output ?? { note: "Нет данных." }} /> : null}
{tab === "validation" ? <JsonView value={result?.validation ?? { note: "Нет данных." }} /> : null}
{tab === "logs" ? <JsonView value={appLogs} /> : null}
</PanelFrame>
);
}