66 lines
2.7 KiB
Python
66 lines
2.7 KiB
Python
"""One persistent persona for all configured chat/agent providers on this AI Core."""
|
|
from contextlib import closing
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
from app.database.db import connect
|
|
|
|
|
|
class DialoguePair(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
user: str = Field(default="", max_length=8000)
|
|
assistant: str = Field(default="", max_length=8000)
|
|
|
|
|
|
class PersonaSettings(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
version: int = Field(default=0, ge=0)
|
|
name: str = Field(default="", max_length=128)
|
|
system_prompt: str = Field(default="", max_length=16000)
|
|
dialogue_pairs: list[DialoguePair] = Field(default_factory=list, max_length=20)
|
|
|
|
|
|
def connection():
|
|
conn = connect()
|
|
conn.execute("CREATE TABLE IF NOT EXISTS global_persona (id INTEGER PRIMARY KEY CHECK(id=1), data TEXT NOT NULL)")
|
|
return conn
|
|
|
|
|
|
def load_persona():
|
|
with closing(connection()) as conn:
|
|
row = conn.execute("SELECT data FROM global_persona WHERE id=1").fetchone()
|
|
return PersonaSettings.model_validate_json(row[0]) if row else PersonaSettings()
|
|
|
|
|
|
def save_persona(settings):
|
|
from app.errors import ApiError
|
|
with closing(connection()) as conn:
|
|
conn.execute("BEGIN IMMEDIATE")
|
|
try:
|
|
row = conn.execute("SELECT data FROM global_persona WHERE id=1").fetchone()
|
|
current = PersonaSettings.model_validate_json(row[0]) if row else PersonaSettings()
|
|
if current.version != settings.version:
|
|
raise ApiError(409, "PERSONA_VERSION_CONFLICT", "全局人设已被修改,请重新打开表单后保存。")
|
|
updated = settings.model_copy(update={"version": current.version + 1})
|
|
conn.execute("INSERT OR REPLACE INTO global_persona(id,data) VALUES(1,?)", (updated.model_dump_json(),))
|
|
conn.commit()
|
|
return updated
|
|
except BaseException:
|
|
conn.rollback()
|
|
raise
|
|
|
|
|
|
def apply_global_persona(request):
|
|
settings = load_persona()
|
|
parts = [request.system or ""]
|
|
if settings.system_prompt.strip():
|
|
parts.append("全局人设 / Global persona\n" + settings.system_prompt.strip())
|
|
examples = []
|
|
for pair in settings.dialogue_pairs:
|
|
lines = []
|
|
if pair.user.strip(): lines.append("User: " + pair.user.strip())
|
|
if pair.assistant.strip(): lines.append("Assistant: " + pair.assistant.strip())
|
|
if lines: examples.append("\n".join(lines))
|
|
if examples:
|
|
parts.append("预设对话示例 / Example dialogue\n" + "\n\n".join(examples))
|
|
system = "\n\n".join(part for part in parts if part.strip())
|
|
return request.model_copy(update={"system": system or None})
|