Files
writing-agent/web/presets.html
chenmoranzhi f3303038fe 新增预设工作台:编辑、版本树、结构检查、用例试跑放在同一页。
改预设要能一边写一边看装出来的 messages,还要多模型对照,所以把编辑与试跑拆成两个视图塞进一个页面;版本存完整快照、可分叉,用例全局共用一份、运行记录按预设存。顺带让读预设文件先剥 BOM,静态资源改成不缓存,免得改了脚本还要强刷。
2026-10-26 01:09:40 +08:00

183 lines
8.1 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>预设工作台 · Writing Agent</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;600;700&family=Noto+Serif+SC:wght@500;600;700&display=swap"
rel="stylesheet"
/>
<script src="/theme-init.js"></script>
<link rel="stylesheet" href="/settings.css" />
<link rel="stylesheet" href="/history-editor.css" />
<link rel="stylesheet" href="/presets.css" />
</head>
<body class="settings-page px-page" data-preview="on" data-outline="off">
<header class="st-top">
<a class="st-brand" href="/">Writing Agent</a>
<nav class="st-nav" aria-label="主导航">
<a href="/">对话</a>
<a href="/chat.html">直聊</a>
<a href="/modules.html">技能</a>
<a href="/libraries.html">库</a>
<a href="/stats.html">Token</a>
<a href="/presets.html" aria-current="page">预设</a>
<a href="/settings.html">设置</a>
</nav>
</header>
<!-- 预设身份条:唯一脏状态 + 唯一主行动 -->
<div class="px-idbar">
<div class="px-id-main">
<select id="preset-select" class="px-select" aria-label="选择预设"></select>
<button type="button" id="btn-new-preset" class="px-btn px-btn-mini" title="新建预设">+</button>
<input
id="preset-name"
class="px-input px-name"
type="text"
aria-label="预设名称"
placeholder="预设名称"
/>
<span class="px-idmeta" id="preset-meta"></span>
<span class="px-dirty" id="dirty-pill" data-dirty="0">已同步</span>
</div>
<div class="px-id-actions">
<span class="px-notice" id="notice" aria-live="polite"></span>
<button type="button" class="px-btn" id="btn-reload" title="从磁盘重读预设文件,未保存的草稿会丢">重新载入</button>
<button type="button" class="px-btn" id="btn-run-entry">
<span class="px-btn-label">试跑</span><span class="px-btn-meta" id="run-entry-meta"></span>
</button>
<button type="button" class="px-btn" id="btn-versions" title="打开版本树">版本树</button>
<button type="button" class="px-btn" id="btn-save-current" title="覆盖当前版本节点,不新建(Ctrl+Shift+S)">
保存至当前版本
</button>
<button type="button" class="px-btn" id="btn-save-new" title="在当前节点下追加一个新版本(Ctrl+S)">
保存为新版本
</button>
<button type="button" class="px-btn px-btn-primary" id="btn-apply" title="先保存为新版本,再覆盖预设文件——对话页读的是那个文件">应用到对话页</button>
</div>
</div>
<div class="px-alert" id="alert" hidden></div>
<!-- 视图 A:编辑 -->
<div class="px-view px-view-edit" id="view-edit">
<nav class="px-outline" id="outline" aria-label="发送顺序"></nav>
<main class="px-editor" id="editor"></main>
<aside class="px-preview" id="preview-pane" aria-label="实际发送内容">
<div class="px-preview-head">
<select id="preview-case" class="px-select" aria-label="预览用例"></select>
<button type="button" class="px-btn px-btn-mini" id="btn-preview" title="Ctrl+Enter">重算</button>
<button type="button" class="px-btn px-btn-mini" id="btn-toggle-preview" title="显示 / 收起预览">
收起
</button>
</div>
<div class="px-band" id="issues-band" data-level="ok"></div>
<p class="px-preview-meta" id="preview-meta"></p>
<div class="px-messages" id="preview-out"></div>
</aside>
</div>
<!-- 视图 B:试跑 -->
<div class="px-view px-view-run" id="view-run" hidden>
<div class="px-runbar">
<div class="px-runbar-row">
<span class="px-label">当前用例</span>
<span class="px-runbar-case" id="run-case-label">先在左侧选一个用例</span>
<span class="px-runbar-sep" aria-hidden="true"></span>
<span class="px-label">模型</span>
<div class="px-picker">
<button
type="button"
class="px-btn px-btn-mini px-picker-trigger"
id="model-picker-btn"
aria-haspopup="listbox"
aria-expanded="false"
>
选择模型<span class="px-picker-count" id="model-picker-count"></span>
</button>
<div
class="px-picker-menu"
id="model-picker-menu"
role="listbox"
aria-multiselectable="true"
hidden
></div>
</div>
<div class="px-picked" id="picked-models" aria-label="已选模型"></div>
<button type="button" class="px-btn px-btn-primary px-runbar-run" id="btn-run">运行此用例</button>
</div>
</div>
<nav class="px-caselist" id="cases" aria-label="用例" title="用例全局共用:任何预设都能拿这些用例去跑"></nav>
<main class="px-results-pane">
<div class="px-results-head">
<select id="run-select" class="px-select" aria-label="历史运行"></select>
<button type="button" class="px-btn px-btn-mini" id="btn-refresh-runs">刷新记录</button>
<p class="px-hint px-results-hint">不自动评分,逐条标记成功 / 失败;标记会落盘。</p>
</div>
<div class="px-results" id="results"></div>
</main>
</div>
<!-- 版本抽屉(低频,从身份条进入) -->
<div class="px-scrim" id="scrim" hidden></div>
<aside class="px-drawer" id="version-drawer" hidden aria-label="版本">
<div class="px-drawer-head">
<h2>版本</h2>
<button type="button" class="px-btn px-btn-mini" id="btn-close-versions">关闭</button>
</div>
<div class="px-drawer-body">
<div id="version-tree" role="tree"></div>
<p class="px-hint" id="version-hint">还没有版本。</p>
<label class="px-field">
<span>本次修改说明</span>
<input type="text" id="note-input" placeholder="例:收紧叙事视角" />
</label>
<div class="px-row">
<button type="button" class="px-btn px-btn-primary" id="btn-save-version">保存为新版本</button>
<button type="button" class="px-btn" id="btn-save-version-current">保存至当前版本</button>
</div>
<div class="px-row">
<button type="button" class="px-btn" id="btn-load-version">载入选中</button>
<button type="button" class="px-btn" id="btn-fork-version">从选中分叉</button>
</div>
<p class="px-hint" id="dirty-hint"></p>
<p class="px-hint">
点节点弹菜单:「读取」换进编辑器,「从它分叉」用当前草稿在它下面开新分支。
圆点是当前编辑位置,分叉会另开一条线。
</p>
<p class="px-hint">
「保存为新版本」(Ctrl+S)在当前节点下追加子节点;「保存至当前版本」直接覆盖当前节点。
「应用到对话页」会先保存为新版本,再覆盖 <code>presets/&lt;id&gt;.json</code>——对话页读的是那个文件。
「重新载入」从磁盘重读预设文件,未保存的草稿会丢。
</p>
</div>
</aside>
<!-- 用例浮窗(字段多、还要写历史,用大浮窗而不是窄侧栏) -->
<section
class="px-modal"
id="case-modal"
role="dialog"
aria-modal="true"
aria-labelledby="case-drawer-title"
hidden
>
<div class="px-modal-head">
<h2 id="case-drawer-title">用例</h2>
<button type="button" class="px-btn px-btn-mini" id="btn-close-case">完成</button>
</div>
<div class="px-modal-body" id="case-form"></div>
</section>
<script type="module" src="/presets.js"></script>
</body>
</html>