121 lines
4.9 KiB
TypeScript
121 lines
4.9 KiB
TypeScript
import { api, supplementalApi } from "../../lib/api";
|
|
import type { components } from "../../lib/api.gen";
|
|
|
|
type ApiSchema<Name extends keyof components["schemas"]> =
|
|
components["schemas"][Name];
|
|
|
|
/** G5 wire DTO는 생성된 FastAPI OpenAPI 계약을 그대로 사용한다. */
|
|
export type CalibrationConfidenceInterval = ApiSchema<"ConfidenceInterval">;
|
|
export type CalibrationPair = ApiSchema<"CalibrationPair">;
|
|
export type CompetencyCalibrationAssessment =
|
|
ApiSchema<"CompetencyCalibrationAssessment">;
|
|
export type MetacognitivePrescription = ApiSchema<"MetacognitivePrescription">;
|
|
export type PredictionRevisionItem = ApiSchema<"PredictionRevisionItem">;
|
|
export type PredictionLockItem = ApiSchema<"PredictionLockItem">;
|
|
export type PerformanceObservationItem = ApiSchema<"PerformanceObservationItem">;
|
|
export type PredictionHistoryItem = ApiSchema<"PredictionHistoryItem">;
|
|
export type CalibrationAssessmentItem = ApiSchema<"CalibrationAssessmentItem">;
|
|
export type TransferAssessment = ApiSchema<"TransferAssessment">;
|
|
export type TransferTrialItem = ApiSchema<"TransferTrialItem">;
|
|
export type TransferAssessmentItem = ApiSchema<"TransferAssessmentItem">;
|
|
export type SyntheticSubgroupResult = ApiSchema<"SyntheticSubgroupResult">;
|
|
export type SubgroupDriftReport = ApiSchema<"SubgroupDriftReport">;
|
|
export type DriftReportItem = ApiSchema<"DriftReportItem">;
|
|
export type TransferSuiteItem = ApiSchema<"TransferSuiteItem">;
|
|
export type TeacherReviewItem = ApiSchema<"TeacherReviewItem">;
|
|
export type CalibrationTransferReadModelResponse =
|
|
ApiSchema<"CalibrationTransferReadModelResponse">;
|
|
export type PredictionRevisionRequest = ApiSchema<"PredictionRevisionRequest">;
|
|
export type PredictionRevisionResponse = ApiSchema<"PredictionRevisionResponse">;
|
|
export type PredictionLockRequest = ApiSchema<"PredictionLockRequest">;
|
|
export type PredictionLockResponse = ApiSchema<"PredictionLockResponse">;
|
|
export type TeacherCorrectionResponse = ApiSchema<"TeacherReviewResponse">;
|
|
export type ActualTransferAssessment = ApiSchema<"ActualTransferAssessment">;
|
|
export type ActualTransferExecutionRequest =
|
|
ApiSchema<"ActualTransferExecutionRequest">;
|
|
export type ActualTransferExecutionResponse =
|
|
ApiSchema<"ActualTransferExecutionResponse">;
|
|
|
|
export type CalibrationBias = CompetencyCalibrationAssessment["bias"];
|
|
export type CalibrationImprovement =
|
|
CompetencyCalibrationAssessment["improvement"];
|
|
export type PerformanceStatus = PerformanceObservationItem["status"];
|
|
export type RelationshipStyle = TransferTrialItem["relationship_style"];
|
|
export type DriftStatus = SubgroupDriftReport["status"];
|
|
|
|
/** 교수자 UI는 원판정 쓰기를 열지 않고 append-only 교정만 허용한다. */
|
|
export type TeacherCorrectionRequest = Omit<
|
|
ApiSchema<"TeacherReviewRequest">,
|
|
"disposition" | "correction_payload"
|
|
> & {
|
|
disposition: "corrected";
|
|
correction_payload: { teacher_note: string };
|
|
};
|
|
|
|
interface TeacherSessionRef {
|
|
session_id: string;
|
|
learner_id: string;
|
|
}
|
|
|
|
interface TeacherDashboardLookup {
|
|
pending_reviews?: TeacherSessionRef[];
|
|
recent_sessions?: TeacherSessionRef[];
|
|
}
|
|
|
|
function learnerPath(learnerId?: string): string {
|
|
return learnerId
|
|
? `/calibration/learners/${encodeURIComponent(learnerId)}`
|
|
: "/calibration/learners/me";
|
|
}
|
|
|
|
export class CalibrationLearnerContextError extends Error {
|
|
constructor() {
|
|
super("이 회기의 학습자 캘리브레이션 원장을 찾지 못했습니다.");
|
|
this.name = "CalibrationLearnerContextError";
|
|
}
|
|
}
|
|
|
|
export const calibrationTransferApi = {
|
|
getForLearner: (sessionId: string, signal?: AbortSignal) =>
|
|
supplementalApi.get<CalibrationTransferReadModelResponse>(
|
|
`${learnerPath()}?session_id=${encodeURIComponent(sessionId)}`,
|
|
{ signal },
|
|
),
|
|
|
|
getForTeacherSession: async (sessionId: string, signal?: AbortSignal) => {
|
|
const dashboard = await supplementalApi.get<TeacherDashboardLookup>(
|
|
"/teacher/dashboard",
|
|
{ signal },
|
|
);
|
|
const session = [
|
|
...(dashboard.pending_reviews ?? []),
|
|
...(dashboard.recent_sessions ?? []),
|
|
].find((item) => item.session_id === sessionId);
|
|
if (!session) throw new CalibrationLearnerContextError();
|
|
return supplementalApi.get<CalibrationTransferReadModelResponse>(
|
|
learnerPath(session.learner_id),
|
|
{ signal },
|
|
);
|
|
},
|
|
|
|
appendPredictionRevision: (body: PredictionRevisionRequest) =>
|
|
api.post<PredictionRevisionResponse>(
|
|
"/calibration/predictions/revisions",
|
|
body,
|
|
),
|
|
|
|
lockPrediction: (historyId: string, body: PredictionLockRequest) =>
|
|
api.post<PredictionLockResponse>(
|
|
`/calibration/predictions/${encodeURIComponent(historyId)}/lock`,
|
|
body,
|
|
),
|
|
|
|
appendTeacherCorrection: (body: TeacherCorrectionRequest) =>
|
|
api.post<TeacherCorrectionResponse>("/calibration/reviews", body),
|
|
|
|
appendActualTransferExecution: (body: ActualTransferExecutionRequest) =>
|
|
api.post<ActualTransferExecutionResponse>(
|
|
"/calibration/transfer-executions",
|
|
body,
|
|
),
|
|
};
|