feat: Group chunks under sections in hierarchical search

- Stage 2 now searches chunks for EACH section using section summary as query
- Chunks distributed across sections (limit / sections_limit)
- Template displays sections with nested chunks underneath
- Each section shows: title, summary, concepts, chunk count, and passages
- Removes separate global passages list - now fully grouped by section

Structure: Section 1 → Chunks 1-3, Section 2 → Chunks 4-6, etc.
This commit is contained in:
2026-01-01 18:25:11 +01:00
parent 65adc02d6e
commit 1cec07b284
2 changed files with 81 additions and 77 deletions

View File

@@ -172,59 +172,64 @@
{% if results_data.results %}
<!-- Hierarchical display -->
<!-- Hierarchical display: sections with grouped chunks -->
{% if results_data.mode == "hierarchical" and results_data.sections %}
<!-- Show relevant sections as context -->
<div style="margin-bottom: 2rem;">
<h3 style="font-size: 1.2em; margin-bottom: 1rem; color: var(--color-accent);">📚 Sections pertinentes trouvées</h3>
<div style="display: flex; flex-direction: column; gap: 1rem;">
{% for section in results_data.sections %}
<div style="padding: 1rem; border-left: 3px solid var(--color-accent); background: rgba(125, 110, 88, 0.05); border-radius: 4px;">
<div style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem;">
<strong>{{ section.title[:80] }}{% if section.title|length > 80 %}...{% endif %}</strong>
<div>
<h3 style="font-size: 1.3em; margin-bottom: 1.5rem; color: var(--color-accent);">📚 Sections pertinentes avec passages</h3>
{% for section in results_data.sections %}
<div class="section-group" style="margin-bottom: 2rem; border: 1px solid rgba(125, 110, 88, 0.2); border-radius: 8px; padding: 1.5rem; background: linear-gradient(135deg, var(--color-bg-main) 0%, #ffffff 100%); box-shadow: 0 2px 8px rgba(125, 110, 88, 0.08);">
<!-- Section header -->
<div class="section-header" style="margin-bottom: 1rem; padding-bottom: 0.75rem; border-bottom: 2px solid var(--color-accent);">
<div style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; flex-wrap: wrap;">
<h4 style="margin: 0; font-size: 1.1em; color: var(--color-text-strong);">{{ section.title[:100] }}{% if section.title|length > 100 %}...{% endif %}</h4>
<span class="badge badge-similarity">⚡ {{ section.similarity }}% similaire</span>
<span class="badge" style="background-color: rgba(125, 110, 88, 0.15); color: var(--color-accent); font-size: 0.85em;">{{ section.chunks_count }} passage{% if section.chunks_count > 1 %}s{% endif %}</span>
</div>
{% if section.summary_text and section.summary_text != section.title and section.summary_text != section.section_path %}
<p style="margin: 0; font-size: 0.9em; color: var(--color-text-main); font-style: italic;">{{ section.summary_text[:150] }}{% if section.summary_text|length > 150 %}...{% endif %}</p>
<p class="summary-text" style="margin: 0.5rem 0 0 0; font-size: 0.9em; color: var(--color-text-main); font-style: italic; line-height: 1.5;">{{ section.summary_text[:200] }}{% if section.summary_text|length > 200 %}...{% endif %}</p>
{% endif %}
{% if section.concepts %}
<div style="margin-top: 0.5rem;">
<div class="concepts" style="margin-top: 0.5rem;">
{% for concept in section.concepts %}
<span class="badge" style="background-color: rgba(125, 110, 88, 0.15); color: var(--color-accent); border: 1px solid rgba(125, 110, 88, 0.3); margin-right: 0.25rem; font-size: 0.85em;">{{ concept }}</span>
{% endfor %}
</div>
{% endif %}
</div>
{% endfor %}
</div>
</div>
<!-- Show top relevant chunks globally -->
<div>
<h3 style="font-size: 1.2em; margin-bottom: 1rem; color: var(--color-accent);">📄 Passages les plus pertinents</h3>
{% for chunk in results_data.results[:20] %}
<div class="chunk-item" style="background: white; padding: 1rem; margin-bottom: 0.75rem; border-left: 3px solid var(--color-accent-alt); border-radius: 4px;">
<div style="margin-bottom: 0.5rem; display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center;">
{% if chunk.work and chunk.work.author %}
<span class="badge badge-author">{{ chunk.work.author }}</span>
{% endif %}
{% if chunk.work and chunk.work.title %}
<span class="badge badge-work">{{ chunk.work.title }}</span>
{% endif %}
<span class="badge badge-similarity">⚡ {{ chunk.similarity }}% similaire</span>
</div>
<div class="passage-text" style="margin-bottom: 0.5rem;">"{{ chunk.text }}"</div>
<div class="passage-meta" style="font-size: 0.85em; color: #666;">
<strong>Section :</strong> {{ chunk.sectionPath or '—' }} &nbsp;&nbsp;
<strong>Type :</strong> {{ chunk.unitType or '—' }} &nbsp;&nbsp;
<strong>Langue :</strong> {{ (chunk.language or '—') | upper }}
</div>
{% if chunk.keywords %}
<div style="margin-top: 0.5rem;">
{% for kw in chunk.keywords %}
<span class="keyword-tag">{{ kw }}</span>
<!-- Chunks under this section -->
{% if section.chunks %}
<div class="chunks-list" style="margin-left: 0; margin-top: 1rem;">
{% for chunk in section.chunks %}
<div class="chunk-item" style="background: white; padding: 1rem; margin-bottom: 0.75rem; border-left: 3px solid var(--color-accent-alt); border-radius: 4px; box-shadow: 0 1px 3px rgba(85, 107, 99, 0.12);">
<div style="margin-bottom: 0.5rem; display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center;">
{% if chunk.work and chunk.work.author %}
<span class="badge badge-author">{{ chunk.work.author }}</span>
{% endif %}
{% if chunk.work and chunk.work.title %}
<span class="badge badge-work">{{ chunk.work.title }}</span>
{% endif %}
<span class="badge badge-similarity">⚡ {{ chunk.similarity }}% similaire</span>
</div>
<div class="passage-text" style="margin-bottom: 0.5rem;">"{{ chunk.text }}"</div>
<div class="passage-meta" style="font-size: 0.85em; color: #666;">
<strong>Section :</strong> {{ chunk.sectionPath or '—' }} &nbsp;&nbsp;
<strong>Type :</strong> {{ chunk.unitType or '—' }} &nbsp;&nbsp;
<strong>Langue :</strong> {{ (chunk.language or '—') | upper }}
</div>
{% if chunk.keywords %}
<div style="margin-top: 0.5rem;">
{% for kw in chunk.keywords %}
<span class="keyword-tag">{{ kw }}</span>
{% endfor %}
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% else %}
<p style="margin-left: 1rem; color: #999; font-style: italic;">Aucun passage trouvé pour cette section</p>
{% endif %}
</div>
{% endfor %}