e4dcfc49aa
Tests / Import Check (Python 3.13) (push) Has been cancelled
Tests / Import Check (Python 3.14) (push) Has been cancelled
Tests / Python Tests (Python 3.11) (push) Has been cancelled
Tests / Python Tests (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.14) (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Tests / Lint and Format (push) Has been cancelled
Tests / Web Node Tests (push) Has been cancelled
Tests / Import Check (Python 3.11) (push) Has been cancelled
Tests / Import Check (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.13) (push) Has been cancelled
189 lines
4.9 KiB
TypeScript
189 lines
4.9 KiB
TypeScript
import { apiUrl, apiFetch } from "./api";
|
|
|
|
export interface ModuleInit {
|
|
id: string;
|
|
name: string;
|
|
order: number;
|
|
pass_threshold?: number;
|
|
knowledge_points: {
|
|
id: string;
|
|
name: string;
|
|
type: string;
|
|
module_id: string;
|
|
}[];
|
|
}
|
|
|
|
export interface LearningKnowledgePoint {
|
|
id: string;
|
|
name: string;
|
|
type: string;
|
|
}
|
|
|
|
export interface LearningModule {
|
|
id: string;
|
|
name: string;
|
|
order: number;
|
|
pass_threshold: number;
|
|
knowledge_points: LearningKnowledgePoint[];
|
|
}
|
|
|
|
export interface ProgressDetail {
|
|
book_id: string;
|
|
modules: LearningModule[];
|
|
mastery_levels: Record<string, number>;
|
|
current_module_id?: string;
|
|
current_stage?: string;
|
|
diagnostic?: unknown;
|
|
}
|
|
|
|
export async function fetchProgress(bookId: string): Promise<ProgressDetail> {
|
|
const res = await apiFetch(apiUrl(`/api/v1/learning/progress/${bookId}`));
|
|
if (!res.ok) throw new Error(`Failed to fetch progress: ${res.status}`);
|
|
return res.json() as Promise<ProgressDetail>;
|
|
}
|
|
|
|
export async function initModules(bookId: string, modules: ModuleInit[]) {
|
|
const res = await apiFetch(
|
|
apiUrl(`/api/v1/learning/progress/${bookId}/init-modules`),
|
|
{
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ modules }),
|
|
},
|
|
);
|
|
if (!res.ok) throw new Error(`Failed to init modules: ${res.status}`);
|
|
return res.json();
|
|
}
|
|
|
|
// ── Mastery map (the dashboard view) ──────────────────────────────────────
|
|
// Mirrors deeptutor/learning/policy.py map_summary + next_objective.
|
|
|
|
export type ObjectiveStatus = "new" | "learning" | "mastered";
|
|
|
|
export interface MapKnowledgePoint {
|
|
id: string;
|
|
name: string;
|
|
type: string;
|
|
status: ObjectiveStatus;
|
|
mastery: number;
|
|
}
|
|
|
|
export interface MapModule {
|
|
id: string;
|
|
name: string;
|
|
order: number;
|
|
mastered: number;
|
|
total: number;
|
|
knowledge_points: MapKnowledgePoint[];
|
|
}
|
|
|
|
export interface MasteryMap {
|
|
counts: { mastered: number; learning: number; new: number; total: number };
|
|
due_reviews: number;
|
|
complete: boolean;
|
|
modules: MapModule[];
|
|
}
|
|
|
|
export interface NextStep {
|
|
action: string;
|
|
knowledge_point_name: string;
|
|
knowledge_point_type: string;
|
|
status: string;
|
|
mastery: number;
|
|
threshold: number;
|
|
reason: string;
|
|
}
|
|
|
|
export interface MasteryMapResult {
|
|
book_id: string;
|
|
next: NextStep;
|
|
map: MasteryMap;
|
|
}
|
|
|
|
export async function fetchMasteryMap(
|
|
pathId: string,
|
|
): Promise<MasteryMapResult> {
|
|
const res = await apiFetch(
|
|
apiUrl(`/api/v1/learning/progress/${encodeURIComponent(pathId)}/map`),
|
|
);
|
|
if (!res.ok) throw new Error(`Failed to fetch mastery map: ${res.status}`);
|
|
return res.json() as Promise<MasteryMapResult>;
|
|
}
|
|
|
|
export interface ProgressSummary {
|
|
book_id: string;
|
|
name: string;
|
|
modules_count: number;
|
|
kp_count: number;
|
|
current_stage: string;
|
|
avg_mastery_pct: number;
|
|
updated_at: number;
|
|
}
|
|
|
|
export interface ProgressListResult {
|
|
summaries: ProgressSummary[];
|
|
errors: { book_id: string; error: string }[];
|
|
}
|
|
|
|
export async function fetchAllProgress(): Promise<ProgressListResult> {
|
|
const res = await apiFetch(apiUrl("/api/v1/learning/progress"));
|
|
if (!res.ok) throw new Error(`Failed to fetch all progress: ${res.status}`);
|
|
return res.json();
|
|
}
|
|
|
|
export async function deleteProgress(bookId: string) {
|
|
const res = await apiFetch(
|
|
apiUrl(`/api/v1/learning/progress/${encodeURIComponent(bookId)}`),
|
|
{ method: "DELETE" },
|
|
);
|
|
if (!res.ok) throw new Error(`Failed to delete progress: ${res.status}`);
|
|
return res.json();
|
|
}
|
|
|
|
export async function redoProgress(bookId: string) {
|
|
const res = await apiFetch(
|
|
apiUrl(`/api/v1/learning/progress/${encodeURIComponent(bookId)}/redo`),
|
|
{ method: "POST" },
|
|
);
|
|
if (!res.ok) throw new Error(`Failed to redo progress: ${res.status}`);
|
|
return res.json();
|
|
}
|
|
|
|
export async function importFromBook(
|
|
bookId: string,
|
|
chapters: { title: string; knowledge_points: string[] }[],
|
|
) {
|
|
const res = await apiFetch(
|
|
apiUrl(
|
|
`/api/v1/learning/progress/${encodeURIComponent(bookId)}/import-from-book`,
|
|
),
|
|
{
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ chapters }),
|
|
},
|
|
);
|
|
if (!res.ok) throw new Error(`Failed to import from book: ${res.status}`);
|
|
return res.json();
|
|
}
|
|
|
|
export async function generateModulesFromNotebook(
|
|
bookId: string,
|
|
notebookId: string,
|
|
records: { id: string; type: string; title: string; output: string }[],
|
|
): Promise<{ modules: ModuleInit[] }> {
|
|
const res = await apiFetch(
|
|
apiUrl(
|
|
`/api/v1/learning/progress/${encodeURIComponent(bookId)}/generate-from-notebook`,
|
|
),
|
|
{
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ notebook_id: notebookId, records }),
|
|
},
|
|
);
|
|
if (!res.ok)
|
|
throw new Error(`Failed to generate modules from notebook: ${res.status}`);
|
|
return res.json();
|
|
}
|