feat(cli): include system prompts in HTML export

This commit is contained in:
doer 2026-05-23 16:28:06 +08:00 committed by Teknium
parent a80e5e72bc
commit 49dd0b1cb5

View file

@ -18,6 +18,7 @@ ICON_WRENCH = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" vi
ICON_SPARKLES = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sparkles"><path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z"/><path d="M5 3v4"/><path d="M19 17v4"/><path d="M3 5h4"/><path d="M17 19h4"/></svg>'
ICON_CHEVRON_RIGHT = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-right"><path d="m9 18 6-6-6-6"/></svg>'
ICON_SEARCH = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-search"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>'
ICON_SHIELD = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-shield"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.5 3.8 17 5 19 5a1 1 0 0 1 1 1z"/></svg>'
ICON_HERMES = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#FFD700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="m9 12 2 2 4-4"/></svg>'
HTML_TEMPLATE = """<!DOCTYPE html>
@ -272,6 +273,12 @@ HTML_TEMPLATE = """<!DOCTYPE html>
border-left: 4px solid var(--accent-color);
}}
.message-system {{
background-color: var(--bg-color);
border-left: 4px solid var(--secondary-text);
opacity: 0.9;
}}
.message-tool {{
background-color: #f8fafc;
border-style: dotted;
@ -286,6 +293,11 @@ HTML_TEMPLATE = """<!DOCTYPE html>
background-color: #041c1c;
}}
.message-system {{
background-color: #020617;
border-left: 4px solid var(--secondary-text);
}}
.message-tool {{
background-color: #0f172a;
}}
@ -599,6 +611,8 @@ def _generate_messages_html(messages: List[Dict[str, Any]]) -> str:
role_icon = ICON_USER
elif role == "assistant":
role_icon = ICON_BOT
elif role == "system":
role_icon = ICON_SHIELD
# Handle multimodal or complex content
if isinstance(content, list):
@ -725,7 +739,22 @@ def generate_multi_session_html_export(sessions: List[Dict[str, Any]]) -> str:
model = s.get("model", "Unknown")
started_at = _format_timestamp(s.get("started_at", 0))
messages = s.get("messages", [])
messages_html = _generate_messages_html(messages)
# System Prompt Handling: Prepend if present in session metadata and not already in messages
system_prompt = s.get("system_prompt")
all_messages = []
if system_prompt:
# Avoid duplicating if the first message in the list is already the system prompt
first_msg = messages[0] if messages else None
if not (first_msg and first_msg.get("role") == "system" and first_msg.get("content") == system_prompt):
all_messages.append({
"role": "system",
"content": system_prompt,
"timestamp": s.get("started_at", 0)
})
all_messages.extend(messages)
messages_html = _generate_messages_html(all_messages)
view_class = "session-view"
if not is_multi: view_class += " active"