회기 무발화 0턴 분리, 자기예측 락 불변식 및 TDD 회귀 검증 완료
Some checks failed
API contract / OpenAPI type drift (push) Failing after 3m27s
Some checks failed
API contract / OpenAPI type drift (push) Failing after 3m27s
This commit is contained in:
parent
a479db7a5a
commit
a0311c5957
100 changed files with 4884 additions and 11210 deletions
100
apps/api/app/session_persistence_values.py
Normal file
100
apps/api/app/session_persistence_values.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
"""세션 영속성에서 공유하는 정규화·마스킹 도우미."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
from .services import guardrail
|
||||
|
||||
|
||||
def _ts(value: datetime | None) -> float | None:
|
||||
if value is None:
|
||||
return None
|
||||
if value.tzinfo is None:
|
||||
value = value.replace(tzinfo=timezone.utc)
|
||||
return value.timestamp()
|
||||
|
||||
|
||||
def _clean_text(value: Any) -> str | None:
|
||||
if value is None:
|
||||
return None
|
||||
text = str(value).strip()
|
||||
return text or None
|
||||
|
||||
|
||||
def _clean_masked_text(value: Any) -> str | None:
|
||||
text = _clean_text(value)
|
||||
if text is None:
|
||||
return None
|
||||
masked = guardrail.mask_pii(text).text_masked.strip()
|
||||
return masked or None
|
||||
|
||||
|
||||
def _clean_role_masked_text(
|
||||
value: Any,
|
||||
*,
|
||||
counselor_identity: str | None = None,
|
||||
client_identity: str | None = None,
|
||||
synthetic_generated: bool = False,
|
||||
) -> str | None:
|
||||
text = _clean_text(value)
|
||||
if text is None:
|
||||
return None
|
||||
masked = guardrail.mask_role_identities(
|
||||
text,
|
||||
counselor_identity=counselor_identity,
|
||||
client_identity=client_identity,
|
||||
synthetic_generated=synthetic_generated,
|
||||
).text_masked.strip()
|
||||
return masked or None
|
||||
|
||||
|
||||
def _mask_json_text_values(
|
||||
value: Any,
|
||||
*,
|
||||
counselor_identity: str | None = None,
|
||||
client_identity: str | None = None,
|
||||
synthetic_generated: bool = False,
|
||||
) -> Any:
|
||||
if isinstance(value, str):
|
||||
return (
|
||||
_clean_role_masked_text(
|
||||
value,
|
||||
counselor_identity=counselor_identity,
|
||||
client_identity=client_identity,
|
||||
synthetic_generated=synthetic_generated,
|
||||
)
|
||||
or ""
|
||||
)
|
||||
if isinstance(value, dict):
|
||||
return {
|
||||
key: _mask_json_text_values(
|
||||
child,
|
||||
counselor_identity=counselor_identity,
|
||||
client_identity=client_identity,
|
||||
synthetic_generated=synthetic_generated,
|
||||
)
|
||||
for key, child in value.items()
|
||||
}
|
||||
if isinstance(value, list):
|
||||
return [
|
||||
_mask_json_text_values(
|
||||
child,
|
||||
counselor_identity=counselor_identity,
|
||||
client_identity=client_identity,
|
||||
synthetic_generated=synthetic_generated,
|
||||
)
|
||||
for child in value
|
||||
]
|
||||
if isinstance(value, tuple):
|
||||
return [
|
||||
_mask_json_text_values(
|
||||
child,
|
||||
counselor_identity=counselor_identity,
|
||||
client_identity=client_identity,
|
||||
synthetic_generated=synthetic_generated,
|
||||
)
|
||||
for child in value
|
||||
]
|
||||
return value
|
||||
Loading…
Add table
Add a link
Reference in a new issue