Doua greseli din grupul "Maria Test", 2026-09-01, pe care 27409fb le-a atenuat dar
nu le-a rezolvat.
1. La o reclamatie vaga Maria cauta, in loc sa intrebe. "Buna . Am si eu o factura
pe luna august cu eroare in spv la trimitere AUTO SULE" nu spune CE eroare e —
n-are ce cauta in documente si n-are ce trimite la suport, fiindca programatorul
ar pune exact aceeasi intrebare. Gardul (triaj.prea_vag) exista, dar cerea text
sub 12 cuvinte; mesajul are 14. Gresea si invers: "nu pot incarca factura in SPV,
imi da eroare de certificat" are 9 cuvinte si ARE raspuns in documente, si era
oprita degeaba. Lungimea nu masoara cat de precis e mesajul.
-> gardul nu mai numara cuvinte si se aplica DUPA cautare, doar cand nu exista
acoperire. O singura data pe fir: daca nici intrebat omul nu spune mai mult,
mesajul pleaca la suport.
2. Textul si captura, trimise una dupa alta, erau tratate ca doua probleme fara
legatura. `este_continuare` rupea firul la ORICE imagine — dar cazul frecvent e
tocmai omul care scrie problema si trimite captura imediat dupa, sau care
raspunde la "trimite-mi o captura". Textul se pierdea, captura se cauta doar pe
OCR-ul ei, se deschideau doua fire si se puteau deschide doua escaladari pentru
aceeasi problema.
-> o captura in primele FIR_IMAGINE_MIN (5) minute continua firul: textul citit
din ea intra in ancora (cu tot cu coduri), cautarea se face pe mesaj +
captura, iar pe o escaladare deschisa pleaca la aceeasi referinta — cu
imaginea, nu doar cu textul citit din ea (_notifica_suport ia si media).
Si, ca urmare a lui (2): RANK_STRONG_COSINE dispare. Interogarea pe un fir e ancora
plus mesajul nou, deci cosinusul urca la fiecare replica fara sa apara vreo dovada
noua — aceeasi captura da 0,778 singura si 0,836 cu mesajul de dinainte, adica peste
0,80 pus ieri. Orice prag fix de sus e trecut de o discutie destul de lunga. Acoperirea
ramane pe dovada lexicala (termenii distinctivi ai intrebarii chiar in chunk-uri),
care e stabila la lungime. Niciun caz cu raspuns in documente nu avea nevoie de
scurtatura.
ops/calibrate-rank.py: 26/26, cu interogarea combinata adaugata la set. Teste: 102 pass.
Verificat end-to-end pe scenariul real (mesaj, apoi captura la 10 secunde): intrebare
de detalii, apoi o singura escaladare care poarta si textul si captura.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4uzvgm7AyJch5WH8QHRhY
113 lines
4.1 KiB
Python
113 lines
4.1 KiB
Python
"""Firul de discutie: continuare vs subiect nou, ancora, tacerea la preluare."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import time
|
|
|
|
import fir
|
|
|
|
|
|
JID = "40712345678@s.whatsapp.net"
|
|
EROARE = ("[Oracle][ODBC][Ora]ORA-06550: line 1, column 7\n"
|
|
"PLS-00906: object VADECO PACK PARTENERI is invalid")
|
|
|
|
|
|
def test_firul_retine_codurile_ancorei():
|
|
f = fir.deschide(JID, EROARE)
|
|
assert "ora-06550" in f["coduri"] and "pls-00906" in f["coduri"]
|
|
|
|
|
|
def test_un_raspuns_scurt_e_continuare_nu_eroare_noua():
|
|
"""Cazul masurat: „da, ma blocheaza" cautat singur nimerea ordinul de plata."""
|
|
f = fir.deschide(JID, EROARE)
|
|
assert fir.este_continuare(f, "da, ma blocheaza complet", False)
|
|
assert fir.este_continuare(f, "eram la salvarea unei facturi", False)
|
|
# ancora intra in cautare, ca sa nu se caute patru cuvinte fara context
|
|
q = fir.interogare(f, "da, ma blocheaza complet")
|
|
assert "ORA-06550" in q and "ma blocheaza" in q
|
|
|
|
|
|
def test_alt_cod_rupe_firul():
|
|
f = fir.deschide(JID, EROARE)
|
|
assert not fir.este_continuare(f, "imi da acum ORA-12154", False)
|
|
# acelasi cod nu rupe firul
|
|
assert fir.este_continuare(f, "tot ORA-06550 imi da", False)
|
|
|
|
|
|
def test_captura_imediat_dupa_mesaj_continua_firul():
|
|
"""Cazul real: omul scrie problema si trimite captura la cateva secunde."""
|
|
f = fir.deschide(JID, "am o factura pe august cu eroare la trimitere")
|
|
assert fir.este_continuare(f, "", True)
|
|
|
|
|
|
def test_captura_mult_mai_tarziu_deschide_alt_fir():
|
|
f = fir.deschide(JID, EROARE)
|
|
f["at"] = time.time() - fir.imagine_fereastra_s() - 1
|
|
assert not fir.este_continuare(f, "", True)
|
|
|
|
|
|
def test_captura_pe_fir_aduce_textul_erorii_in_ancora():
|
|
"""Ancora era reclamatia vaga; captura e cea care spune ce eroare e."""
|
|
f = fir.deschide(JID, "am o factura cu eroare la trimitere")
|
|
fir.extinde_ancora(f, "ORA-06550: line 1, column 7")
|
|
assert "ora-06550" in f["coduri"]
|
|
assert "eroare la trimitere" in f["ancora"] and "ORA-06550" in f["ancora"]
|
|
# continuarile de dupa captura se cauta cu tot cu eroare, nu doar cu reclamatia
|
|
assert "ORA-06550" in fir.interogare(f, "da, ma blocheaza")
|
|
|
|
|
|
def test_fara_fir_nu_exista_continuare():
|
|
assert not fir.este_continuare(None, "da", False)
|
|
|
|
|
|
def test_firul_expira(monkeypatch):
|
|
f = fir.deschide(JID, EROARE)
|
|
fir.salveaza(f)
|
|
assert fir.incarca(JID) is not None
|
|
|
|
tarziu = time.time() + fir.ttl_s() + 1
|
|
monkeypatch.setattr(fir.time, "time", lambda: tarziu)
|
|
assert fir.incarca(JID) is None
|
|
|
|
|
|
def test_istoricul_se_opreste_la_max_schimburi():
|
|
f = fir.deschide(JID, EROARE)
|
|
for i in range(fir.MAX_SCHIMBURI + 4):
|
|
fir.adauga(f, "client", f"mesaj {i}")
|
|
assert len(f["schimburi"]) == fir.MAX_SCHIMBURI
|
|
assert f["schimburi"][-1]["text"] == f"mesaj {fir.MAX_SCHIMBURI + 3}"
|
|
assert fir.istoric(f)[-1]["role"] == "user"
|
|
|
|
|
|
def test_comenzile_de_oprire_si_revenire():
|
|
assert fir.comanda("Maria, stop") == "stop"
|
|
assert fir.comanda("preiau eu") == "stop"
|
|
assert fir.comanda("Maria, continua") == "start"
|
|
assert fir.comanda("cum trimit D406") is None
|
|
|
|
|
|
def test_tacerea_expira(monkeypatch):
|
|
f = fir.deschide(JID, EROARE)
|
|
fir.taci(f)
|
|
assert fir.tace(f)
|
|
tarziu = time.time() + fir.tacere_s() + 1
|
|
monkeypatch.setattr(fir.time, "time", lambda: tarziu)
|
|
assert not fir.tace(f)
|
|
|
|
|
|
def test_preluarea_doar_in_grupuri_cu_mai_multi_oameni(monkeypatch):
|
|
"""In self-chat si in grupul de test tot ce se scrie e fromMe."""
|
|
import consumer
|
|
monkeypatch.setattr(consumer, "grup_info",
|
|
lambda jid: {"participants": 1 if "test" in jid else 5})
|
|
|
|
assert not consumer.preluare_de_om({"fromMe": True, "isGroup": False, "from": JID})
|
|
assert not consumer.preluare_de_om(
|
|
{"fromMe": True, "isGroup": True, "from": "test@g.us", "text": "salut"})
|
|
assert consumer.preluare_de_om(
|
|
{"fromMe": True, "isGroup": True, "from": "client@g.us", "text": "preiau eu cazul"})
|
|
# propriul raspuns al Mariei nu e „un om care a preluat"
|
|
assert not consumer.preluare_de_om(
|
|
{"fromMe": True, "isGroup": True, "from": "client@g.us",
|
|
"text": consumer.REPLY_PREFIX + "buna"})
|