fix(protected-phrases): isolate phrase generation per book
Run full-book candidate generation inside worker-owned sessions so each book commits independently during backfills. Abort recalculation when a book has no indexed chapters to preserve existing phrase data, and update admin/UI tests for the new generation flow.
This commit is contained in:
@@ -61,50 +61,20 @@ async def scan_library(request: Request, config: AppConfig, session: AsyncDbSess
|
||||
|
||||
|
||||
@router.post("/phrases/generate-all", response_class=HTMLResponse)
|
||||
async def generate_all_phrases(request: Request, config: AppConfig, session: AsyncDbSession) -> HTMLResponse:
|
||||
async def generate_all_phrases(request: Request, config: AppConfig, engine: AppEngine) -> HTMLResponse:
|
||||
"""Regenerate candidate phrases for every indexed book without LLM judging."""
|
||||
return await run_phrase_generation(request, config, session)
|
||||
|
||||
|
||||
async def run_phrase_generation(
|
||||
request: Request,
|
||||
config: AppConfig,
|
||||
session: AsyncDbSession,
|
||||
*,
|
||||
only_missing: bool,
|
||||
) -> HTMLResponse:
|
||||
"""Run candidate phrase generation and render the outcome as an admin status partial.
|
||||
|
||||
Args:
|
||||
request (Request): Current request, for template rendering.
|
||||
config (AppConfig): Runtime phrase-tuning settings.
|
||||
session (AsyncDbSession): Active database session.
|
||||
only_missing (bool): Only generate for books without candidates instead of every book.
|
||||
|
||||
Returns:
|
||||
HTMLResponse: Status partial describing the generation outcome.
|
||||
"""
|
||||
try:
|
||||
result = await generate_candidate_phrases_for_books(session, config, only_missing=only_missing)
|
||||
await session.commit()
|
||||
result = await generate_candidate_phrases_for_books(engine, config)
|
||||
except Exception as error:
|
||||
await session.rollback()
|
||||
logger.exception("ebook_admin_generate_phrases_failed only_missing=%s", only_missing)
|
||||
logger.exception("ebook_admin_generate_phrases_failed")
|
||||
return templates.TemplateResponse(request, "partials/error.html", {"message": str(error)}, status_code=500)
|
||||
|
||||
logger.info(
|
||||
"ebook_admin_generate_phrases_complete only_missing=%s books_seen=%s books_built=%s candidates=%s",
|
||||
only_missing,
|
||||
"ebook_admin_generate_phrases_complete books_seen=%s books_built=%s candidates=%s",
|
||||
result.books_seen,
|
||||
result.books_built,
|
||||
result.candidate_phrases,
|
||||
)
|
||||
if only_missing and result.books_seen == 0:
|
||||
return templates.TemplateResponse(
|
||||
request,
|
||||
"partials/admin_status.html",
|
||||
{"message": "All books already have candidate phrases"},
|
||||
)
|
||||
return templates.TemplateResponse(
|
||||
request,
|
||||
"partials/admin_status.html",
|
||||
|
||||
Reference in New Issue
Block a user