feat: add curriculum management admin dashboard with AI generation and draft approval workflows
This commit is contained in:
@@ -133,6 +133,24 @@ export async function updateSourceStatus(id, status, error = '') {
|
||||
return pb.collection('sources').update(id, { status, error });
|
||||
}
|
||||
|
||||
export async function updateSourceProgress(id, progress) {
|
||||
return pb.collection('sources').update(id, { progress });
|
||||
}
|
||||
|
||||
/**
|
||||
* Find sources stuck in 'processing' status — likely orphaned by a tab close.
|
||||
* Sources older than 5 minutes in 'processing' state are considered stale.
|
||||
*/
|
||||
export async function getOrphanedSources() {
|
||||
try {
|
||||
const all = await pb.collection('sources').getFullList({
|
||||
filter: 'status="processing"',
|
||||
});
|
||||
const fiveMinAgo = Date.now() - 5 * 60 * 1000;
|
||||
return all.filter(s => new Date(s.updated || s.created).getTime() < fiveMinAgo);
|
||||
} catch { return []; }
|
||||
}
|
||||
|
||||
export async function deleteSource(id) {
|
||||
return pb.collection('sources').delete(id);
|
||||
}
|
||||
|
||||
@@ -128,6 +128,9 @@ export async function processSourceText(textContent, sourceName, { signal } = {}
|
||||
const chunks = chunkText(textContent);
|
||||
console.log(`[Pipeline] Split "${sourceName}" into ${chunks.length} chunks for processing.`);
|
||||
|
||||
// Persist initial progress so other sessions/reloads can see it
|
||||
await db.updateSourceProgress(sourceId, { current: 0, total: chunks.length, message: 'Starting extraction...' });
|
||||
|
||||
const existingTopics = await db.getTopics();
|
||||
const knownTopics = existingTopics.map((t) => ({ id: t.id, label: t.label }));
|
||||
|
||||
@@ -138,6 +141,14 @@ export async function processSourceText(textContent, sourceName, { signal } = {}
|
||||
if (signal?.aborted) throw signal.reason ?? new DOMException('Aborted', 'AbortError');
|
||||
|
||||
console.log(`[Pipeline] Processing chunk ${i + 1}/${chunks.length} (${chunks[i].length} chars)...`);
|
||||
|
||||
// Update progress before each chunk
|
||||
await db.updateSourceProgress(sourceId, {
|
||||
current: i,
|
||||
total: chunks.length,
|
||||
message: `Extracting chunk ${i + 1} of ${chunks.length}...`,
|
||||
});
|
||||
|
||||
const hint = buildKnownIdsHint(knownTopics);
|
||||
const result = await callLLM({
|
||||
task: 'extract.source',
|
||||
@@ -168,6 +179,7 @@ export async function processSourceText(textContent, sourceName, { signal } = {}
|
||||
}
|
||||
}
|
||||
|
||||
await db.updateSourceProgress(sourceId, { current: chunks.length, total: chunks.length, message: 'Merging results...' });
|
||||
await mergeKnowledgeGraph(existingTopics, { topics: allExtractedTopics, relations: allExtractedRelations });
|
||||
await db.updateSourceStatus(sourceId, 'completed');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user