From 63af5d234e30325779a2249ea5eec53faa40d914 Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Sun, 15 Feb 2026 20:08:02 +0000 Subject: [PATCH] Further improve detail display and work on inline latency display --- core/realtime/compose_ws.py | 79 ++-- core/templates/base.html | 62 +-- .../mixins/window-content/persona-form.html | 165 ++++++++ .../pages/ai-workspace-information.html | 21 +- .../pages/ai-workspace-insight-detail.html | 15 +- .../pages/ai-workspace-insight-graphs.html | 11 +- .../pages/ai-workspace-insight-help.html | 11 +- core/templates/partials/ai-insight-nav.html | 20 + .../partials/ai-workspace-ai-result.html | 22 +- .../ai-workspace-mitigation-panel.html | 29 +- .../partials/ai-workspace-person-widget.html | 195 ++++++++-- core/templates/partials/compose-panel.html | 269 ++++++++++++- core/templates/partials/osint/list-table.html | 132 ++++++- core/views/compose.py | 367 +++++++++++++++++- core/views/osint.py | 1 + core/views/personas.py | 2 + core/views/workspace.py | 61 ++- 17 files changed, 1223 insertions(+), 239 deletions(-) create mode 100644 core/templates/mixins/window-content/persona-form.html create mode 100644 core/templates/partials/ai-insight-nav.html diff --git a/core/realtime/compose_ws.py b/core/realtime/compose_ws.py index 860f7d2..0e1b4ee 100644 --- a/core/realtime/compose_ws.py +++ b/core/realtime/compose_ws.py @@ -1,19 +1,16 @@ import asyncio import json import time -from datetime import datetime, timezone as dt_timezone from urllib.parse import parse_qs from asgiref.sync import sync_to_async from django.core import signing -from core.models import ChatSession, Message, PersonIdentifier +from core.models import ChatSession, Message, PersonIdentifier, WorkspaceConversation from core.realtime.typing_state import get_person_typing_state from core.views.compose import ( COMPOSE_WS_TOKEN_SALT, - _image_urls_from_text, - _is_url_only_text, - _looks_like_image_url, + _serialize_messages_with_artifacts, ) @@ -24,39 +21,6 @@ def _safe_int(value, default=0): return default -def _fmt_ts(ts_value): - try: - dt = datetime.fromtimestamp(int(ts_value) / 1000, tz=dt_timezone.utc) - return dt.strftime("%H:%M") - except Exception: - return str(ts_value or "") - - -def _serialize_message(msg): - author = str(msg.custom_author or "").strip() - text_value = str(msg.text or "") - image_urls = _image_urls_from_text(text_value) - image_url = image_urls[0] if image_urls else "" - hide_text = bool( - image_urls - and _is_url_only_text(text_value) - and all(_looks_like_image_url(url) for url in image_urls) - ) - display_text = text_value if text_value.strip() else ("(no text)" if not image_url else "") - return { - "id": str(msg.id), - "ts": int(msg.ts or 0), - "display_ts": _fmt_ts(msg.ts), - "text": text_value, - "display_text": display_text, - "image_url": image_url, - "image_urls": image_urls, - "hide_text": hide_text, - "author": author, - "outgoing": author.upper() in {"USER", "BOT"}, - } - - def _load_since(user_id, service, identifier, person_id, after_ts, limit): person_identifier = None if person_id: @@ -91,11 +55,18 @@ def _load_since(user_id, service, identifier, person_id, after_ts, limit): "person_id": int(person_identifier.person_id), } - qs = Message.objects.filter( - user_id=user_id, - session=session, - ).order_by("ts") + qs = Message.objects.filter(user_id=user_id, session=session).order_by("ts") + seed_previous = None if after_ts > 0: + seed_previous = ( + Message.objects.filter( + user_id=user_id, + session=session, + ts__lte=after_ts, + ) + .order_by("-ts") + .first() + ) qs = qs.filter(ts__gt=after_ts) rows = list(qs[: max(10, min(limit, 200))]) @@ -105,8 +76,30 @@ def _load_since(user_id, service, identifier, person_id, after_ts, limit): .values_list("ts", flat=True) .first() ) + + conversation = ( + WorkspaceConversation.objects.filter( + user_id=user_id, + participants__id=person_identifier.person_id, + ) + .order_by("-last_event_ts", "-created_at") + .first() + ) + counterpart_identifiers = { + str(value or "").strip() + for value in PersonIdentifier.objects.filter( + user_id=user_id, + person_id=person_identifier.person_id, + ).values_list("identifier", flat=True) + if str(value or "").strip() + } return { - "messages": [_serialize_message(row) for row in rows], + "messages": _serialize_messages_with_artifacts( + rows, + counterpart_identifiers=counterpart_identifiers, + conversation=conversation, + seed_previous=seed_previous, + ), "last_ts": int(newest or after_ts or 0), "person_id": int(person_identifier.person_id), } diff --git a/core/templates/base.html b/core/templates/base.html index 6bc8ade..d3860a1 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -296,24 +296,6 @@ Queue - - + {% endif %} + + Install + + + +