feat(doantu): constrain target pool to phow2sim rank 100-1000

Default /random pulled from the full Vietnamese corpus (rank 40k+ words
like "sa_mạc_hoá" showed up), which made rounds unplayable for casual
speakers. Filter targets to min_rank=100, max_rank=1000 so words stay
recognizable.
This commit is contained in:
2026-04-23 12:09:56 +07:00
parent 919fa038d5
commit 8024dbfd40
2 changed files with 7 additions and 2 deletions
+3 -1
View File
@@ -27,7 +27,9 @@ ignored (no cost, no stat inflation).
Target words + similarity scores come from our self-hosted **phow2sim**
instance (default: `https://phow2sim.sg.miti99.com`). Wraps two endpoints:
- `GET /random` — pick a secret Vietnamese word at round start.
- `GET /random` — pick a secret Vietnamese word at round start. Targets
are filtered to the top-frequency band (`min_rank=100`, `max_rank=1000`)
so rounds stay guessable for casual players.
- `GET /similarity?a=…&b=…` — cosine similarity + canonical forms +
`in_vocab_a` / `in_vocab_b` flags.
+4 -1
View File
@@ -19,6 +19,9 @@ import { renderBoard, renderGuess } from "./render.js";
import { clearGame, loadGame, loadStats, recordResult, saveGame } from "./state.js";
const UPSTREAM_FAIL = "⚠️ Upstream hiccup — try again in a few seconds.";
// Keep targets inside the top-frequency band so the game stays guessable.
// phow2sim ranks by corpus frequency; lower rank = more common.
const RANDOM_FILTERS = { min_rank: 100, max_rank: 1000 };
function getSubject(ctx) {
const type = ctx.chat?.type;
@@ -43,7 +46,7 @@ function logFail(stage, err) {
}
async function startFreshGame(db, client, subject) {
const picked = await client.randomWord();
const picked = await client.randomWord(RANDOM_FILTERS);
const target = String(picked?.word ?? "").toLowerCase();
if (!target) throw new UpstreamError("empty target from randomWord");
const fresh = { target, startedAt: null, solved: false, guesses: [] };