Files
game-library/app/templates/index.html
Claude Agent bcfb6841eb Faza 1 complete: bilingual+enrichment plumbing, UI/filters, frozen DB
Extraction finished (575/588 chunks; 6 content-filter-blocked, 7 await
re-extraction). DB rebuilt and frozen at 9418 activities — content_keys
are now stable for the enrichment overlay.

Part A (plumbing + UI):
- database.py: name_ro/description_ro/rules_ro/variations_ro, indoor_outdoor,
  space_needed, estimated_fields, source_id/source_ids/chunk_key columns;
  FTS5 indexes the 4 *_ro columns across CREATE + all 3 triggers; new equality
  filters + category counts for both axes.
- activity.py: new fields + bilingual display helpers (get_display_*,
  is_estimated, axis displays).
- config_taxonomy.py: INDOOR_OUTDOOR/SPACE_NEEDED enums + normalizers
  (None on unrecognised, no fabrication).
- search.py / routes.py / config.py / templates / css: new dropdowns,
  RO-primary rendering with "(estimat)" markers and collapsible original
  text, and a /source/<id> download route shipped DARK behind
  SOURCE_DOWNLOAD_ENABLED (copyright opt-in).
- build_database.py: source_id/chunk_key in dict_to_activity; merge_cluster
  unions source_ids without touching enrichment fields.

Part B (enrichment pipeline, built not yet run):
- build_database.py: load_enrichment + apply_enrichment (post-dedup, keyed on
  content_key) + --enrichment CLI + stated-vs-estimated QA.
- run_enrichment.py (resumable, --source/--limit pilot scoping, --collect),
  ENRICHMENT_PROMPT.md.

Repair: scripts/repair_extractions.py fixes the subagents' systematic
unescaped-ASCII-quote bug with a faithful char-scanner (escapes, never
truncates) + schema validation + a strictly-more-text guard. json_repair was
tried first, truncated silently, and is NOT used. build_database has no repair
dependency.

Tests: tests/test_enrichment.py added; 99 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 18:10:13 +00:00

201 lines
8.5 KiB
HTML

{% extends "base.html" %}
{% block title %}Căutare Activități - INDEX Sistem Jocuri{% endblock %}
{% block content %}
<div class="search-page">
<div class="search-header">
<h2 class="search-title">Căutare Activități Educaționale</h2>
<p class="search-subtitle">
Descoperă activități pentru copii și tineri din catalogul nostru de
{% if stats and stats.total_activities %}{{ stats.total_activities }}{% else %}500+{% endif %}
jocuri și exerciții.
</p>
</div>
<form method="POST" action="{{ url_for('main.search') }}" class="search-form">
<!-- Main search input -->
<div class="search-input-group">
<input
type="text"
name="search_query"
id="search_query"
class="search-input"
placeholder="Caută activități după nume, descriere sau cuvinte cheie..."
autocomplete="off"
>
<button type="submit" class="search-button">Căutare</button>
</div>
<!-- Dynamic filters -->
<div class="filters-grid">
{% if filters %}
{% if filters.category %}
<div class="filter-group">
<label for="category" class="filter-label">Categorie</label>
<select name="category" id="category" class="filter-select">
<option value="">Toate categoriile</option>
{% for category in filters.category %}
<option value="{{ category }}">{{ display_names.get(category, category) }}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% if filters.content_type %}
<div class="filter-group">
<label for="content_type" class="filter-label">Tip conținut</label>
<select name="content_type" id="content_type" class="filter-select">
<option value="">Doar jocuri și activități</option>
{% for content_type in filters.content_type %}
<option value="{{ content_type }}">{{ display_names.get(content_type, content_type) }}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% if filters.language %}
<div class="filter-group">
<label for="language" class="filter-label">Limbă</label>
<select name="language" id="language" class="filter-select">
<option value="">Toate limbile</option>
{% for language in filters.language %}
<option value="{{ language }}">{{ display_names.get(language, language) }}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% if filters.age_group %}
<div class="filter-group">
<label for="age_group" class="filter-label">Grupa de vârstă</label>
<select name="age_group" id="age_group" class="filter-select">
<option value="">Toate vârstele</option>
{% for age_group in filters.age_group %}
<option value="{{ age_group }}">{{ age_group }}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% if filters.participants %}
<div class="filter-group">
<label for="participants" class="filter-label">Participanți</label>
<select name="participants" id="participants" class="filter-select">
<option value="">Orice număr</option>
{% for participants in filters.participants %}
<option value="{{ participants }}">{{ participants }}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% if filters.duration %}
<div class="filter-group">
<label for="duration" class="filter-label">Durata</label>
<select name="duration" id="duration" class="filter-select">
<option value="">Orice durată</option>
{% for duration in filters.duration %}
<option value="{{ duration }}">{{ duration }}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% if filters.materials %}
<div class="filter-group">
<label for="materials" class="filter-label">Materiale</label>
<select name="materials" id="materials" class="filter-select">
<option value="">Orice materiale</option>
{% for materials in filters.materials %}
<option value="{{ materials }}">{{ materials }}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% if filters.difficulty %}
<div class="filter-group">
<label for="difficulty" class="filter-label">Dificultate</label>
<select name="difficulty" id="difficulty" class="filter-select">
<option value="">Orice nivel</option>
{% for difficulty in filters.difficulty %}
<option value="{{ difficulty }}">{{ difficulty }}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% if filters.indoor_outdoor %}
<div class="filter-group">
<label for="indoor_outdoor" class="filter-label">Interior / exterior</label>
<select name="indoor_outdoor" id="indoor_outdoor" class="filter-select">
<option value="">Oriunde</option>
{% for io in filters.indoor_outdoor %}
<option value="{{ io }}">{{ display_names.get(io, io) }}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% if filters.space_needed %}
<div class="filter-group">
<label for="space_needed" class="filter-label">Spațiu necesar</label>
<select name="space_needed" id="space_needed" class="filter-select">
<option value="">Orice spațiu</option>
{% for sp in filters.space_needed %}
<option value="{{ sp }}">{{ display_names.get(sp, sp) }}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% endif %}
</div>
<!-- Action buttons -->
<div class="search-actions">
<button type="submit" class="btn btn-primary">Aplică filtrele</button>
<button type="button" class="btn btn-secondary" onclick="clearFilters()">Resetează</button>
</div>
</form>
<!-- Quick stats -->
{% if stats and stats.categories %}
<div class="quick-stats">
<h3 class="stats-title">Categorii disponibile</h3>
<div class="stats-grid">
{% for category, count in stats.categories.items() %}
<div class="stat-item">
<span class="stat-label">{{ category }}</span>
<span class="stat-value">{{ count }}</span>
</div>
{% endfor %}
</div>
</div>
{% endif %}
</div>
{% endblock %}
{% block scripts %}
<script>
function clearFilters() {
// Reset all form fields
document.getElementById('search_query').value = '';
const selects = document.querySelectorAll('.filter-select');
selects.forEach(select => select.selectedIndex = 0);
}
// Auto-submit on filter change for better UX
document.addEventListener('DOMContentLoaded', function() {
const filterSelects = document.querySelectorAll('.filter-select');
filterSelects.forEach(select => {
select.addEventListener('change', function() {
if (this.value) {
document.querySelector('.search-form').submit();
}
});
});
});
</script>
{% endblock %}