Spaces:
Paused
Paused
Upload 3 files
Browse files- groqai.py +79 -25
- humanizer.py +32 -12
- meaning.py +3 -0
groqai.py
CHANGED
|
@@ -12,6 +12,8 @@ If Groq is unreachable or out of quota, the local checks alone are used (as befo
|
|
| 12 |
|
| 13 |
Settings (Space → Settings → Variables and secrets):
|
| 14 |
GROQ_API_KEY secret — from https://console.groq.com/keys
|
|
|
|
|
|
|
| 15 |
GROQ_MODELS preference list, first one available on your key is used
|
| 16 |
(default: openai/gpt-oss-120b, llama-3.3-70b-versatile, qwen/qwen3.8-27b, openai/gpt-oss-20b)
|
| 17 |
GROQ_BATCH sentence pairs per request (default 10)
|
|
@@ -25,8 +27,19 @@ import time
|
|
| 25 |
|
| 26 |
import textparse as TP
|
| 27 |
|
| 28 |
-
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
URL = "https://api.groq.com/openai/v1"
|
| 31 |
PREF = [m.strip() for m in os.getenv(
|
| 32 |
"GROQ_MODELS", "openai/gpt-oss-120b,llama-3.3-70b-versatile,qwen/qwen3.8-27b,openai/gpt-oss-20b").split(",")
|
|
@@ -34,7 +47,7 @@ PREF = [m.strip() for m in os.getenv(
|
|
| 34 |
BATCH = max(1, int(os.getenv("GROQ_BATCH", "12")))
|
| 35 |
MAX_WAIT = float(os.getenv("GROQ_MAX_WAIT", "60"))
|
| 36 |
|
| 37 |
-
_lock = threading.
|
| 38 |
_models = None # models available on this key (ordered by preference)
|
| 39 |
_down_until = 0.0 # daily quota exhausted -> skip Groq until then
|
| 40 |
STATS = {"calls": 0, "checked": 0, "ok": 0, "fixed": 0, "rejected": 0, "errors": 0, "tokens": 0,
|
|
@@ -45,12 +58,37 @@ class Unavailable(Exception):
|
|
| 45 |
"""Groq cannot be used right now (quota, network, bad key) — caller falls back to the local model."""
|
| 46 |
|
| 47 |
|
| 48 |
-
def _headers():
|
| 49 |
-
return {"Authorization": f"Bearer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
|
| 52 |
def available():
|
| 53 |
-
return ENABLED and time.time() >= _down_until
|
| 54 |
|
| 55 |
|
| 56 |
def _model_list():
|
|
@@ -59,7 +97,7 @@ def _model_list():
|
|
| 59 |
if _models is None:
|
| 60 |
import httpx
|
| 61 |
try:
|
| 62 |
-
r = httpx.get(URL + "/models", headers=_headers(), timeout=20)
|
| 63 |
if r.status_code == 401:
|
| 64 |
STATS["last_error"] = "Groq key rejected (401) — check GROQ_API_KEY."
|
| 65 |
raise Unavailable(STATS["last_error"])
|
|
@@ -81,7 +119,7 @@ def _drop_model(model):
|
|
| 81 |
|
| 82 |
|
| 83 |
def status():
|
| 84 |
-
if not
|
| 85 |
return "Groq check is OFF — add the GROQ_API_KEY secret (Parrot output is checked by the local rules only)."
|
| 86 |
if not ENABLED:
|
| 87 |
return "Groq is disabled (GROQ_ENABLED=0)."
|
|
@@ -89,14 +127,20 @@ def status():
|
|
| 89 |
m = (_models or PREF)[0]
|
| 90 |
down = f" · quota pause until {time.strftime('%H:%M UTC', time.gmtime(_down_until))}" \
|
| 91 |
if time.time() < _down_until else ""
|
| 92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
f"{s['ok']} fine as written, {s['fixed']} repaired, {s['rejected']} rejected (original kept); "
|
| 94 |
f"~{s['tokens']:,} tokens."
|
| 95 |
+ (f" Last error: {s['last_error']}" if s["last_error"] else ""))
|
| 96 |
|
| 97 |
|
| 98 |
def _chat(messages, temperature, max_tokens):
|
| 99 |
-
"""One chat completion (JSON mode).
|
|
|
|
|
|
|
| 100 |
global _down_until
|
| 101 |
import httpx
|
| 102 |
if not available():
|
|
@@ -108,9 +152,18 @@ def _chat(messages, temperature, max_tokens):
|
|
| 108 |
"response_format": {"type": "json_object"}}
|
| 109 |
if "gpt-oss" in model:
|
| 110 |
body["reasoning_effort"] = "low"
|
| 111 |
-
for attempt in range(8):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
try:
|
| 113 |
-
r = httpx.post(URL + "/chat/completions", json=body, headers=_headers(), timeout=120)
|
| 114 |
except Exception as err:
|
| 115 |
STATS["errors"] += 1
|
| 116 |
STATS["last_error"] = f"network: {err}"
|
|
@@ -118,26 +171,27 @@ def _chat(messages, temperature, max_tokens):
|
|
| 118 |
raise Unavailable(str(err))
|
| 119 |
time.sleep(2 * (attempt + 1))
|
| 120 |
continue
|
|
|
|
|
|
|
| 121 |
txt = r.text[:400]
|
| 122 |
if r.status_code == 429:
|
| 123 |
try:
|
| 124 |
ra = float(r.headers.get("retry-after") or 5)
|
| 125 |
except ValueError:
|
| 126 |
ra = 5.0
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
raise Unavailable("Groq rate limit")
|
| 132 |
-
time.sleep(ra)
|
| 133 |
-
waited += ra
|
| 134 |
-
continue
|
| 135 |
if r.status_code == 401:
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
|
|
|
|
|
|
|
|
|
| 139 |
if r.status_code in (400, 404) and "model" in txt.lower() and any(
|
| 140 |
-
|
| 141 |
"no access", "deprecated")):
|
| 142 |
_drop_model(model)
|
| 143 |
nxt = _model_list()[0]
|
|
@@ -240,7 +294,7 @@ def _check_batch(pairs, glossary):
|
|
| 240 |
return _parse(content, len(pairs))
|
| 241 |
|
| 242 |
|
| 243 |
-
PARALLEL = max(1, int(os.getenv("GROQ_PARALLEL",
|
| 244 |
|
| 245 |
|
| 246 |
def review(pairs, glossary, progress=None, lo=0.85, hi=0.9):
|
|
|
|
| 12 |
|
| 13 |
Settings (Space → Settings → Variables and secrets):
|
| 14 |
GROQ_API_KEY secret — from https://console.groq.com/keys
|
| 15 |
+
GROQ_API_KEY_2, GROQ_API_KEY_3 ... (up to _9) or GROQ_API_KEYS="k1,k2,k3": more keys. Requests are spread over
|
| 16 |
+
all keys (round robin); a key that hits its rate limit is paused and the next key is used.
|
| 17 |
GROQ_MODELS preference list, first one available on your key is used
|
| 18 |
(default: openai/gpt-oss-120b, llama-3.3-70b-versatile, qwen/qwen3.8-27b, openai/gpt-oss-20b)
|
| 19 |
GROQ_BATCH sentence pairs per request (default 10)
|
|
|
|
| 27 |
|
| 28 |
import textparse as TP
|
| 29 |
|
| 30 |
+
def _read_keys():
|
| 31 |
+
"""GROQ_API_KEY, GROQ_API_KEY_2 ... GROQ_API_KEY_9 and/or GROQ_API_KEYS (comma separated), de-duplicated."""
|
| 32 |
+
keys = [k.strip() for k in os.getenv("GROQ_API_KEYS", "").split(",")]
|
| 33 |
+
keys += [os.getenv("GROQ_API_KEY", "")] + [os.getenv(f"GROQ_API_KEY_{i}", "") for i in range(2, 10)]
|
| 34 |
+
return list(dict.fromkeys(k.strip() for k in keys if k and k.strip()))
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
KEYS = _read_keys()
|
| 38 |
+
KEY = KEYS[0] if KEYS else ""
|
| 39 |
+
ENABLED = bool(KEYS) and os.getenv("GROQ_ENABLED", "1") != "0"
|
| 40 |
+
# per key: paused until (rate limit / daily quota / rejected key), requests sent, last error
|
| 41 |
+
_KEY_STATE = [{"until": 0.0, "calls": 0, "err": ""} for _ in KEYS]
|
| 42 |
+
_rr = [0] # round-robin position
|
| 43 |
URL = "https://api.groq.com/openai/v1"
|
| 44 |
PREF = [m.strip() for m in os.getenv(
|
| 45 |
"GROQ_MODELS", "openai/gpt-oss-120b,llama-3.3-70b-versatile,qwen/qwen3.8-27b,openai/gpt-oss-20b").split(",")
|
|
|
|
| 47 |
BATCH = max(1, int(os.getenv("GROQ_BATCH", "12")))
|
| 48 |
MAX_WAIT = float(os.getenv("GROQ_MAX_WAIT", "60"))
|
| 49 |
|
| 50 |
+
_lock = threading.RLock()
|
| 51 |
_models = None # models available on this key (ordered by preference)
|
| 52 |
_down_until = 0.0 # daily quota exhausted -> skip Groq until then
|
| 53 |
STATS = {"calls": 0, "checked": 0, "ok": 0, "fixed": 0, "rejected": 0, "errors": 0, "tokens": 0,
|
|
|
|
| 58 |
"""Groq cannot be used right now (quota, network, bad key) — caller falls back to the local model."""
|
| 59 |
|
| 60 |
|
| 61 |
+
def _headers(k=0):
|
| 62 |
+
return {"Authorization": f"Bearer {KEYS[k] if KEYS else ''}", "Content-Type": "application/json"}
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def _pick_key():
|
| 66 |
+
"""Next usable key (round robin, so the load is spread over all keys); None if all are paused."""
|
| 67 |
+
now = time.time()
|
| 68 |
+
with _lock:
|
| 69 |
+
n = len(KEYS)
|
| 70 |
+
for step in range(n):
|
| 71 |
+
k = (_rr[0] + step) % n
|
| 72 |
+
if _KEY_STATE[k]["until"] <= now:
|
| 73 |
+
_rr[0] = (k + 1) % n
|
| 74 |
+
return k
|
| 75 |
+
return None
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def _pause_key(k, seconds, why):
|
| 79 |
+
with _lock:
|
| 80 |
+
_KEY_STATE[k]["until"] = max(_KEY_STATE[k]["until"], time.time() + seconds)
|
| 81 |
+
_KEY_STATE[k]["err"] = why
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def _next_free_in():
|
| 85 |
+
"""Seconds until the first paused key is usable again."""
|
| 86 |
+
now = time.time()
|
| 87 |
+
return max(0.0, min((st["until"] for st in _KEY_STATE), default=0.0) - now)
|
| 88 |
|
| 89 |
|
| 90 |
def available():
|
| 91 |
+
return ENABLED and time.time() >= _down_until and _next_free_in() <= MAX_WAIT
|
| 92 |
|
| 93 |
|
| 94 |
def _model_list():
|
|
|
|
| 97 |
if _models is None:
|
| 98 |
import httpx
|
| 99 |
try:
|
| 100 |
+
r = httpx.get(URL + "/models", headers=_headers(_pick_key() or 0), timeout=20)
|
| 101 |
if r.status_code == 401:
|
| 102 |
STATS["last_error"] = "Groq key rejected (401) — check GROQ_API_KEY."
|
| 103 |
raise Unavailable(STATS["last_error"])
|
|
|
|
| 119 |
|
| 120 |
|
| 121 |
def status():
|
| 122 |
+
if not KEYS:
|
| 123 |
return "Groq check is OFF — add the GROQ_API_KEY secret (Parrot output is checked by the local rules only)."
|
| 124 |
if not ENABLED:
|
| 125 |
return "Groq is disabled (GROQ_ENABLED=0)."
|
|
|
|
| 127 |
m = (_models or PREF)[0]
|
| 128 |
down = f" · quota pause until {time.strftime('%H:%M UTC', time.gmtime(_down_until))}" \
|
| 129 |
if time.time() < _down_until else ""
|
| 130 |
+
now = time.time()
|
| 131 |
+
keys = " · ".join(f"key {i + 1}: {st['calls']} calls" + (f", paused {int(st['until'] - now)}s ({st['err']})"
|
| 132 |
+
if st["until"] > now else "")
|
| 133 |
+
for i, st in enumerate(_KEY_STATE))
|
| 134 |
+
return (f"Groq quality check is ON ({m}), {len(KEYS)} key(s) [{keys}]{down}. Since restart: {s['checked']} Parrot sentences checked �� "
|
| 135 |
f"{s['ok']} fine as written, {s['fixed']} repaired, {s['rejected']} rejected (original kept); "
|
| 136 |
f"~{s['tokens']:,} tokens."
|
| 137 |
+ (f" Last error: {s['last_error']}" if s["last_error"] else ""))
|
| 138 |
|
| 139 |
|
| 140 |
def _chat(messages, temperature, max_tokens):
|
| 141 |
+
"""One chat completion (JSON mode). With several keys, a rate-limited key is paused and the request moves to
|
| 142 |
+
the next key at once; it waits only when every key is paused (short limits), and raises Unavailable when all
|
| 143 |
+
keys are out for longer than GROQ_MAX_WAIT."""
|
| 144 |
global _down_until
|
| 145 |
import httpx
|
| 146 |
if not available():
|
|
|
|
| 152 |
"response_format": {"type": "json_object"}}
|
| 153 |
if "gpt-oss" in model:
|
| 154 |
body["reasoning_effort"] = "low"
|
| 155 |
+
for attempt in range(8 + 2 * len(KEYS)):
|
| 156 |
+
k = _pick_key()
|
| 157 |
+
if k is None: # every key is paused: wait for the first one, if short
|
| 158 |
+
wait = _next_free_in()
|
| 159 |
+
if wait > MAX_WAIT or waited + wait > MAX_WAIT:
|
| 160 |
+
STATS["last_error"] = "rate limit on all Groq keys"
|
| 161 |
+
raise Unavailable("Groq rate limit (all keys)")
|
| 162 |
+
time.sleep(wait + 0.2)
|
| 163 |
+
waited += wait
|
| 164 |
+
continue
|
| 165 |
try:
|
| 166 |
+
r = httpx.post(URL + "/chat/completions", json=body, headers=_headers(k), timeout=120)
|
| 167 |
except Exception as err:
|
| 168 |
STATS["errors"] += 1
|
| 169 |
STATS["last_error"] = f"network: {err}"
|
|
|
|
| 171 |
raise Unavailable(str(err))
|
| 172 |
time.sleep(2 * (attempt + 1))
|
| 173 |
continue
|
| 174 |
+
with _lock:
|
| 175 |
+
_KEY_STATE[k]["calls"] += 1
|
| 176 |
txt = r.text[:400]
|
| 177 |
if r.status_code == 429:
|
| 178 |
try:
|
| 179 |
ra = float(r.headers.get("retry-after") or 5)
|
| 180 |
except ValueError:
|
| 181 |
ra = 5.0
|
| 182 |
+
daily = "per day" in txt.lower()
|
| 183 |
+
_pause_key(k, min(max(ra, 60), 6 * 3600) if daily else ra, "daily quota" if daily else "rate limit")
|
| 184 |
+
STATS["last_error"] = f"rate limit (key {k + 1}): {txt[:160]}"
|
| 185 |
+
continue # next key at once
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
if r.status_code == 401:
|
| 187 |
+
_pause_key(k, 3600, "key rejected (401)")
|
| 188 |
+
STATS["last_error"] = f"Groq key {k + 1} rejected (401) — check that secret."
|
| 189 |
+
if all(st["err"].startswith("key rejected") for st in _KEY_STATE):
|
| 190 |
+
_down_until = time.time() + 600
|
| 191 |
+
raise Unavailable(STATS["last_error"])
|
| 192 |
+
continue
|
| 193 |
if r.status_code in (400, 404) and "model" in txt.lower() and any(
|
| 194 |
+
w in txt.lower() for w in ("decommission", "not found", "does not exist", "not available",
|
| 195 |
"no access", "deprecated")):
|
| 196 |
_drop_model(model)
|
| 197 |
nxt = _model_list()[0]
|
|
|
|
| 294 |
return _parse(content, len(pairs))
|
| 295 |
|
| 296 |
|
| 297 |
+
PARALLEL = max(1, int(os.getenv("GROQ_PARALLEL", str(min(12, 4 * max(1, len(KEYS)))))))
|
| 298 |
|
| 299 |
|
| 300 |
def review(pairs, glossary, progress=None, lo=0.85, hi=0.9):
|
humanizer.py
CHANGED
|
@@ -509,6 +509,7 @@ def _paraphrase_local(texts, temperature, progress=None, lo=0.15, hi=0.85, mode=
|
|
| 509 |
todo = list(range(len(sent_map)))
|
| 510 |
options, first_raw = [[] for _ in sent_map], [s for s, _, _ in sent_map]
|
| 511 |
extra_rounds = meaning_dropped = 0
|
|
|
|
| 512 |
for r in range(rounds):
|
| 513 |
if not todo:
|
| 514 |
break
|
|
@@ -520,17 +521,30 @@ def _paraphrase_local(texts, temperature, progress=None, lo=0.15, hi=0.85, mode=
|
|
| 520 |
extra_rounds += r > 0
|
| 521 |
for si in todo:
|
| 522 |
options[si], first_raw[si] = build(si)
|
| 523 |
-
#
|
| 524 |
pairs = [(si, o) for si in todo for o in options[si]]
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
|
|
|
|
|
|
|
|
|
| 532 |
for si in todo:
|
| 533 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 534 |
if not target:
|
| 535 |
break
|
| 536 |
todo = [si for si in todo
|
|
@@ -638,12 +652,18 @@ def _paraphrase_local(texts, temperature, progress=None, lo=0.15, hi=0.85, mode=
|
|
| 638 |
|
| 639 |
# final meaning check of what will actually be used (Groq rescues / repairs included)
|
| 640 |
final = [si for si in range(len(sent_map)) if chosen[si] and chosen[si].strip() != sent_map[si][0].strip()]
|
| 641 |
-
for si, k_ in zip(final, MEANING.keeps_meaning([(sent_map[si][0], chosen[si]) for si in final]
|
|
|
|
| 642 |
if not k_:
|
| 643 |
meaning_dropped += 1
|
| 644 |
chosen[si] = next((o for o in ranked[si] if o != chosen[si]), None) # already meaning-checked
|
| 645 |
-
if
|
| 646 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 647 |
|
| 648 |
sentences = [chosen[si] or s for si, (s, _, _) in enumerate(sent_map)]
|
| 649 |
changed = sum(1 for si, (s, _, _) in enumerate(sent_map) if sentences[si].strip() != s.strip())
|
|
|
|
| 509 |
todo = list(range(len(sent_map)))
|
| 510 |
options, first_raw = [[] for _ in sent_map], [s for s, _, _ in sent_map]
|
| 511 |
extra_rounds = meaning_dropped = 0
|
| 512 |
+
qstat = dict(n=0, meaning=0, fluency=0, second=0, sims=[])
|
| 513 |
for r in range(rounds):
|
| 514 |
if not todo:
|
| 515 |
break
|
|
|
|
| 521 |
extra_rounds += r > 0
|
| 522 |
for si in todo:
|
| 523 |
options[si], first_raw[si] = build(si)
|
| 524 |
+
# quality checks of every version: meaning (vs the original sentence) and fluency (well-formed English)
|
| 525 |
pairs = [(si, o) for si in todo for o in options[si]]
|
| 526 |
+
if pairs:
|
| 527 |
+
sims = MEANING.similarities([(sent_map[si][0], o) for si, o in pairs])
|
| 528 |
+
flu = FL.acceptable([(sent_map[si][0], o) for si, o in pairs])
|
| 529 |
+
keep_ = {}
|
| 530 |
+
for (si, o), sm, fl in zip(pairs, sims, flu):
|
| 531 |
+
keep_[(si, o)] = (sm >= MEANING.MIN_SIM and fl, sm, fl)
|
| 532 |
+
qstat["n"] += 1
|
| 533 |
+
qstat["meaning"] += sm < MEANING.MIN_SIM
|
| 534 |
+
qstat["fluency"] += not fl
|
| 535 |
+
qstat["sims"].append(sm)
|
| 536 |
for si in todo:
|
| 537 |
+
good = [o for o in options[si] if keep_[(si, o)][0]]
|
| 538 |
+
if not good and options[si]:
|
| 539 |
+
# second chance: no version passed both checks -> keep the closest-meaning version that is
|
| 540 |
+
# fluent English and only slightly below the meaning threshold
|
| 541 |
+
soft = [(keep_[(si, o)][1], o) for o in options[si]
|
| 542 |
+
if keep_[(si, o)][2] and keep_[(si, o)][1] >= MEANING.SOFT_SIM]
|
| 543 |
+
if soft:
|
| 544 |
+
good = [max(soft)[1]]
|
| 545 |
+
qstat["second"] += 1
|
| 546 |
+
meaning_dropped += len(options[si]) - len(good)
|
| 547 |
+
options[si] = good
|
| 548 |
if not target:
|
| 549 |
break
|
| 550 |
todo = [si for si in todo
|
|
|
|
| 652 |
|
| 653 |
# final meaning check of what will actually be used (Groq rescues / repairs included)
|
| 654 |
final = [si for si in range(len(sent_map)) if chosen[si] and chosen[si].strip() != sent_map[si][0].strip()]
|
| 655 |
+
for si, k_ in zip(final, MEANING.keeps_meaning([(sent_map[si][0], chosen[si]) for si in final],
|
| 656 |
+
min_sim=MEANING.SOFT_SIM)):
|
| 657 |
if not k_:
|
| 658 |
meaning_dropped += 1
|
| 659 |
chosen[si] = next((o for o in ranked[si] if o != chosen[si]), None) # already meaning-checked
|
| 660 |
+
if qstat["n"]:
|
| 661 |
+
import statistics as _st
|
| 662 |
+
med = _st.median(qstat["sims"]) if qstat["sims"] else 0
|
| 663 |
+
print(f"[humanizer] quality checks: {qstat['n']} versions | below meaning {MEANING.MIN_SIM:.2f}: "
|
| 664 |
+
f"{qstat['meaning']} (median similarity {med:.2f}) | not fluent: {qstat['fluency']} | "
|
| 665 |
+
f"rejected in total: {meaning_dropped} | sentences saved by second chance: {qstat['second']}",
|
| 666 |
+
flush=True)
|
| 667 |
|
| 668 |
sentences = [chosen[si] or s for si, (s, _, _) in enumerate(sent_map)]
|
| 669 |
changed = sum(1 for si, (s, _, _) in enumerate(sent_map) if sentences[si].strip() != s.strip())
|
meaning.py
CHANGED
|
@@ -12,6 +12,8 @@ message is printed once, so the app keeps working.
|
|
| 12 |
Space variables:
|
| 13 |
MEANING_MODEL default sentence-transformers/all-MiniLM-L6-v2
|
| 14 |
MEANING_MIN default 0.80 (raise to be stricter, lower if too many good rewrites are rejected)
|
|
|
|
|
|
|
| 15 |
MEANING_CHECK default 1 (0 turns the check off)
|
| 16 |
"""
|
| 17 |
import os
|
|
@@ -19,6 +21,7 @@ import threading
|
|
| 19 |
|
| 20 |
MODEL_ID = os.environ.get("MEANING_MODEL", "sentence-transformers/all-MiniLM-L6-v2")
|
| 21 |
MIN_SIM = float(os.environ.get("MEANING_MIN", "0.80"))
|
|
|
|
| 22 |
ENABLED = os.environ.get("MEANING_CHECK", "1") != "0"
|
| 23 |
BATCH = 64
|
| 24 |
|
|
|
|
| 12 |
Space variables:
|
| 13 |
MEANING_MODEL default sentence-transformers/all-MiniLM-L6-v2
|
| 14 |
MEANING_MIN default 0.80 (raise to be stricter, lower if too many good rewrites are rejected)
|
| 15 |
+
MEANING_SOFT default 0.72 a sentence with no version above MEANING_MIN may keep its closest fluent version
|
| 16 |
+
if it reaches this similarity
|
| 17 |
MEANING_CHECK default 1 (0 turns the check off)
|
| 18 |
"""
|
| 19 |
import os
|
|
|
|
| 21 |
|
| 22 |
MODEL_ID = os.environ.get("MEANING_MODEL", "sentence-transformers/all-MiniLM-L6-v2")
|
| 23 |
MIN_SIM = float(os.environ.get("MEANING_MIN", "0.80"))
|
| 24 |
+
SOFT_SIM = float(os.environ.get("MEANING_SOFT", "0.72")) # second chance when no version reaches MIN_SIM
|
| 25 |
ENABLED = os.environ.get("MEANING_CHECK", "1") != "0"
|
| 26 |
BATCH = 64
|
| 27 |
|