Files

142 lines
7.9 KiB
HTML

{% extends "base.html" %}
{% block content %}
<div class="info-bar">
<span style="font-weight:600">📜 Enrichissement Lore — Venice of Wasteland</span>
<div class="lore-stat-bar" style="margin:0">
<span class="lore-stat">En attente : <span style="color:var(--amber)">{{ lore_stats.pending }}</span></span>
<span class="lore-stat">Acceptées : <span style="color:var(--green)">{{ lore_stats.accepted }}</span></span>
<span class="lore-stat">Rejetées : <span style="color:var(--red)">{{ lore_stats.rejected }}</span></span>
<span class="lore-stat">Modifiées : <span style="color:var(--blue)">{{ lore_stats.modified }}</span></span>
</div>
</div>
<div class="lore-filters">
<label>Faction :</label>
<select onchange="location.href='/lore?faction='+this.value+'&status='+document.getElementById('filt-status').value">
<option value="" {{ 'selected' if not filt_faction else '' }}>— toutes —</option>
{% for f in all_factions %}
<option value="{{ f }}" {{ 'selected' if filt_faction==f else '' }}>{{ f }}</option>
{% endfor %}
</select>
<label>Statut :</label>
<select id="filt-status" onchange="location.href='/lore?faction='+document.querySelector('[onchange]').value+'&status='+this.value">
<option value="pending" {{ 'selected' if filt_status=='pending' else '' }}>pending</option>
<option value="accepted" {{ 'selected' if filt_status=='accepted' else '' }}>accepted</option>
<option value="rejected" {{ 'selected' if filt_status=='rejected' else '' }}>rejected</option>
<option value="modified" {{ 'selected' if filt_status=='modified' else '' }}>modified</option>
<option value="" {{ 'selected' if not filt_status else '' }}>— tous —</option>
</select>
<span style="font-size:12px;color:var(--dim)">{{ proposals|length }} proposition(s) affichée(s)</span>
</div>
{% if not proposals %}
<div class="panel" style="color:var(--dim);text-align:center;padding:24px">
Aucune proposition lore.<br>
<small style="color:var(--border)">Lancer : <code>python3 lore_enricher.py --faction grand_krewe</code> sur Ampère</small>
</div>
{% endif %}
{% for p in proposals %}
<div class="lore-card">
<div class="lore-meta">
<span>#{{ p.id }}</span>
<span class="badge-{{ p.status }}">{{ p.status | upper }}</span>
<span class="change-type-badge">{{ p.change_type }}</span>
<span style="color:var(--amber)">{{ p.faction_slug }}</span>
{% if p.field_path %}<span>{{ p.field_path }}</span>{% endif %}
<span style="color:var(--dim)">{{ p.created_at.strftime('%d/%m %H:%M') if p.created_at else '' }}</span>
</div>
<h3>{{ p.rationale or '(pas de justification)' }}</h3>
<div class="lore-diff">
<div>
<div class="diff-label">Original</div>
<div class="diff-old">{{ p.original_text or '(ajout — pas de texte original)' }}</div>
</div>
<div>
<div class="diff-label">Proposé</div>
<div class="diff-new">{{ p.proposed_text }}</div>
</div>
</div>
{% if p.status == 'pending' %}
<div class="lore-actions">
<form method="POST" action="/lore/action" style="display:inline">
<input type="hidden" name="id" value="{{ p.id }}">
<input type="hidden" name="action" value="accept">
<input type="hidden" name="filt_faction" value="{{ filt_faction }}">
<input type="hidden" name="filt_status" value="{{ filt_status }}">
<button type="submit" class="btn btn-green" onclick="return confirm('Accepter cette proposition ?')">✓ Accepter</button>
</form>
<form method="POST" action="/lore/action" style="display:inline">
<input type="hidden" name="id" value="{{ p.id }}">
<input type="hidden" name="action" value="reject">
<input type="hidden" name="filt_faction" value="{{ filt_faction }}">
<input type="hidden" name="filt_status" value="{{ filt_status }}">
<button type="submit" class="btn btn-red">✗ Rejeter</button>
</form>
<form method="POST" action="/lore/action" style="width:100%;margin-top:6px">
<input type="hidden" name="id" value="{{ p.id }}">
<input type="hidden" name="action" value="modify">
<input type="hidden" name="filt_faction" value="{{ filt_faction }}">
<input type="hidden" name="filt_status" value="{{ filt_status }}">
<textarea name="modified_text" placeholder="Texte modifié…">{{ p.proposed_text }}</textarea>
<button type="submit" class="btn" style="margin-top:6px">✎ Modifier & Accepter</button>
</form>
</div>
{% elif p.status == 'modified' and p.modified_text %}
<div style="margin-top:8px">
<div class="diff-label">Texte modifié accepté</div>
<div class="diff-new" style="border-color:rgba(96,165,250,.3)">{{ p.modified_text }}</div>
</div>
{% endif %}
{% if p.status in ('modified', 'accepted') %}
<button type="button" class="btn" onclick="toggleDiscuss({{ p.id }})" style="font-size:12px;margin-top:8px">💬 Discuter / Modifier</button>
<div id="discuss-{{ p.id }}" style="display:none;margin-top:12px;border-top:1px solid var(--border);padding-top:10px">
{% for msg in proposal_threads.get(p.id, []) %}
<div style="margin-bottom:8px;padding:6px 10px;border-radius:4px;{% if msg.role=='user' %}background:#0d1117;border-left:2px solid var(--amber){% else %}background:#050d05;border-left:2px solid var(--green){% endif %}">
<span style="font-size:10px;color:var(--dim);display:block;margin-bottom:3px">{{ '👤 Toi' if msg.role=='user' else '🤖 LLM' }} — {{ msg.created_at.strftime('%d/%m %H:%M') if msg.created_at else '' }}</span>
<span style="font-size:12px;white-space:pre-wrap">{{ msg.content }}</span>
</div>
{% endfor %}
<div style="display:flex;flex-direction:column;gap:6px;margin-top:8px">
<textarea id="discuss-msg-{{ p.id }}" placeholder="Ex: Garde l'idée mais réduis l'impact de 50%…" style="background:var(--bg);border:1px solid var(--border);color:var(--text);font-size:12px;padding:6px;border-radius:3px;height:54px;resize:vertical"></textarea>
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">
<span style="font-size:11px;color:var(--dim)">temp: <input type="range" id="discuss-temp-{{ p.id }}" min="0" max="1" step="0.05" value="0.75" style="width:70px;vertical-align:middle" oninput="document.getElementById('discuss-temp-val-{{ p.id }}').textContent=this.value"> <span id="discuss-temp-val-{{ p.id }}">0.75</span></span>
<span style="font-size:11px;color:var(--dim)">tokens: <input type="number" id="discuss-np-{{ p.id }}" value="512" min="128" max="2048" step="128" style="width:58px;background:var(--bg);border:1px solid var(--border);color:var(--text);font-size:11px;padding:2px 4px"></span>
<button class="btn btn-green" onclick="submitDiscuss({{ p.id }})" style="font-size:12px">▶ Envoyer</button>
<span id="discuss-spinner-{{ p.id }}" style="display:none;color:var(--amber);font-size:12px">⏳ Génération…</span>
</div>
</div>
</div>
{% endif %}
</div>
{% endfor %}
<script>
function toggleDiscuss(id) {
var el = document.getElementById('discuss-' + id);
el.style.display = el.style.display === 'none' ? 'block' : 'none';
}
function submitDiscuss(id) {
var msg = document.getElementById('discuss-msg-' + id).value.trim();
var temp = parseFloat(document.getElementById('discuss-temp-' + id).value);
var np = parseInt(document.getElementById('discuss-np-' + id).value);
if (!msg) { alert('Message vide'); return; }
var spin = document.getElementById('discuss-spinner-' + id);
spin.style.display = 'inline';
fetch('/lore/' + id + '/discuss', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({message: msg, temperature: temp, num_predict: np})
}).then(function(r){ return r.json(); }).then(function(d){
spin.style.display = 'none';
if (d.error) { alert(d.error); return; }
location.reload();
}).catch(function(e){ spin.style.display = 'none'; alert('Erreur réseau : ' + e); });
}
</script>
{% endblock %}