Ranking siły (LOG-21) + grupowanie identycznych opisów + geolokalizacja

Punktacja siły (LOG-21):
- scoring.py: siła fasety z sygnałów obliczalnych (typ fasety, rodzaj aspektu,
  ciasnota orbu). Konfigurowalne wagi. Hook na przyszłość: kolumny countas*/level*
  z SIGNIFICATORS KEY (obecnie puste).
- aspekty niosą orb+allowed; fasety dostają "score"; ranking faset malejąco.

Grupowanie:
- opcja group: zwija próbki po opisie (ten sam efekt = jedna grupa z listą
  sygnifikatorów i licznikiem). Checkbox "grupuj identyczne opisy" w /interpret.

Geolokalizacja (bajer):
- "Tu i teraz" (widok Horoskop i Interpretacje) uzupełnia lat/lon z przeglądarki
  (navigator.geolocation; wymaga zgody, https/localhost).

Zweryfikowano na realnym main_base.xlsx: ranking sensowny (ciasna opozycja z
Saturn 9.59 > szeroka koniunkcja z Moon 6.25 > znak/dom 5.0); grupowanie zwija
powtórzone opisy. 41 testów przechodzi.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-05 01:16:47 +02:00
parent 243d02d55b
commit f6323cac10
12 changed files with 146 additions and 8 deletions
@@ -23,6 +23,9 @@
<input type="number" name="lon" step="0.0001" value="{{ form.lon if form.lon is not none else 0 }}">
</label>
</div>
<div class="opts">
<label><input type="checkbox" name="group" value="true" {{ 'checked' if form.group else '' }}> grupuj identyczne opisy</label>
</div>
<div class="actions">
<button type="button" id="nowBtn" class="ghost">Tu i teraz</button>
<button type="submit">Szukaj interpretacji</button>
@@ -51,8 +54,20 @@
{% for f in o.facets %}
<div class="facet">
<div class="facet-head">{{ f.label }} — <strong>{{ f.count }}</strong> dopasowań
<span class="badge" title="siła (LOG-21)">siła {{ f.score }}</span>
<span class="muted small">[{{ f.token }}]</span></div>
{% if f.samples %}
{% if f.groups %}
<table class="samples">
<tbody>
{% for g in f.groups %}
<tr>
<td>{{ g.effect }}{% if g.count > 1 %} <span class="badge">×{{ g.count }}</span>{% endif %}</td>
<td class="sig small">{{ g.significators | join('; ') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% elif f.samples %}
<table class="samples">
<tbody>
{% for s in f.samples %}
@@ -75,6 +90,13 @@
d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate());
document.querySelector('input[name=time]').value = pad(d.getHours()) + ':' + pad(d.getMinutes());
document.querySelector('input[name=tz_offset]').value = (-d.getTimezoneOffset() / 60);
// bajer: lokalizacja z przeglądarki (wymaga zgody; działa na https/localhost)
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (pos) {
document.querySelector('input[name=lat]').value = pos.coords.latitude.toFixed(4);
document.querySelector('input[name=lon]').value = pos.coords.longitude.toFixed(4);
});
}
});
</script>
{% endblock %}