fix(translate): exclude key columns from cache hash — only text + context fields

- _compute_source_hash now accepts context_keys parameter
- source_data is filtered to only include context-relevant fields (not row_id, primary keys)
- If no context_columns configured, hash is based on source_text + dict_hash + config_hash
- This ensures identical text in different rows produces a cache hit
This commit is contained in:
2026-05-16 09:33:15 +03:00
parent b466ac6211
commit 4f6544ab1a
2 changed files with 23 additions and 5 deletions

View File

@@ -127,18 +127,33 @@ def _enforce_dictionary(
# #region _compute_source_hash [TYPE Function]
# @BRIEF Compute deterministic cache key for a source row.
# SHA256 of (source_text + source_data + dict_config_ctx) so that changing
# the text, context, dictionary snapshot, or job config produces a new key.
# SHA256 of (source_text + context_fields + dict_snapshot_hash + config_hash).
# Key columns (row_id, primary keys) are EXCLUDED — only the text content
# and meaningful context affect the hash. This ensures identical text with
# different row identifiers still produces a cache hit.
def _compute_source_hash(
source_text: str,
source_data: dict | None,
dict_snapshot_hash: str | None,
config_hash: str | None,
context_keys: list[str] | None = None,
) -> str:
"""Deterministic cache key for a translation source row."""
"""Deterministic cache key for a translation source row.
Only includes source_text and context-relevant fields from source_data.
Key/identifier columns are excluded so identical text in different rows hits cache.
"""
# Extract only context-relevant fields from source_data (not keys/identifiers)
context_data: dict[str, str] = {}
if source_data and context_keys:
for key in context_keys:
val = source_data.get(key)
if val is not None:
context_data[key] = str(val)
payload = json.dumps({
"text": source_text,
"data": source_data,
"ctx": context_data, # only context columns, no key/row_id
"dict_hash": dict_snapshot_hash or "",
"config_hash": config_hash or "",
}, sort_keys=True, ensure_ascii=False)
@@ -719,9 +734,12 @@ class TranslationExecutor:
if not source_text:
continue
source_data = row.get("source_data")
# Build context_keys from job config (exclude key columns from hash)
ctx_keys = list(job.context_columns or [])
source_hash = _compute_source_hash(
source_text, source_data,
dict_snapshot_hash, config_hash,
context_keys=ctx_keys,
)
row["_source_hash"] = source_hash
cached = _check_translation_cache(self.db, source_hash)