Implement workspace history reconciliation
This commit is contained in:
@@ -2753,7 +2753,11 @@ def _panel_context(
|
||||
),
|
||||
"compose_answer_suggestion_send_url": reverse("compose_answer_suggestion_send"),
|
||||
"compose_ws_url": ws_url,
|
||||
"tasks_hub_url": reverse("tasks_hub"),
|
||||
"tasks_hub_url": (
|
||||
f"{reverse('tasks_hub')}?{urlencode({'person': str(base['person'].id), 'service': base['service'], 'identifier': base['identifier'] or ''})}"
|
||||
if base["person"]
|
||||
else reverse("tasks_hub")
|
||||
),
|
||||
"tasks_group_url": reverse(
|
||||
"tasks_group",
|
||||
kwargs={
|
||||
|
||||
@@ -39,6 +39,7 @@ from core.models import (
|
||||
WorkspaceConversation,
|
||||
WorkspaceMetricSnapshot,
|
||||
)
|
||||
from core.workspace import DENSITY_POINT_CAPS, downsample_points
|
||||
|
||||
SEND_ENABLED_MODES = {"active", "instant"}
|
||||
OPERATION_LABELS = {
|
||||
@@ -960,21 +961,28 @@ def _metric_psychological_read(metric_slug, conversation):
|
||||
return ""
|
||||
|
||||
|
||||
def _history_points(conversation, field_name):
|
||||
def _history_points(conversation, field_name, density="medium"):
|
||||
rows = (
|
||||
conversation.metric_snapshots.exclude(**{f"{field_name}__isnull": True})
|
||||
.order_by("computed_at")
|
||||
.values("computed_at", field_name)
|
||||
.values("computed_at", "source_event_ts", field_name)
|
||||
)
|
||||
points = []
|
||||
raw_points = []
|
||||
for row in rows:
|
||||
points.append(
|
||||
source_ts = int(row.get("source_event_ts") or 0)
|
||||
if source_ts > 0:
|
||||
x_value = datetime.fromtimestamp(source_ts / 1000, tz=timezone.utc).isoformat()
|
||||
else:
|
||||
x_value = row["computed_at"].isoformat()
|
||||
raw_points.append(
|
||||
{
|
||||
"x": row["computed_at"].isoformat(),
|
||||
"x": x_value,
|
||||
"y": row[field_name],
|
||||
"ts_ms": source_ts,
|
||||
"computed_at": row.get("computed_at"),
|
||||
}
|
||||
)
|
||||
return points
|
||||
return downsample_points(raw_points, density=density)
|
||||
|
||||
|
||||
def _metric_supports_history(metric_slug, metric_spec):
|
||||
@@ -983,10 +991,15 @@ def _metric_supports_history(metric_slug, metric_spec):
|
||||
return any(graph["slug"] == metric_slug for graph in INSIGHT_GRAPH_SPECS)
|
||||
|
||||
|
||||
def _all_graph_payload(conversation):
|
||||
def _all_graph_payload(conversation, density="medium"):
|
||||
graphs = []
|
||||
for spec in INSIGHT_GRAPH_SPECS:
|
||||
points = _history_points(conversation, spec["field"])
|
||||
raw_count = (
|
||||
conversation.metric_snapshots.exclude(
|
||||
**{f"{spec['field']}__isnull": True}
|
||||
).count()
|
||||
)
|
||||
points = _history_points(conversation, spec["field"], density=density)
|
||||
graphs.append(
|
||||
{
|
||||
"slug": spec["slug"],
|
||||
@@ -995,6 +1008,7 @@ def _all_graph_payload(conversation):
|
||||
"group_title": INSIGHT_GROUPS[spec["group"]]["title"],
|
||||
"points": points,
|
||||
"count": len(points),
|
||||
"raw_count": raw_count,
|
||||
"y_min": spec["y_min"],
|
||||
"y_max": spec["y_max"],
|
||||
}
|
||||
@@ -1002,6 +1016,13 @@ def _all_graph_payload(conversation):
|
||||
return graphs
|
||||
|
||||
|
||||
def _sanitize_graph_density(value: str) -> str:
|
||||
density = str(value or "").strip().lower()
|
||||
if density in DENSITY_POINT_CAPS:
|
||||
return density
|
||||
return "medium"
|
||||
|
||||
|
||||
def _information_overview_rows(conversation):
|
||||
latest_snapshot = conversation.metric_snapshots.first()
|
||||
rows = []
|
||||
@@ -3668,9 +3689,12 @@ class AIWorkspaceInsightDetail(LoginRequiredMixin, View):
|
||||
value = _format_metric_value(conversation, metric, latest_snapshot)
|
||||
group = INSIGHT_GROUPS[spec["group"]]
|
||||
graph_applicable = _metric_supports_history(metric, spec)
|
||||
graph_density = _sanitize_graph_density(request.GET.get("density"))
|
||||
points = []
|
||||
if graph_applicable:
|
||||
points = _history_points(conversation, spec["history_field"])
|
||||
points = _history_points(
|
||||
conversation, spec["history_field"], density=graph_density
|
||||
)
|
||||
|
||||
context = {
|
||||
"person": person,
|
||||
@@ -3682,6 +3706,8 @@ class AIWorkspaceInsightDetail(LoginRequiredMixin, View):
|
||||
"metric_group": group,
|
||||
"graph_points": points,
|
||||
"graph_applicable": graph_applicable,
|
||||
"graph_density": graph_density,
|
||||
"graph_density_caps": DENSITY_POINT_CAPS,
|
||||
**_workspace_nav_urls(person),
|
||||
}
|
||||
return render(request, "pages/ai-workspace-insight-detail.html", context)
|
||||
@@ -3696,11 +3722,14 @@ class AIWorkspaceInsightGraphs(LoginRequiredMixin, View):
|
||||
|
||||
person = get_object_or_404(Person, pk=person_id, user=request.user)
|
||||
conversation = _conversation_for_person(request.user, person)
|
||||
graph_cards = _all_graph_payload(conversation)
|
||||
graph_density = _sanitize_graph_density(request.GET.get("density"))
|
||||
graph_cards = _all_graph_payload(conversation, density=graph_density)
|
||||
context = {
|
||||
"person": person,
|
||||
"workspace_conversation": conversation,
|
||||
"graph_cards": graph_cards,
|
||||
"graph_density": graph_density,
|
||||
"graph_density_caps": DENSITY_POINT_CAPS,
|
||||
**_workspace_nav_urls(person),
|
||||
}
|
||||
return render(request, "pages/ai-workspace-insight-graphs.html", context)
|
||||
@@ -3717,9 +3746,10 @@ class AIWorkspaceInformation(LoginRequiredMixin, View):
|
||||
conversation = _conversation_for_person(request.user, person)
|
||||
latest_snapshot = conversation.metric_snapshots.first()
|
||||
directionality = _commitment_directionality_payload(conversation)
|
||||
graph_density = _sanitize_graph_density(request.GET.get("density"))
|
||||
commitment_graph_cards = [
|
||||
card
|
||||
for card in _all_graph_payload(conversation)
|
||||
for card in _all_graph_payload(conversation, density=graph_density)
|
||||
if card["group"] == "commitment"
|
||||
]
|
||||
|
||||
@@ -3743,6 +3773,7 @@ class AIWorkspaceInformation(LoginRequiredMixin, View):
|
||||
"directionality": directionality,
|
||||
"overview_rows": _information_overview_rows(conversation),
|
||||
"commitment_graph_cards": commitment_graph_cards,
|
||||
"graph_density": graph_density,
|
||||
**_workspace_nav_urls(person),
|
||||
}
|
||||
return render(request, "pages/ai-workspace-information.html", context)
|
||||
|
||||
Reference in New Issue
Block a user