{% if designations is undefined %}{% set designations = speaker_designations(request) %}{% endif %} {{ speaker.primary_name }} {% set _desig = designations.get(speaker.primary_name) %} {% if _desig %} {% if _desig.status == 'clear' %} {% if _desig.reviewed %} {# A person approved this speaker. Do not label it auto-accepted - that claim is false here, and it is what made an approved row look like it had simply been dropped from the worklist. #} ✓ reviewed {% else %} ✓ clear {% endif %} {% else %} ⚠ needs check {% endif %} {% endif %} {% if speaker.flagged %} thin profile {% endif %} {% if speaker.sample_dialogue %}
"{{ speaker.sample_dialogue[:80] }}{% if speaker.sample_dialogue|length > 80 %}...{% endif %}" {% endif %} {% if speaker.description %}
{{ speaker.description[:100] }}{% if speaker.description|length > 100 %}...{% endif %} {% endif %} {% for alias in speaker.aliases %} {{ alias }} {% endfor %}
{{ speaker.demographics.type if speaker.demographics else 'Unknown' }} / {{ speaker.demographics.gender if speaker.demographics else '??' }} {% if speaker.get('accent') and speaker.accent != 'none' %} {{ speaker.accent }} {% endif %} {% for trait in speaker.vocal_traits %} {{ trait }} {% endfor %} {% for eff in speaker.get('distortion_effects', []) %} {{ eff }} {% endfor %} {% set ref_name = speaker.primary_name|lower|replace(' ', '_') %} {% set ref_file = ref_name ~ '_ref.wav' %}
{% if speaker.has_voice_ref %} {% else %} No sample {% endif %}
{% if speaker.engine_fallback %} ⚠ Edge-TTS fallback not the Qwen3 voice — regenerate {% elif speaker.voice_engine == 'qwen' and speaker.has_voice_ref %} Qwen3-TTS ✓ {% endif %} {% if speaker.voice_status == 'approved' %} Approved ✓ saved to registry {% elif speaker.voice_status == 'rejected' %} Rejected ✗ {% elif speaker.has_voice_ref %} Pending {% else %} {% endif %}
{% if speaker.is_narrator %} Narrator {% elif speaker.is_group %} Group {% endif %} {# Queue state for this speaker. Rendered empty on load, then filled by refreshVoiceQueue(); the id is what the poller updates in place. #} {# Not hx-delete: htmx will not swap a 409, and this has to be able to answer "this speaker has 12 utterances - where do they go?". The handler also re-renders the whole list, because deleting renumbers every speaker after it. #}