2026-03-31 23:55:26 +08:00
|
|
|
|
"""
|
|
|
|
|
|
从用户档案「职业」等文本推断访谈/叙事语气维度(干部形、军队形)。
|
|
|
|
|
|
与 chat_interview_persona(温柔倾听等)正交,可叠加。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
|
|
from typing import Final, Literal
|
|
|
|
|
|
|
|
|
|
|
|
BackgroundVoice = Literal["default", "cadre", "military"]
|
|
|
|
|
|
|
|
|
|
|
|
# 军队系优先:含「军、部队」等则走军队形,避免与泛「干部」冲突。
|
|
|
|
|
|
_MILITARY_NEEDLES: Final[tuple[str, ...]] = (
|
|
|
|
|
|
"军人",
|
|
|
|
|
|
"军官",
|
|
|
|
|
|
"士兵",
|
|
|
|
|
|
"部队",
|
|
|
|
|
|
"入伍",
|
|
|
|
|
|
"服役",
|
|
|
|
|
|
"退伍",
|
|
|
|
|
|
"转业",
|
|
|
|
|
|
"武警",
|
|
|
|
|
|
"解放军",
|
|
|
|
|
|
"陆军",
|
|
|
|
|
|
"海军",
|
|
|
|
|
|
"空军",
|
|
|
|
|
|
"火箭军",
|
|
|
|
|
|
"军区",
|
|
|
|
|
|
"军营",
|
|
|
|
|
|
"军校",
|
|
|
|
|
|
"文职干部",
|
|
|
|
|
|
"军队文职",
|
|
|
|
|
|
"现役",
|
|
|
|
|
|
"预备役",
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 干部/机关系(避免过短词误判:如「机关」→机关枪、「主任」→班主任)
|
|
|
|
|
|
_CADRE_NEEDLES: Final[tuple[str, ...]] = (
|
|
|
|
|
|
"公务员",
|
|
|
|
|
|
"党政机关",
|
|
|
|
|
|
"党政",
|
|
|
|
|
|
"组织部",
|
|
|
|
|
|
"党委书记",
|
|
|
|
|
|
"党组书记",
|
|
|
|
|
|
"书记",
|
|
|
|
|
|
"处长",
|
|
|
|
|
|
"科长",
|
|
|
|
|
|
"局长",
|
|
|
|
|
|
"厅长",
|
|
|
|
|
|
"部长",
|
|
|
|
|
|
"国企",
|
|
|
|
|
|
"事业单位",
|
|
|
|
|
|
"干部",
|
|
|
|
|
|
"科级",
|
|
|
|
|
|
"处级",
|
|
|
|
|
|
"厅级",
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def infer_background_voice(occupation: str | None) -> BackgroundVoice:
|
|
|
|
|
|
"""
|
|
|
|
|
|
据职业自由文本推断背景语气。军队关键词优先于干部关键词。
|
|
|
|
|
|
无匹配或未填 → default。
|
|
|
|
|
|
"""
|
|
|
|
|
|
if not occupation or not str(occupation).strip():
|
|
|
|
|
|
return "default"
|
|
|
|
|
|
t = str(occupation).strip().casefold()
|
|
|
|
|
|
for n in _MILITARY_NEEDLES:
|
|
|
|
|
|
if n.casefold() in t:
|
|
|
|
|
|
return "military"
|
|
|
|
|
|
for n in _CADRE_NEEDLES:
|
|
|
|
|
|
if n.casefold() in t:
|
|
|
|
|
|
return "cadre"
|
|
|
|
|
|
return "default"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def normalize_background_voice(voice: str | None) -> BackgroundVoice:
|
|
|
|
|
|
"""调用方传入已归一化枚举或原始职业文本均可。"""
|
|
|
|
|
|
if not voice:
|
|
|
|
|
|
return "default"
|
|
|
|
|
|
s = voice.strip()
|
|
|
|
|
|
if s in ("default", "cadre", "military"):
|
|
|
|
|
|
return s # type: ignore[return-value]
|
|
|
|
|
|
return infer_background_voice(s)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-06 22:22:50 +08:00
|
|
|
|
def get_background_voice_tone_hint(voice: str | None) -> str:
|
|
|
|
|
|
"""一句背景语气提示,融入主 system prompt;default 返回空串。"""
|
2026-03-31 23:55:26 +08:00
|
|
|
|
v = normalize_background_voice(voice)
|
|
|
|
|
|
if v == "default":
|
|
|
|
|
|
return ""
|
|
|
|
|
|
if v == "military":
|
|
|
|
|
|
return (
|
2026-04-06 22:22:50 +08:00
|
|
|
|
"语气简洁利落、得体;称呼自然;不写命令式、不堆砌军事辞藻;"
|
|
|
|
|
|
"仅当用户口述已出现相关事实时才呼应军旅语境,不编造经历。"
|
2026-03-31 23:55:26 +08:00
|
|
|
|
)
|
|
|
|
|
|
return (
|
2026-04-06 22:22:50 +08:00
|
|
|
|
"语气稳重有分寸、敬语适度;避免官样排比与公文套话;"
|
|
|
|
|
|
"不得编造用户未提及的职级、单位与荣誉。"
|
2026-03-31 23:55:26 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_background_voice_narrative_block(voice: str | None) -> str:
|
|
|
|
|
|
"""附在叙事系统提示后的文体补充;default 返回空串。"""
|
|
|
|
|
|
v = normalize_background_voice(voice)
|
|
|
|
|
|
if v == "default":
|
|
|
|
|
|
return ""
|
|
|
|
|
|
if v == "military":
|
|
|
|
|
|
return (
|
|
|
|
|
|
"## 背景文体(军队,须遵守上文事实边界)\n"
|
|
|
|
|
|
"叙事紧凑、层次清楚;若口述已出现纪律、集体、任务等语境,可适度用书面语呼应,**禁止**堆砌口号式军事辞藻或虚构军旅细节。\n"
|
2026-04-01 11:49:33 +08:00
|
|
|
|
"不新增军衔、单位番号、表彰等口述未出现的信息。\n"
|
|
|
|
|
|
"用户已退役/转业,以回忆军旅岁月为基调,不要预设其仍在服役。"
|
2026-03-31 23:55:26 +08:00
|
|
|
|
)
|
|
|
|
|
|
return (
|
|
|
|
|
|
"## 背景文体(干部/机关,须遵守上文事实边界)\n"
|
|
|
|
|
|
"段落层次清晰,用语庄重自然,避免口语碎词与段子感;**不得编造**职务、荣誉、单位名称与组织细节。\n"
|
2026-04-01 11:49:33 +08:00
|
|
|
|
"文采服务于真实内容,不写成公文或汇报腔。\n"
|
|
|
|
|
|
"用户已退休,以回顾和怀念工作岁月为基调,不要预设其仍在岗。"
|
2026-03-31 23:55:26 +08:00
|
|
|
|
)
|