refactor(ocr-training): route SenderModelService and OcrTrainingService through TranscriptionBlockQueryService

Both services injected TranscriptionBlockRepository directly to read block
counts. They now go through TranscriptionBlockQueryService (count() and
countManualKurrentBlocksByPerson() added as 1-line delegations) — chosen over
TranscriptionService to avoid the existing
SenderModelService → TrainingDataExportService → TranscriptionBlockQueryService
chain reaching back into TranscriptionService and creating a cycle.

Refs #417 (C6.2 violations #8 and #9).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-05 07:40:34 +02:00
parent 310bb5b2d5
commit f5151f3949
5 changed files with 38 additions and 34 deletions

View File

@@ -10,7 +10,6 @@ import org.raddatz.familienarchiv.model.OcrTrainingRun;
import org.raddatz.familienarchiv.model.SenderModel;
import org.raddatz.familienarchiv.model.TrainingStatus;
import org.raddatz.familienarchiv.repository.OcrTrainingRunRepository;
import org.raddatz.familienarchiv.repository.TranscriptionBlockRepository;
import org.slf4j.MDC;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
@@ -37,7 +36,7 @@ public class OcrTrainingService {
private final SegmentationTrainingExportService segmentationTrainingExportService;
private final OcrClient ocrClient;
private final OcrHealthClient ocrHealthClient;
private final TranscriptionBlockRepository blockRepository;
private final TranscriptionBlockQueryService transcriptionBlockQueryService;
private final TransactionTemplate txTemplate;
private final PersonService personService;
private final SenderModelService senderModelService;
@@ -189,7 +188,7 @@ public class OcrTrainingService {
.distinct()
.count();
int totalOcrBlocks = (int) blockRepository.count();
int totalOcrBlocks = (int) transcriptionBlockQueryService.count();
int availableSegBlocks = segmentationTrainingExportService.querySegmentationBlocks().size();
List<OcrTrainingRun> recentRuns = trainingRunRepository.findTop20ByOrderByCreatedAtDesc();

View File

@@ -9,7 +9,6 @@ import org.raddatz.familienarchiv.model.SenderModel;
import org.raddatz.familienarchiv.model.TrainingStatus;
import org.raddatz.familienarchiv.repository.OcrTrainingRunRepository;
import org.raddatz.familienarchiv.repository.SenderModelRepository;
import org.raddatz.familienarchiv.repository.TranscriptionBlockRepository;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -32,7 +31,7 @@ import java.util.UUID;
public class SenderModelService {
private final SenderModelRepository senderModelRepository;
private final TranscriptionBlockRepository blockRepository;
private final TranscriptionBlockQueryService transcriptionBlockQueryService;
private final OcrTrainingRunRepository trainingRunRepository;
private final OcrClient ocrClient;
private final TransactionTemplate txTemplate;
@@ -62,7 +61,7 @@ public class SenderModelService {
public OcrTrainingRun triggerManualSenderTraining(UUID personId) {
personService.getById(personId);
long correctedLines = blockRepository.countManualKurrentBlocksByPerson(personId);
long correctedLines = transcriptionBlockQueryService.countManualKurrentBlocksByPerson(personId);
boolean runNow = runOrQueueSenderTraining(personId, (int) correctedLines);
TrainingStatus targetStatus = runNow ? TrainingStatus.RUNNING : TrainingStatus.QUEUED;
OcrTrainingRun run = trainingRunRepository.findFirstByPersonIdAndStatus(personId, targetStatus)
@@ -77,7 +76,7 @@ public class SenderModelService {
@Async
public void runSenderTraining(UUID personId) {
long correctedLines = blockRepository.countManualKurrentBlocksByPerson(personId);
long correctedLines = transcriptionBlockQueryService.countManualKurrentBlocksByPerson(personId);
triggerSenderTraining(personId, (int) correctedLines);
}
@@ -87,7 +86,7 @@ public class SenderModelService {
*/
@Async
public void checkAndTriggerTraining(UUID personId) {
long correctedLines = blockRepository.countManualKurrentBlocksByPerson(personId);
long correctedLines = transcriptionBlockQueryService.countManualKurrentBlocksByPerson(personId);
Optional<SenderModel> existing = senderModelRepository.findByPersonId(personId);
boolean shouldActivate = existing.isEmpty() && correctedLines >= activationThreshold;
@@ -121,7 +120,7 @@ public class SenderModelService {
}
if (trainingRunRepository.findFirstByStatus(TrainingStatus.RUNNING).isPresent()) {
int blockCount = (int) blockRepository.countManualKurrentBlocksByPerson(personId);
int blockCount = (int) transcriptionBlockQueryService.countManualKurrentBlocksByPerson(personId);
trainingRunRepository.save(OcrTrainingRun.builder()
.status(TrainingStatus.QUEUED)
.personId(personId)
@@ -133,7 +132,7 @@ public class SenderModelService {
return false;
}
long blockCount = blockRepository.countManualKurrentBlocksByPerson(personId);
long blockCount = transcriptionBlockQueryService.countManualKurrentBlocksByPerson(personId);
trainingRunRepository.save(OcrTrainingRun.builder()
.status(TrainingStatus.RUNNING)
.personId(personId)
@@ -227,7 +226,7 @@ public class SenderModelService {
if (queuedOpt != null && queuedOpt.isPresent()) {
OcrTrainingRun promoted = queuedOpt.get();
log.info("Promoting queued sender training run {} for person {}", promoted.getId(), promoted.getPersonId());
long freshCount = blockRepository.countManualKurrentBlocksByPerson(promoted.getPersonId());
long freshCount = transcriptionBlockQueryService.countManualKurrentBlocksByPerson(promoted.getPersonId());
triggerSenderTraining(promoted.getPersonId(), (int) freshCount);
}
}

View File

@@ -37,4 +37,12 @@ public class TranscriptionBlockQueryService {
public List<TranscriptionBlock> findManualKurrentBlocksByPerson(UUID personId) {
return blockRepository.findManualKurrentBlocksByPerson(personId);
}
public long countManualKurrentBlocksByPerson(UUID personId) {
return blockRepository.countManualKurrentBlocksByPerson(personId);
}
public long count() {
return blockRepository.count();
}
}