{# Insights section fragment for htmx polling (#383). Rendered by the insights-poll endpoint; replaces itself via hx-swap. poll_remaining controls bounded retry: >0 re-polls after a delay, 0 shows a manual check button, absent means static (no poll attrs). #}
{% if insights %}

INSIGHTS

{% if insights.distinctive_terms %}

DISTINCTIVE VOCABULARY

Based on {{ "{:,}".format(insights.speaker_token_count) }} words across {{ insights.recording_count }} recording{{ "s" if insights.recording_count != 1 else "" }}

{%- set max_z = insights.distinctive_terms[0].z_score if insights.distinctive_terms and insights.distinctive_terms[0].z_score else 1 -%} {% for t in insights.distinctive_terms[:20] %} {{ t.term }} {{ t.count }} {% endfor %}
{% endif %} {% if insights.ego_transitions_in or insights.ego_transitions_out %}

CONVERSATION PARTNERS

{% if insights.ego_transitions_in %}

SPEAKS BEFORE {{ speaker.display_name|upper }}

{% for edge in insights.ego_transitions_in[:8] %}
{{ edge.speaker_name or "Unknown" }} {{ edge.count }}
{% endfor %}
{% endif %} {% if insights.ego_transitions_out %}

{{ speaker.display_name|upper }} SPEAKS BEFORE

{% for edge in insights.ego_transitions_out[:8] %}
{{ edge.speaker_name or "Unknown" }} {{ edge.count }}
{% endfor %}
{% endif %}
{% endif %} {% if insights.wpm is not none %}

SPEAKING PACE

{{ insights.wpm|round|int }} words/min
{% if insights.wpm_timed_segments < insights.wpm_total_segments %}

Based on {{ insights.wpm_timed_segments }} of {{ insights.wpm_total_segments }} segments with word-level timing

{% endif %}
{% endif %}

All quotes by {{ speaker.display_name }} in Explore →

{% elif insights_eligible and poll_remaining is defined and poll_remaining > 0 %}

INSIGHTS

Computing speaker insights...

{% elif insights_eligible %}

INSIGHTS

Speaker insights are still computing.

Check now
{% elif not insights_eligible and aggregate.files > 0 %}

INSIGHTS

Not enough data for speaker insights. This speaker needs at least 2 recordings with substantial speech.

{% endif %}