fix(maria): fara "caut informatia" la completari, si trei feluri de raspuns
Din firul testat in grup: la "Urgent este", "Nu m-a contactat nimeni. Cat mai
dureaza?" si "Tot nimic", Maria trimitea de fiecare data "Caut informatia, revin
imediat...", calcula un embedding pe care il arunca, si raspundea acelasi sablon
("am adaugat si asta la M-..."). La intrebarea "cat mai dureaza" nu raspundea deloc,
iar "urgent" nu schimba nimic nicaieri.
- Completarea se decide INAINTEA confirmarii si a cautarii: raspunsul vine instant,
deci nici promisiune, nici embedding degeaba (~1-2s per mesaj).
- triaj.fel_completare: urgenta / stare / detaliu.
- urgenta -> escaladarea se marcheaza si suportul primeste un mesaj cu URGENT;
- stare -> raspuns cu ce stim (de cat timp asteapta) si reamintire catre echipa,
cel mult una la 15 minute, ca sa nu sune telefonul la fiecare "tot nimic";
- detaliu -> confirmare scurta, cu formularea rotita.
- Peste 30 de minute fara raspuns Maria o spune pe fata si indruma spre telefon
(SUPPORT_PHONE), in loc sa repete ca "echipa vede detaliul".
- Gramatica: "acum 10 minute", nu "acum 10 de minute".
Teste: 99 pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4uzvgm7AyJch5WH8QHRhY
This commit is contained in:
@@ -429,6 +429,23 @@ singurele semne sigure ca omul a trecut la altceva. Schimbarea subiectului in cu
|
||||
NU rupe firul: e prea usor de confundat cu o continuare, iar greseala aia produce
|
||||
exact tabelul de mai sus. In rest, firul expira dupa `FIR_TTL_MIN` (120 min).
|
||||
|
||||
### Completarile: trei feluri, trei raspunsuri
|
||||
|
||||
Cat timp firul are o escaladare deschisa, mesajele urmatoare sunt completari la ea.
|
||||
Decizia se ia **inaintea cautarii si a confirmarii** „caut informatia": raspunsul vine
|
||||
instant, deci un „revin imediat" ar fi o promisiune inutila, iar embedding-ul (~1-2s)
|
||||
s-ar calcula degeaba — asta se si intampla inainte, la fiecare „tot nimic".
|
||||
|
||||
| Ce scrie omul | Ce face Maria |
|
||||
|---|---|
|
||||
| „este foarte urgent", „ma blocheaza" | marcheaza escaladarea `urgenta`, trimite la suport un mesaj cu **URGENT** in cap |
|
||||
| „cat mai dureaza?", „nu m-a contactat nimeni" | spune de cat timp e trimisa problema si reaminteste echipei — **cel mult o data la 15 minute** (`REAMINTIRE_MIN`) |
|
||||
| orice alt detaliu | confirmare scurta, cu formularea rotita |
|
||||
|
||||
Peste 30 de minute fara raspuns, Maria n-o mai da cu „echipa vede detaliul cand preia
|
||||
problema": spune ca nu i-a raspuns nimeni si indruma spre telefon (`SUPPORT_PHONE`,
|
||||
daca e completat). Omul stie oricum de cat timp asteapta — o formula l-ar enerva.
|
||||
|
||||
### Cand preia un om
|
||||
|
||||
Daca cineva din echipa scrie in discutie, Maria tace `FIR_TACERE_MIN` minute (60), ca
|
||||
|
||||
@@ -50,6 +50,8 @@ RANK_MIN_RARE_RATIO=0.5
|
||||
# "<id>@g.us" pentru un grup. Numarul se scrie international, fara "+".
|
||||
# Gol = escaladarile se scriu doar in ~/.maria-bridge/escalations/, fara notificare.
|
||||
SUPPORT_JID=
|
||||
# Numarul spus clientului cand asteapta de peste 30 de minute fara raspuns.
|
||||
SUPPORT_PHONE=
|
||||
|
||||
# --- Backend LLM + embeddings -----------------------------------------------
|
||||
# Modelul de chat folosit pentru raspunsuri (format compatibil OpenAI
|
||||
|
||||
@@ -64,6 +64,9 @@ DEFAULTS: dict[str, str] = {
|
||||
# "40712345678@s.whatsapp.net" sau "1203...@g.us" pentru un grup.
|
||||
# Gol = escaladarile se scriu doar in jurnal (~/.maria-bridge/escalations/).
|
||||
"SUPPORT_JID": "",
|
||||
# Numarul de telefon al suportului, spus omului cand asteapta de prea mult
|
||||
# timp fara ca cineva sa preia (vezi triaj.raspuns_stare). Gol = nu se da.
|
||||
"SUPPORT_PHONE": "",
|
||||
# Tinta rclone pentru sincronizarea depozitului de documente, ex:
|
||||
# "gdrive,root_folder_id=1C4e75zgH1_7ZK-_oBP5ZZBvUPh3iEo1O:" (dosarul
|
||||
# document_store din Drive, vazut pe Windows ca D:\GoogleDrive\romfast\document_store).
|
||||
|
||||
@@ -80,10 +80,6 @@ TACERE_OK = (
|
||||
'Am inteles, ma opresc. Scrie-mi "Maria, continua" cand vrei sa reiau.'
|
||||
)
|
||||
REVENIRE_OK = "Sunt aici. Cu ce te ajut?"
|
||||
FOLLOWUP_OK = (
|
||||
"Multumesc, am adaugat si asta la {ref} — echipa vede detaliul cand preia "
|
||||
"problema."
|
||||
)
|
||||
|
||||
|
||||
def bridge_url() -> str:
|
||||
@@ -346,40 +342,84 @@ def escalate(msg: dict, question: str, search_result: dict, fir: dict | None = N
|
||||
return record
|
||||
|
||||
|
||||
def append_followup(ref: str, msg: dict, text: str) -> bool:
|
||||
"""Adauga raspunsul omului la escaladarea deschisa si il trimite la suport.
|
||||
REAMINTIRE_MIN = 15 # cat de rar poate Maria sa reaminteasca aceeasi problema
|
||||
|
||||
Raspunsul la „te blocheaza sau poti continua?" e chiar informatia care lipseste
|
||||
din escaladare. O escaladare noua ar rupe firul: aceeasi problema, alta
|
||||
referinta, iar omul a citat-o deja pe prima.
|
||||
"""
|
||||
|
||||
def _fisier_escaladare(ref: str):
|
||||
d = config.STATE_DIR / "escalations"
|
||||
fisier = next((f for f in sorted(d.glob(f"*-{ref}.json"))), None) if d.exists() else None
|
||||
if fisier is None:
|
||||
if not d.exists():
|
||||
return None
|
||||
return next(iter(sorted(d.glob(f"*-{ref}.json"))), None)
|
||||
|
||||
|
||||
def _notifica_suport(text: str) -> bool:
|
||||
jid = config.get("SUPPORT_JID") or ""
|
||||
if not jid:
|
||||
return False
|
||||
try:
|
||||
requests.post(f"{bridge_url()}/send", json={"to": jid, "text": text}, timeout=20)
|
||||
return True
|
||||
except Exception as exc: # noqa: BLE001
|
||||
print(f"[consumer] mesaj catre suport netrimis: {exc}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
|
||||
def completeaza(ref: str, msg: dict, text: str) -> str | None:
|
||||
"""Adauga mesajul la escaladarea deschisa si intoarce ce i se raspunde omului.
|
||||
|
||||
`None` daca escaladarea nu mai exista (atunci mesajul se trateaza normal).
|
||||
|
||||
Trei feluri de completare, cu trei raspunsuri diferite: un semnal de urgenta
|
||||
schimba escaladarea si anunta echipa; o intrebare de stare primeste ce stim
|
||||
(de cat timp asteapta, daca am reamintit); un detaliu primeste o confirmare
|
||||
scurta, rotita, ca sa nu sune a robot la a treia oara.
|
||||
"""
|
||||
fisier = _fisier_escaladare(ref)
|
||||
if fisier is None:
|
||||
return None
|
||||
try:
|
||||
record = json.loads(fisier.read_text(encoding="utf-8"))
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
record.setdefault("completari", []).append(
|
||||
{"at": time.time(), "text": text, "message_id": msg.get("id")})
|
||||
return None
|
||||
|
||||
fel = triaj.fel_completare(text)
|
||||
completari = record.setdefault("completari", [])
|
||||
completari.append({"at": time.time(), "text": text, "fel": fel,
|
||||
"message_id": msg.get("id")})
|
||||
cine = msg.get("pushName") or msg.get("from") or "necunoscut"
|
||||
minute = int((time.time() - record.get("at", time.time())) / 60)
|
||||
|
||||
if fel == "urgenta":
|
||||
record["urgenta"] = True
|
||||
trimis = _notifica_suport(
|
||||
f"[Maria] URGENT — {ref} (de la {cine})\n{text[:800]}")
|
||||
record["ultima_reamintire"] = time.time()
|
||||
raspuns = triaj.URGENTA_MARCATA.format(ref=ref)
|
||||
elif fel == "stare":
|
||||
# Reamintirea e limitata: la fiecare „tot nimic" nu suna telefonul echipei.
|
||||
de_reamintit = time.time() - record.get("ultima_reamintire", record.get("at", 0)) \
|
||||
> REAMINTIRE_MIN * 60
|
||||
reamintit = False
|
||||
if de_reamintit:
|
||||
reamintit = _notifica_suport(
|
||||
f"[Maria] {ref}: clientul intreaba de {minute} minute daca s-a "
|
||||
f"rezolvat.\n{text[:400]}")
|
||||
if reamintit:
|
||||
record["ultima_reamintire"] = time.time()
|
||||
intrebari = sum(1 for c in completari if c.get("fel") == "stare")
|
||||
raspuns = triaj.raspuns_stare(ref, minute, reamintit,
|
||||
config.get("SUPPORT_PHONE", ""),
|
||||
a_cata=intrebari - 1)
|
||||
else:
|
||||
_notifica_suport(f"[Maria] Completare la {ref} (de la {cine}):\n{text[:800]}")
|
||||
raspuns = triaj.confirmare(ref, len(completari) - 1)
|
||||
|
||||
try:
|
||||
fisier.write_text(json.dumps(record, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
except OSError as exc:
|
||||
print(f"[consumer] nu pot actualiza {fisier.name}: {exc}", file=sys.stderr)
|
||||
|
||||
jid = config.get("SUPPORT_JID") or ""
|
||||
if jid:
|
||||
cine = msg.get("pushName") or msg.get("from") or "necunoscut"
|
||||
try:
|
||||
requests.post(f"{bridge_url()}/send", json={
|
||||
"to": jid,
|
||||
"text": f"[Maria] Completare la {ref} (de la {cine}):\n{text[:800]}",
|
||||
}, timeout=20)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
print(f"[consumer] completare netrimisa: {exc}", file=sys.stderr)
|
||||
print(f"[consumer] completare la {ref}: {text[:60]!r}", file=sys.stderr)
|
||||
return True
|
||||
print(f"[consumer] completare '{fel}' la {ref}: {text[:60]!r}", file=sys.stderr)
|
||||
return raspuns
|
||||
|
||||
|
||||
_GRUPURI_CACHE: dict = {"at": 0.0, "date": {}}
|
||||
@@ -483,6 +523,20 @@ def handle(index: Index, msg: dict) -> None:
|
||||
send_reply(sender, triaj.CERE_DETALII)
|
||||
return
|
||||
|
||||
# Firul are o escaladare deschisa: mesajul e completare la ea, nu intrebare
|
||||
# noua. Inaintea confirmarii si a cautarii — raspunsul vine instant, deci un
|
||||
# „caut informatia, revin imediat" ar fi o promisiune inutila, iar embedding-ul
|
||||
# s-ar calcula degeaba.
|
||||
if continuare and fir.get("ref") and text.strip():
|
||||
raspuns = completeaza(fir["ref"], msg, text.strip())
|
||||
if raspuns:
|
||||
fir_mod.adauga(fir, "client", text)
|
||||
fir_mod.adauga(fir, "maria", raspuns)
|
||||
fir_mod.salveaza(fir)
|
||||
send_reply(sender, raspuns)
|
||||
return
|
||||
fir["ref"] = None # escaladarea nu mai exista; tratam mesajul normal
|
||||
|
||||
send_reply(sender, ACK_IMAGE_TEXT if has_image else ACK_TEXT)
|
||||
|
||||
question, search_query, immediate = prepare_query(msg)
|
||||
@@ -511,15 +565,6 @@ def handle(index: Index, msg: dict) -> None:
|
||||
surse = ", ".join(f"{t['source']}({t['cosine']})" for t in result["top"]) or "-"
|
||||
print(f"[consumer] rank: {surse} | {result['reason']}", file=sys.stderr)
|
||||
|
||||
# Firul are deja o escaladare deschisa: ce spune omul acum e completare la ea,
|
||||
# nu o problema noua. De cate ori e nevoie, nu o singura data.
|
||||
if continuare and fir.get("ref") and append_followup(fir["ref"], msg, text.strip() or "(captura)"):
|
||||
raspuns = FOLLOWUP_OK.format(ref=fir["ref"])
|
||||
fir_mod.adauga(fir, "maria", raspuns)
|
||||
fir_mod.salveaza(fir)
|
||||
send_reply(sender, raspuns)
|
||||
return
|
||||
|
||||
if not result["covered"]:
|
||||
print(f"[consumer] fara acoperire in documente -> suport ({result['reason']})", file=sys.stderr)
|
||||
record = escalate(msg, question, result, fir)
|
||||
|
||||
@@ -127,3 +127,93 @@ def raspuns_escaladat(chunk: str, nivel: str, ref: str, notificat: bool,
|
||||
)
|
||||
parti.append(INTREBARE_URGENTA)
|
||||
return "\n\n".join(parti)
|
||||
|
||||
|
||||
# --- ce fel de completare e raspunsul omului --------------------------------
|
||||
|
||||
_URGENTA = re.compile(
|
||||
r"\b(urgent|urgenta|foarte urgent|ma blocheaza|blocheaza|nu pot lucra|"
|
||||
r"nu pot factura|nu merge nimic|sta toata firma|s-a oprit tot)\b"
|
||||
)
|
||||
_STARE = re.compile(
|
||||
r"(cat mai dureaza|cat dureaza|cand ma contacteaza|nu m-?a contactat|"
|
||||
r"nu m-?a sunat|tot nimic|nimic inca|chiar nimic|ati uitat|mai dureaza|"
|
||||
r"s-a rezolvat|ce se intampla|vreo veste|veste|noutati|s-a miscat ceva|"
|
||||
r"aveti un raspuns)"
|
||||
)
|
||||
|
||||
|
||||
def fel_completare(text: str) -> str:
|
||||
"""`"urgenta"` / `"stare"` / `"detaliu"` — ce vrea omul cu mesajul asta.
|
||||
|
||||
Trei lucruri diferite primeau acelasi raspuns sablon („am adaugat si asta la
|
||||
M-…"): un semnal de urgenta, o intrebare la care Maria nici nu raspundea, si un
|
||||
detaliu in plus. Ordinea conteaza: „urgent, cat mai dureaza?" e intai urgenta.
|
||||
"""
|
||||
t = fold_text(text)
|
||||
if _URGENTA.search(t):
|
||||
return "urgenta"
|
||||
if _STARE.search(t):
|
||||
return "stare"
|
||||
return "detaliu"
|
||||
|
||||
|
||||
def fold_text(text: str) -> str:
|
||||
return rank.fold(text or "")
|
||||
|
||||
|
||||
# Confirmari rotite: trei mesaje identice unul dupa altul suna a robot.
|
||||
_CONFIRMARI = (
|
||||
"Am adaugat si asta la {ref}.",
|
||||
"Notat — am trecut si asta in {ref}.",
|
||||
"Am completat {ref} cu ce mi-ai spus.",
|
||||
)
|
||||
|
||||
URGENTA_MARCATA = (
|
||||
"Am marcat problema ca urgenta si am anuntat echipa ({ref}). "
|
||||
"Daca intre timp te blocheaza complet, spune-mi."
|
||||
)
|
||||
|
||||
|
||||
def confirmare(ref: str, a_cata: int) -> str:
|
||||
return _CONFIRMARI[a_cata % len(_CONFIRMARI)].format(ref=ref)
|
||||
|
||||
|
||||
def minute_text(n: int) -> str:
|
||||
"""„3 minute", dar „25 de minute" — regula romaneasca a lui „de" peste 19."""
|
||||
return f"{n} minute" if n < 20 else f"{n} de minute"
|
||||
|
||||
|
||||
# Cand omul intreaba a doua oara si nu s-a schimbat nimic, nu repetam acelasi text.
|
||||
_ASTEPTARE = (
|
||||
"Inca nimic nou de la echipa. Te anunt imediat ce am un raspuns.",
|
||||
"Inca nu mi-a raspuns nimeni. Problema e in lista lor, cu {ref}.",
|
||||
)
|
||||
|
||||
|
||||
def raspuns_stare(ref: str, minute: int, reamintit: bool, telefon: str = "",
|
||||
a_cata: int = 0) -> str:
|
||||
"""Ce se raspunde la „cat mai dureaza?" — cu ce stim, nu cu formule.
|
||||
|
||||
Peste o jumatate de ora fara raspuns, „echipa vede detaliul cand preia
|
||||
problema" nu mai e un raspuns onest: omul asteapta de o jumatate de ora si o
|
||||
stie mai bine decat noi.
|
||||
"""
|
||||
unde = f" la {telefon}" if telefon else ""
|
||||
if minute >= 30:
|
||||
return (
|
||||
f"Au trecut {minute_text(minute)} de cand am trimis problema ({ref}) si inca "
|
||||
f"nu mi-a raspuns nimeni. Nu vreau sa te tin cu vorbe: daca te blocheaza, "
|
||||
f"suna direct la suport{unde}."
|
||||
)
|
||||
if reamintit:
|
||||
return (
|
||||
f"Am trimis problema acum {minute_text(minute)} (referinta {ref}) si tocmai "
|
||||
f"am reamintit echipei. Inca nu am un raspuns de la ei."
|
||||
)
|
||||
if a_cata > 0:
|
||||
return _ASTEPTARE[(a_cata - 1) % len(_ASTEPTARE)].format(ref=ref)
|
||||
return (
|
||||
f"Am trimis problema acum {minute_text(minute)} (referinta {ref}) si inca nu am "
|
||||
f"un raspuns de la ei. Echipa e deja anuntata."
|
||||
)
|
||||
|
||||
@@ -67,32 +67,105 @@ def _escaladare(ref: str) -> None:
|
||||
json.dumps({"ref": ref, "text": "eroare initiala"}), encoding="utf-8")
|
||||
|
||||
|
||||
def test_raspunsul_despre_urgenta_intra_in_escaladarea_deschisa(monkeypatch):
|
||||
def _fara_suport(monkeypatch):
|
||||
import config
|
||||
monkeypatch.setattr(config, "get", lambda k, d=None: "" if k == "SUPPORT_JID"
|
||||
else config.DEFAULTS.get(k, d))
|
||||
|
||||
|
||||
def test_completarea_intra_in_escaladarea_deschisa(monkeypatch):
|
||||
import config
|
||||
import consumer
|
||||
|
||||
monkeypatch.setattr(config, "get", lambda k, d=None: "" if k == "SUPPORT_JID"
|
||||
else config.DEFAULTS.get(k, d))
|
||||
_fara_suport(monkeypatch)
|
||||
_escaladare("M-TEST-1")
|
||||
assert consumer.append_followup("M-TEST-1", {"id": "x"}, "ma blocheaza, nu pot factura")
|
||||
raspuns = consumer.completeaza("M-TEST-1", {"id": "x"}, "eram la salvarea unei facturi")
|
||||
assert "M-TEST-1" in raspuns
|
||||
|
||||
fisier = next((config.STATE_DIR / "escalations").glob("*-M-TEST-1.json"))
|
||||
record = json.loads(fisier.read_text(encoding="utf-8"))
|
||||
assert record["completari"][0]["text"] == "ma blocheaza, nu pot factura"
|
||||
assert record["completari"][0]["text"] == "eram la salvarea unei facturi"
|
||||
assert record["completari"][0]["fel"] == "detaliu"
|
||||
|
||||
|
||||
def test_completarile_se_aduna_nu_se_inlocuiesc(monkeypatch):
|
||||
"""Omul raspunde de mai multe ori; prima data nu inchide firul."""
|
||||
def test_completarile_se_aduna_si_nu_repeta_acelasi_text(monkeypatch):
|
||||
"""Trei confirmari identice una dupa alta suna a robot."""
|
||||
import config
|
||||
import consumer
|
||||
|
||||
monkeypatch.setattr(config, "get", lambda k, d=None: "" if k == "SUPPORT_JID"
|
||||
else config.DEFAULTS.get(k, d))
|
||||
_fara_suport(monkeypatch)
|
||||
_escaladare("M-TEST-3")
|
||||
consumer.append_followup("M-TEST-3", {"id": "a"}, "da, ma blocheaza")
|
||||
consumer.append_followup("M-TEST-3", {"id": "b"}, "eram la salvarea unei facturi")
|
||||
raspunsuri = [consumer.completeaza("M-TEST-3", {"id": str(i)}, t) for i, t in enumerate(
|
||||
["eram la facturi", "si la rapoarte", "si la import"])]
|
||||
assert len(set(raspunsuri)) == 3
|
||||
|
||||
fisier = next((config.STATE_DIR / "escalations").glob("*-M-TEST-3.json"))
|
||||
record = json.loads(fisier.read_text(encoding="utf-8"))
|
||||
assert [c["text"] for c in record["completari"]] == [
|
||||
"da, ma blocheaza", "eram la salvarea unei facturi"]
|
||||
assert len(record["completari"]) == 3
|
||||
|
||||
|
||||
def test_urgenta_marcheaza_escaladarea_si_anunta(monkeypatch):
|
||||
import config
|
||||
import consumer
|
||||
|
||||
trimise = []
|
||||
monkeypatch.setattr(consumer, "_notifica_suport",
|
||||
lambda text: trimise.append(text) or True)
|
||||
_escaladare("M-TEST-U")
|
||||
raspuns = consumer.completeaza("M-TEST-U", {"id": "u"}, "Este foarte urgent, ma blocheaza")
|
||||
|
||||
record = json.loads(next((config.STATE_DIR / "escalations").glob("*-M-TEST-U.json"))
|
||||
.read_text(encoding="utf-8"))
|
||||
assert record["urgenta"] is True
|
||||
assert record["completari"][0]["fel"] == "urgenta"
|
||||
assert trimise and trimise[0].startswith("[Maria] URGENT")
|
||||
assert "urgenta" in raspuns.lower()
|
||||
|
||||
|
||||
def test_intrebarea_de_stare_primeste_un_raspuns_nu_o_confirmare(monkeypatch):
|
||||
"""„Nu m-a contactat nimeni. Cat mai dureaza?" primea „am adaugat si asta"."""
|
||||
import config
|
||||
import consumer
|
||||
|
||||
trimise = []
|
||||
monkeypatch.setattr(consumer, "_notifica_suport",
|
||||
lambda text: trimise.append(text) or True)
|
||||
_escaladare("M-TEST-S")
|
||||
raspuns = consumer.completeaza("M-TEST-S", {"id": "s"},
|
||||
"Nu m-a contactat nimeni. Cat mai dureaza?")
|
||||
assert "am adaugat" not in raspuns.lower()
|
||||
assert "M-TEST-S" in raspuns
|
||||
assert trimise and "intreaba" in trimise[0]
|
||||
|
||||
# a doua intrebare la un minut distanta nu mai suna telefonul echipei
|
||||
trimise.clear()
|
||||
consumer.completeaza("M-TEST-S", {"id": "s2"}, "tot nimic")
|
||||
assert not trimise
|
||||
|
||||
|
||||
def test_dupa_o_jumatate_de_ora_maria_o_spune_pe_fata():
|
||||
import triaj
|
||||
text = triaj.raspuns_stare("M-1", 42, False, telefon="0241 000 000")
|
||||
assert "42" in text and "0241 000 000" in text
|
||||
assert "nu mi-a raspuns nimeni" in text
|
||||
|
||||
|
||||
def test_fel_completare():
|
||||
import triaj
|
||||
assert triaj.fel_completare("Este foarte urgent") == "urgenta"
|
||||
assert triaj.fel_completare("ma blocheaza complet") == "urgenta"
|
||||
assert triaj.fel_completare("Cat mai dureaza?") == "stare"
|
||||
assert triaj.fel_completare("Tot nimic") == "stare"
|
||||
assert triaj.fel_completare("eram la salvarea unei facturi") == "detaliu"
|
||||
# ordinea conteaza: urgenta bate intrebarea de stare
|
||||
assert triaj.fel_completare("urgent, cat mai dureaza?") == "urgenta"
|
||||
|
||||
|
||||
def test_a_doua_intrebare_de_stare_nu_repeta_acelasi_text():
|
||||
import triaj
|
||||
intai = triaj.raspuns_stare("M-1", 10, False, a_cata=0)
|
||||
apoi = triaj.raspuns_stare("M-1", 11, False, a_cata=1)
|
||||
assert intai != apoi
|
||||
# „acum 10 minute", nu „acum 10 de minute"
|
||||
assert "10 minute" in intai and "10 de minute" not in intai
|
||||
assert triaj.minute_text(25) == "25 de minute"
|
||||
|
||||
Reference in New Issue
Block a user