persona-ui / utils /chat_export.py
Jac-Zac
Big refactor and feature addition to analyses + support latest persona-vector
db3d901
import json
from dataclasses import asdict, is_dataclass
from datetime import UTC, datetime
from pathlib import Path
from utils.helpers import slugify
def _serialise_message(message: dict[str, object]) -> dict[str, object]:
payload: dict[str, object] = {
"role": message["role"],
"content": message["content"],
}
contrast = message.get("_contrast")
if contrast is not None:
payload["_contrast"] = asdict(contrast) if is_dataclass(contrast) else contrast
return payload
def save_chat_export(
*,
model_name: str,
dataset_source: str,
persona_id: str,
persona_name: str | None,
prompt_mode: str,
system_prompt: str | None,
messages: list[dict[str, str]],
generation: dict[str, object],
panel_label: str | None = None,
) -> Path:
"""Save the current chat session to ``artifacts/chats`` as JSON.
Args:
model_name: Model identifier used for the chat.
dataset_source: Human-readable dataset source label.
persona_id: Selected persona id.
persona_name: Selected persona display name, if available.
prompt_mode: Active system prompt mode.
system_prompt: Current system prompt text, if any.
messages: Conversation messages without the system prompt.
generation: Generation settings used for the chat.
panel_label: Optional side label (e.g. "left"/"right") for compare-mode exports.
Returns:
The path the export was written to.
"""
from persona_data.environment import get_artifacts_dir
payload = {
"model_name": model_name,
"dataset_source": dataset_source,
"persona": {
"id": persona_id,
"name": persona_name,
},
"panel_label": panel_label,
"prompt_mode": prompt_mode,
"generation": generation,
"messages": (
[{"role": "system", "content": system_prompt}] if system_prompt else []
)
+ [_serialise_message(message) for message in messages],
}
export_dir = (
get_artifacts_dir()
/ "chats"
/ "__".join(slugify(part) for part in model_name.split("/"))
/ slugify(persona_id)
)
export_dir.mkdir(parents=True, exist_ok=True)
timestamp = datetime.now(UTC).strftime("%Y%m%dT%H%M%SZ")
filename_parts = [
timestamp,
slugify(persona_name or persona_id),
slugify(prompt_mode),
]
if panel_label:
filename_parts.append(slugify(panel_label))
export_path = export_dir / f"{'__'.join(filename_parts)}.json"
export_path.write_text(
f"{json.dumps(payload, indent=2, ensure_ascii=False)}\n",
encoding="utf-8",
)
return export_path