22cdf0f334
Switch every prediction READER off the JSON column onto the normalized
image_prediction table. Parity by construction: each reader loads the same
{raw_name: {category, confidence}} dict it consumed before (via small
_load_predictions helpers), so all downstream threshold/alias/merge/consensus
logic is byte-identical — only the data source changed.
- suggestions.SuggestionService.for_image (and for_selection via it)
- ml.apply_allowlist_tags (iterates images that have prediction rows)
- importer re-import reset deletes the image's prediction rows
The tagger_predictions JSON column is still dual-written (step 1) so it stays
valid during transition; the backfill task's NULL check still works. Removing
the JSON write + DROP column + retiring the #764 prune is the cleanup
follow-up (needs a quiesced-worker window for the DROP lock).
Tests: shared tests/_prediction_helpers.seed_predictions seeds the table;
read-path tests (suggestions, bulk consensus, allowlist apply, API) seed there
instead of ImageRecord.tagger_predictions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
22 lines
796 B
Python
22 lines
796 B
Python
"""#768 test helper: seed image_prediction rows.
|
|
|
|
Read-path tests used to seed ImageRecord(tagger_predictions={...}); predictions
|
|
now live in the normalized image_prediction table, so seed there instead.
|
|
"""
|
|
from backend.app.models import ImagePrediction
|
|
|
|
|
|
async def seed_predictions(session, image_id: int, predictions: dict) -> None:
|
|
"""Insert image_prediction rows from a {raw_name: {category, confidence}}
|
|
dict (the old JSON shape). Caller commits/flushes as needed; this flushes."""
|
|
session.add_all([
|
|
ImagePrediction(
|
|
image_record_id=image_id,
|
|
raw_name=name,
|
|
category=p.get("category", "general"),
|
|
score=float(p.get("confidence", 0.0)),
|
|
)
|
|
for name, p in predictions.items()
|
|
])
|
|
await session.flush()
|