feat: add automation activity and employer intelligence

This commit is contained in:
Jens
2026-07-22 20:17:20 +02:00
parent 4fa2a34447
commit afe18e5b96
16 changed files with 679 additions and 18 deletions
+112
View File
@@ -0,0 +1,112 @@
from __future__ import annotations
from datetime import timedelta
from typing import Any
from django.conf import settings
from django.db.models import Count, Q, Sum
from django.utils import timezone
from apps.jobs.models import JobPosting, ScoreRun
from apps.jobs.services.relevance import it_relevance_query
from apps.notifications.models import DigestOutbox, ReminderOutbox
from apps.profiles.models import SearchProfile
from apps.sources.models import Source, SourceRun
from ..health import readiness
def build_automation_cockpit() -> dict[str, Any]:
"""Build an honest operational read model without probing unsafe hidden endpoints."""
since = timezone.now() - timedelta(hours=24)
recent_runs = SourceRun.objects.filter(started_at__gte=since)
run_metrics = recent_runs.aggregate(
discovered=Sum("discovered_count"),
extracted=Sum("extracted_count"),
created=Sum("created_count"),
updated=Sum("updated_count"),
duplicates=Sum("duplicate_count"),
failures=Count("id", filter=Q(status=SourceRun.Status.FAILED)),
)
notification_counts = {
"pending": DigestOutbox.objects.filter(status=DigestOutbox.Status.PENDING).count()
+ ReminderOutbox.objects.filter(status=ReminderOutbox.Status.PENDING).count(),
"failed": DigestOutbox.objects.filter(status=DigestOutbox.Status.FAILED).count()
+ ReminderOutbox.objects.filter(status=ReminderOutbox.Status.FAILED).count(),
"sent_24h": DigestOutbox.objects.filter(
status=DigestOutbox.Status.SENT, sent_at__gte=since
).count()
+ ReminderOutbox.objects.filter(
status=ReminderOutbox.Status.SENT, sent_at__gte=since
).count(),
}
source_total = Source.objects.count()
source_active = Source.objects.filter(status=Source.Status.ACTIVE).count()
active_jobs = JobPosting.objects.filter(status=JobPosting.Status.ACTIVE)
phase_rows = [
{"key": "discover", "label": "Ontdekken", "value": source_total, "unit": "bronnen"},
{"key": "fetch", "label": "Ophalen", "value": recent_runs.count(), "unit": "runs / 24u"},
{
"key": "extract",
"label": "Extraheren",
"value": run_metrics["extracted"] or 0,
"unit": "items",
},
{
"key": "normalize",
"label": "Normaliseren",
"value": (run_metrics["created"] or 0) + (run_metrics["updated"] or 0),
"unit": "records",
},
{
"key": "dedupe",
"label": "Dedupliceren",
"value": run_metrics["duplicates"] or 0,
"unit": "herkend",
},
{
"key": "filter",
"label": "IT-filter",
"value": active_jobs.exclude(it_relevance_query()).count(),
"unit": "uit beeld",
},
{
"key": "analyze",
"label": "Analyseren",
"value": ScoreRun.objects.filter(created_at__gte=since).count(),
"unit": "scores / 24u",
},
{
"key": "notify",
"label": "Notificeren",
"value": notification_counts["sent_24h"],
"unit": "verzonden / 24u",
},
]
return {
"health": readiness(),
"source_total": source_total,
"source_active": source_active,
"run_metrics": run_metrics,
"run_count": recent_runs.count(),
"active_jobs": active_jobs.filter(it_relevance_query()).count(),
"review_jobs": ScoreRun.objects.filter(
recommendation__in=[ScoreRun.Recommendation.STRONG, ScoreRun.Recommendation.POSSIBLE],
job__status=JobPosting.Status.ACTIVE,
).count(),
"notification_counts": notification_counts,
"phase_rows": phase_rows,
"recent_runs": list(
SourceRun.objects.select_related("source").order_by("-started_at")[:10]
),
"source_rows": Source.objects.annotate(run_count=Count("runs")).order_by("name")[:12],
"queue_state": "Eager/lokaal"
if settings.CELERY_TASK_ALWAYS_EAGER
else "Geconfigureerd, worker niet gemeten",
"ai_state": "Geconfigureerd"
if settings.OLLAMA_ENABLED and settings.OLLAMA_MODEL
else "Niet geconfigureerd",
"ai_profiles": SearchProfile.objects.filter(ai_scoring_enabled=True).count(),
"browser_state": "Geen aparte browserextractor geconfigureerd",
}