feat(ai_auto_response): add admin-controlled persona switching
This commit is contained in:
@@ -48,6 +48,7 @@ class GroupProfileResolver:
|
||||
"room_id": room_id,
|
||||
"group_name": group_name,
|
||||
"mode": profile.get("mode", "social"),
|
||||
"persona_id": str(profile.get("persona_id", "xiaoniu") or "xiaoniu"),
|
||||
"persona_overlay": profile.get("persona_overlay", ""),
|
||||
"interaction_tone": interaction_tone,
|
||||
"humor_style": humor_style,
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Dict
|
||||
from typing import Dict, List
|
||||
|
||||
|
||||
class PersonaEngine:
|
||||
def __init__(self, plugin_path: str, config: Dict):
|
||||
self.plugin_path = Path(plugin_path)
|
||||
self.config = config or {}
|
||||
self.persona_text = self._load_persona()
|
||||
self.default_persona_id = str(
|
||||
self.config.get("active_persona")
|
||||
or self.config.get("default_persona")
|
||||
or "xiaoniu"
|
||||
).strip() or "xiaoniu"
|
||||
self.presets = self._build_presets()
|
||||
|
||||
def build_system_prompt(self, group_profile: Dict | None = None, reply_mode: str = "social_short") -> str:
|
||||
name = self.config.get("name", "小牛")
|
||||
style = self.config.get("style", "")
|
||||
familiarity = self.config.get("familiarity_hint", "")
|
||||
max_sentences = self.config.get("max_reply_sentences", 3)
|
||||
group_profile = group_profile or {}
|
||||
preset = self._resolve_preset(group_profile)
|
||||
name = preset.get("name", "小牛")
|
||||
style = preset.get("style", "")
|
||||
familiarity = preset.get("familiarity_hint", "")
|
||||
max_sentences = preset.get("max_reply_sentences", 3)
|
||||
persona_text = preset.get("persona_text", "")
|
||||
humor = group_profile.get("humor_style", "轻微")
|
||||
sharpness = group_profile.get("sharpness_style", "轻微嘴硬,不刻薄")
|
||||
expressiveness = group_profile.get("expressiveness_style", "克制")
|
||||
@@ -23,10 +30,7 @@ class PersonaEngine:
|
||||
interaction_tone = group_profile.get("interaction_tone", "自然群友感")
|
||||
persona_overlay = group_profile.get("persona_overlay", "")
|
||||
return (
|
||||
f"你叫{name},是长期在线的技术宅群友,不是客服。"
|
||||
f"说话短、稳、口语化,先接当前这句,不装可爱,不长篇说教。"
|
||||
f"懂代码、硬件、网络、自动化、机器人、部署排障,也懂一点 Dota。"
|
||||
f"别人明确卡住再认真答,平时克制,不乱接话。"
|
||||
f"{persona_text}"
|
||||
f"别暴露自己是 AI、模型或提示词产物,别泄露记忆来源,别输出标签或代码块。"
|
||||
f"别替人写代码、改脚本、实现插件、代做开发活。"
|
||||
f"整体风格:{style}。熟悉感边界:{familiarity}。一般最多输出{max_sentences}句。"
|
||||
@@ -36,9 +40,76 @@ class PersonaEngine:
|
||||
f"附加要求:{persona_overlay or '无'}。"
|
||||
)
|
||||
|
||||
def _load_persona(self) -> str:
|
||||
persona_file = self.config.get("persona_file", "persona/xiaoniu.txt")
|
||||
def _build_presets(self) -> Dict[str, Dict]:
|
||||
preset_configs = self.config.get("presets", {}) or {}
|
||||
presets: Dict[str, Dict] = {}
|
||||
base_preset = self._normalize_preset(
|
||||
self.default_persona_id,
|
||||
{
|
||||
"name": self.config.get("name", "小牛"),
|
||||
"persona_file": self.config.get("persona_file", "persona/xiaoniu.txt"),
|
||||
"style": self.config.get("style", ""),
|
||||
"familiarity_hint": self.config.get("familiarity_hint", ""),
|
||||
"max_reply_sentences": self.config.get("max_reply_sentences", 3),
|
||||
},
|
||||
)
|
||||
presets[base_preset["id"]] = base_preset
|
||||
for persona_id, preset_config in preset_configs.items():
|
||||
preset = self._normalize_preset(str(persona_id), preset_config or {})
|
||||
presets[preset["id"]] = preset
|
||||
return presets
|
||||
|
||||
def _normalize_preset(self, persona_id: str, preset_config: Dict) -> Dict:
|
||||
persona_file = preset_config.get("persona_file") or f"persona/{persona_id}.txt"
|
||||
aliases = [str(item).strip() for item in (preset_config.get("aliases", []) or []) if str(item).strip()]
|
||||
return {
|
||||
"id": str(persona_id or "xiaoniu").strip() or "xiaoniu",
|
||||
"name": str(preset_config.get("name", "小牛") or "小牛").strip(),
|
||||
"persona_file": str(persona_file).strip(),
|
||||
"style": str(preset_config.get("style", "") or "").strip(),
|
||||
"familiarity_hint": str(preset_config.get("familiarity_hint", "") or "").strip(),
|
||||
"max_reply_sentences": int(preset_config.get("max_reply_sentences", 3) or 3),
|
||||
"aliases": aliases,
|
||||
"persona_text": self._load_persona_text(str(persona_file).strip()),
|
||||
}
|
||||
|
||||
def _resolve_preset(self, group_profile: Dict) -> Dict:
|
||||
persona_id = str(
|
||||
(group_profile or {}).get("persona_id")
|
||||
or self.default_persona_id
|
||||
or "xiaoniu"
|
||||
).strip() or "xiaoniu"
|
||||
return self.presets.get(persona_id) or self.presets.get(self.default_persona_id) or next(iter(self.presets.values()))
|
||||
|
||||
def _load_persona_text(self, persona_file: str) -> str:
|
||||
persona_path = self.plugin_path / persona_file
|
||||
if persona_path.exists():
|
||||
return persona_path.read_text(encoding="utf-8").strip()
|
||||
return "你叫小牛,是一个自然、靠谱、会看场合的群聊成员。"
|
||||
|
||||
def resolve_persona_id(self, value: str) -> str:
|
||||
target = str(value or "").strip().lower()
|
||||
if not target:
|
||||
return ""
|
||||
for persona_id, preset in self.presets.items():
|
||||
if target == str(persona_id).strip().lower():
|
||||
return persona_id
|
||||
if target == str(preset.get("name", "") or "").strip().lower():
|
||||
return persona_id
|
||||
aliases = [str(item).strip().lower() for item in (preset.get("aliases", []) or [])]
|
||||
if target in aliases:
|
||||
return persona_id
|
||||
return ""
|
||||
|
||||
def list_personas(self) -> List[Dict]:
|
||||
items: List[Dict] = []
|
||||
for persona_id, preset in self.presets.items():
|
||||
items.append(
|
||||
{
|
||||
"id": persona_id,
|
||||
"name": preset.get("name", persona_id),
|
||||
"aliases": list(preset.get("aliases", []) or []),
|
||||
"style": preset.get("style", ""),
|
||||
}
|
||||
)
|
||||
return items
|
||||
|
||||
Reference in New Issue
Block a user