update
This commit is contained in:
@@ -3079,7 +3079,7 @@ async def _reset_db_from_phase(topic: str, label: str) -> None:
|
||||
await db.delete_pipeline_state(topic, ["Source prep"])
|
||||
|
||||
|
||||
async def generate_blocks(topic: str, instructions: str = "", provider: str = DEFAULT_PROVIDER, ab_phase: int | None = None, ab_step: int | None = None) -> None:
|
||||
async def generate_blocks(topic: str, instructions: str = "", provider: str = DEFAULT_PROVIDER, ab_phase: int | None = None, ab_step: int | None = None, to_step: int | None = None) -> None:
|
||||
if topic in _blocks_progress:
|
||||
return
|
||||
_blocks_progress[topic] = "Waiting…"
|
||||
@@ -3102,6 +3102,10 @@ async def generate_blocks(topic: str, instructions: str = "", provider: str = DE
|
||||
def aborted() -> None:
|
||||
_blocks_errors[topic] = "Cancelled — progress is preserved"
|
||||
|
||||
_step_list = _blocks_steps(topic)
|
||||
def _past_limit(step: str) -> bool: # optional end limit: stop before any step past to_step
|
||||
return to_step is not None and step in _step_list and _step_list.index(step) > to_step
|
||||
|
||||
ctx = GenContext(topic=topic, provider=provider, is_cancelled=is_cancelled)
|
||||
|
||||
try:
|
||||
@@ -3143,14 +3147,19 @@ async def generate_blocks(topic: str, instructions: str = "", provider: str = DE
|
||||
await db.delete_sub_artefakte(topic)
|
||||
|
||||
# Inventory (DB): research loop → consolidation → clarification.
|
||||
if _past_limit("Research"): return
|
||||
if not await _stage(_research_batch(ctx, set_p, files, q, folder, instructions)):
|
||||
return
|
||||
if _past_limit("Consolidation"): return
|
||||
if not await _stage(_consolidate(ctx, set_p, files)):
|
||||
return
|
||||
if _past_limit("Clarification"): return
|
||||
if not await _stage(_clarify_inventory(ctx, set_p, files)):
|
||||
return
|
||||
if _past_limit("Dedup"): return
|
||||
if not await _stage(_dedup_inventory(ctx, set_p, files)):
|
||||
return
|
||||
if _past_limit("Blocks-Filter"): return
|
||||
if not await _stage(_filter_inventory(ctx, set_p, files)):
|
||||
return
|
||||
consensus_rows = await db.list_blocks(topic, status="consensus")
|
||||
@@ -3161,7 +3170,7 @@ async def generate_blocks(topic: str, instructions: str = "", provider: str = DE
|
||||
|
||||
# Projects only: subject-field supplement — script/project is an excerpt,
|
||||
# a web agent adds canonically missing blocks, marked with [Supplement].
|
||||
if q["type"] == "projekt":
|
||||
if q["type"] == "projekt" and not _past_limit("Supplement"):
|
||||
set_p("Supplementing subject field…", step=_step_idx(topic, "Supplement"))
|
||||
supp_path = files["ergaenzung"]
|
||||
supplements = _supplement_schema(_json_file(supp_path))
|
||||
@@ -3196,6 +3205,7 @@ async def generate_blocks(topic: str, instructions: str = "", provider: str = DE
|
||||
# Make titles unique and write the unsorted inventory
|
||||
entries = _unique_title(entries)
|
||||
atomic_write_text(final_path, "\n".join(f"{i}. {t}" for i, t in entries.items()) + "\n")
|
||||
if _past_limit("Subblocks find"): return # end limit inside the inventory → stop with blocks.md written
|
||||
|
||||
# Block B + C: subblocks per block + levels → sidecar subblocks.json.
|
||||
# Non-destructive: blocks.md already exists; if the sidecar is missing, only
|
||||
@@ -3210,6 +3220,7 @@ async def generate_blocks(topic: str, instructions: str = "", provider: str = DE
|
||||
if raw is None:
|
||||
return # error is set
|
||||
atomic_write_json(files["sub_roh"], raw, indent=1)
|
||||
if _past_limit("Facts find"): return # end limit after subblocks
|
||||
# Facts per sub (BEFORE the level): extract + verify source facts → facts.json.
|
||||
# Extract-once grounding — level/relevance/questions/guide feed on it.
|
||||
if not _facts_complete(files):
|
||||
@@ -3229,6 +3240,7 @@ async def generate_blocks(topic: str, instructions: str = "", provider: str = DE
|
||||
raw = {bt: subs for bt, subs in raw.items() if subs} # drop empty blocks (_sub_roh_schema requires ≥1)
|
||||
atomic_write_json(files["sub_roh"], raw, indent=1)
|
||||
atomic_write_json(files["facts"], facts_map, indent=1)
|
||||
if _past_limit("Levels find"): return # end limit after facts (sidecar not yet valid → no DB mirror)
|
||||
sidecar = await _levels_block(ctx, set_p, files, raw, instructions)
|
||||
if is_cancelled():
|
||||
aborted()
|
||||
@@ -3249,7 +3261,7 @@ async def generate_blocks(topic: str, instructions: str = "", provider: str = DE
|
||||
# Own phase after the levels; drives the ProGuide format (all blocks
|
||||
# with ≥1 relevant subblock) and filters peripheral subs out of the guides.
|
||||
sidecar = _json_file(files["sidecar"])
|
||||
if _sidecar_schema(sidecar) is not None and not _relevance_complete(sidecar):
|
||||
if not _past_limit("Relevance find") and _sidecar_schema(sidecar) is not None and not _relevance_complete(sidecar):
|
||||
relevance_by_id = await _relevance_block(ctx, set_p, files, sidecar, instructions)
|
||||
if is_cancelled():
|
||||
aborted()
|
||||
@@ -3265,7 +3277,7 @@ async def generate_blocks(topic: str, instructions: str = "", provider: str = DE
|
||||
|
||||
# Block D.5: outline (blocks artifact) — chapter structure over ALL blocks,
|
||||
# only read by the guide. Format-agnostic; the guide filters per format.
|
||||
if not _outline_complete(files):
|
||||
if not _past_limit("Outline") and not _outline_complete(files):
|
||||
await _outline_block(ctx, set_p, files, entries, instructions)
|
||||
if is_cancelled():
|
||||
aborted()
|
||||
@@ -3275,7 +3287,7 @@ async def generate_blocks(topic: str, instructions: str = "", provider: str = DE
|
||||
# At exam time each agent draws a pattern without replacement and formulates
|
||||
# a question from it — distinct seeding prevents the duplicate questions of live generation.
|
||||
sidecar = _json_file(files["sidecar"])
|
||||
if _sidecar_schema(sidecar) is not None and _relevance_complete(sidecar) and not _question_pattern_complete(topic):
|
||||
if not _past_limit("Questions find") and _sidecar_schema(sidecar) is not None and _relevance_complete(sidecar) and not _question_pattern_complete(topic):
|
||||
pattern = await _question_pattern_block(ctx, set_p, files, sidecar, instructions)
|
||||
if is_cancelled():
|
||||
aborted()
|
||||
@@ -3287,7 +3299,7 @@ async def generate_blocks(topic: str, instructions: str = "", provider: str = DE
|
||||
# Block F: learning artefacts (flashcards/examples) from the facts — bonus,
|
||||
# presented by the frontend. Does not abort the run (artefacts are optional).
|
||||
sidecar = _json_file(files["sidecar"])
|
||||
if _sidecar_schema(sidecar) is not None and not _artefacts_complete(files):
|
||||
if not _past_limit("Flashcards") and _sidecar_schema(sidecar) is not None and not _artefacts_complete(files):
|
||||
artefacts = await _artefacts_block(ctx, set_p, files, sidecar, instructions)
|
||||
if is_cancelled():
|
||||
aborted()
|
||||
|
||||
@@ -32,6 +32,7 @@ class BlocksCreateRequest(BaseModel):
|
||||
source_location: str = Field(default="", max_length=2000)
|
||||
ab_phase: int | None = Field(default=None, ge=1, le=9) # re-run from a coarse phase (position in _phasen(topic), 1-based; up to 9: …outline/questions/artifacts); None = resume/continue without deleting
|
||||
ab_step: int | None = Field(default=None, ge=0) # re-run from a fine sub-step (0-based index into _blocks_steps); takes precedence over ab_phase
|
||||
to_step: int | None = Field(default=None, ge=0) # stop AFTER this fine sub-step (0-based index into _blocks_steps); None = run to the end
|
||||
|
||||
|
||||
class BlocksResetStepRequest(BaseModel):
|
||||
|
||||
@@ -164,7 +164,7 @@ async def create_blocks(req: BlocksCreateRequest):
|
||||
raise HTTPException(400, "Link must start with http:// or https://.")
|
||||
qp.parent.mkdir(parents=True, exist_ok=True)
|
||||
atomic_write_json(qp, {"type": type, "location": location, "spec": req.instructions.strip()})
|
||||
asyncio.create_task(generate_blocks(topic, req.instructions.strip(), req.provider, ab_phase=req.ab_phase, ab_step=req.ab_step))
|
||||
asyncio.create_task(generate_blocks(topic, req.instructions.strip(), req.provider, ab_phase=req.ab_phase, ab_step=req.ab_step, to_step=req.to_step))
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user