Files
ST-Amily2-Chat-Optimisation/assets/amily-data-table/Memorisation-forms.html
Jenkins CI 2c3072a3d8 release: v2.2.2 [2026-05-27 11:10:55]
### 新功能
- **Function Call 填表模式**:在填表设置中新增独立开关,启用后支持通过 OpenAI 兼容接口(DeepSeek / OpenRouter / 各类中转等)直接返回结构化操作列表,绕过 `<Amily2Edit>` 文本解析路径,填表更稳定
  - 遇到不支持 `tool_choice` 的接口时自动降级重试
  - 对思考模型注入强制调用指令,防止绕过工具直接输出文本
  - 全部走 ST 后端代理,修复 CSP 拦截直连外部 URL 的问题
- **主界面新增提示词链编辑器入口**,同时调换了记忆管理与角色世界书的按钮位置
- **规则中心**新增"自动排除用户楼层"选项
### 修复
- 提示词链按钮点击无响应(改为事件委托方式绑定)
- 拖拽组件微抖误触发(加 5px 移动阈值过滤)
- 填表检查窗若干问题修复;翰林院(批量回填)修复;防抖逻辑落地
- 角色世界书入口添加使用警告弹窗(强制 10 秒倒计时),提示该功能长期未维护
- ApiProfile `fakeStream` 字段保存丢失问题
- 正文优化默认改为关闭状态
- NGMS / NCCS API 配置槽位标签修正(NGMS→总结,NCCS→填表)
- API Profile 面板选择逻辑统一重构,修复多处旧字段覆盖新配置的问题
- 世界书控制参数兼容性修复(排除递归、插入位置、扫描深度等,适配 ST 1.17.0+)
2026-05-27 11:10:55 +08:00

445 lines
29 KiB
HTML
Raw 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">
<title>Amily2 表格编辑器</title>
<link rel="stylesheet" href="table.css">
<style>
.worldbook-selection-container {
display: flex;
gap: 15px;
margin-top: 10px;
}
.worldbook-column {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0; /* Prevents flex items from overflowing */
}
.scrollable-container {
border: 1px solid var(--input-border-color, #444);
border-radius: 5px;
padding: 10px;
height: 150px;
overflow-y: auto;
background-color: var(--input-bg-color, #222);
margin-top: 5px;
margin-bottom: 5px;
}
.scrollable-container .checkbox-item {
display: flex;
align-items: center;
margin-bottom: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.scrollable-container .checkbox-item input[type="checkbox"] {
margin-right: 8px;
flex-shrink: 0;
}
.scrollable-container .checkbox-item label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
select.text_pole {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background-image: url("data:image/svg+xml;utf8,<svg fill='white' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/><path d='M0 0h24v24H0z' fill='none'/></svg>");
background-repeat: no-repeat;
background-position: right 8px center;
background-size: 1.2em;
padding-right: 2em !important;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="amily2-header">
<div class="additional-features-title">
<i class="fas fa-table"></i> 内存储司 · 表格核心
</div>
<button id="amily2_back_to_main_from_forms" class="menu_button secondary small_button interactable">
返回主殿 <i class="fas fa-arrow-right"></i>
</button>
</div>
<hr class="header-divider" style="margin-top: 5px; margin-bottom: 10px;">
<div id="upper-controls-wrapper">
<fieldset class="settings-group" style="padding: 10px; margin-bottom: 10px;">
<legend><i class="fas fa-brain"></i> 中枢决策室</legend>
<div class="sinan-navigation-deck" style="gap: 5px; margin-bottom: 10px;">
<button class="sinan-nav-item active" data-tab="injection-settings"><i class="fas fa-cogs"></i> 注入设置</button>
<button class="sinan-nav-item" data-tab="action-center"><i class="fas fa-toolbox"></i> 操作中心</button>
<button class="sinan-nav-item" data-tab="ai-template"><i class="fas fa-robot"></i> 指令模板</button>
<button class="sinan-nav-item" data-tab="world-settings"><i class="fas fa-globe"></i> 世界读取</button>
</div>
<div class="sinan-content-wrapper">
<div id="sinan-injection-settings-tab" class="sinan-tab-pane active">
<div class="inline-settings-grid">
<label for="table-injection-position">注入位置</label>
<select id="table-injection-position" class="text_pole">
<option value="2">主提示前</option>
<option value="0">主提示后</option>
<option value="1">聊天内</option>
</select>
<label for="table-injection-depth">注入深度</label>
<input type="number" id="table-injection-depth" class="text_pole" value="3">
<label>注入角色</label>
<div class="radio-group">
<input type="radio" id="table-role-system" name="table-injection-role" value="0" data-setting-key="injection.role" data-type="integer">
<label for="table-role-system">系统</label>
<input type="radio" id="table-role-user" name="table-injection-role" value="1" data-setting-key="injection.role" data-type="integer">
<label for="table-role-user">用户</label>
<input type="radio" id="table-role-ai" name="table-injection-role" value="2" data-setting-key="injection.role" data-type="integer">
<label for="table-role-ai">AI</label>
</div>
<label for="batch-filling-threshold">批处理阈值</label>
<input type="number" id="batch-filling-threshold" class="text_pole" value="30">
</div>
<div class="control-block-with-switch" style="margin-top: 10px;">
<label for="show-table-in-chat-toggle">聊天内显示表格</label>
<label class="toggle-switch">
<input type="checkbox" id="show-table-in-chat-toggle" data-setting-key="show_table_in_chat" data-type="boolean">
<span class="slider"></span>
</label>
</div>
<div class="control-block-with-switch" style="margin-top: 10px;">
<label for="render-on-every-message-toggle">持续渲染最新消息</label>
<label class="toggle-switch">
<input type="checkbox" id="render-on-every-message-toggle" data-setting-key="render_on_every_message" data-type="boolean">
<span class="slider"></span>
</label>
</div>
</div>
<div id="sinan-world-settings-tab" class="sinan-tab-pane">
<div class="amily2_opt_settings_block">
<label for="table_worldbook_enabled">启用世界书</label>
<label class="toggle-switch">
<input id="table_worldbook_enabled" type="checkbox" />
<span class="slider"></span>
</label>
</div>
<div class="amily2_opt_settings_block">
<label for="table_worldbook_char_limit">世界书最大字符数: <span id="table_worldbook_char_limit_value">60000</span></label>
<input type="number" class="text_pole" id="table_worldbook_char_limit" min="1000" max="200000" value="60000">
</div>
<hr>
<div class="amily2_opt_settings_block_radio">
<label>世界书来源</label>
<div class="amily2_opt_radio_group">
<input type="radio" id="table_worldbook_source_character" name="table_worldbook_source" value="character" checked>
<label for="table_worldbook_source_character">角色卡主世界书</label>
<input type="radio" id="table_worldbook_source_manual" name="table_worldbook_source" value="manual">
<label for="table_worldbook_source_manual">手动选择世界书</label>
</div>
</div>
<div id="table_worldbook_select_wrapper" style="display: none;">
<div class="worldbook-selection-container">
<!-- World Book List Column -->
<div class="worldbook-column">
<div class="amily2_opt_label_with_button_wrapper">
<label>选择世界书 (可多选)</label>
<button id="table_refresh_worldbooks" class="menu_button" title="刷新世界书列表"><i class="fa-solid fa-sync"></i></button>
</div>
<div class="table-search-wrapper">
<input type="text" id="table_worldbook_search" class="table-search-input" placeholder="搜索世界书名称...">
<i class="fas fa-search table-search-icon"></i>
</div>
<div id="table_worldbook_checkbox_list" class="scrollable-container">
<!-- 世界书勾选框将在这里动态生成 -->
</div>
<small class="notes">勾选需要启用的世界书。</small>
</div>
</div>
</div>
<!-- World Book Entry List Column -->
<div class="worldbook-column" style="margin-top: 10px;">
<label>选择条目 (可多选)</label>
<div class="table-search-wrapper">
<input type="text" id="table_entry_search" class="table-search-input" placeholder="搜索条目名称、关键词...">
<i class="fas fa-search table-search-icon"></i>
</div>
<div id="table_worldbook_entry_list" class="scrollable-container">
<!-- 世界书条目勾选框将在这里动态生成 -->
</div>
<small class="notes">勾选需要注入的条目。</small>
</div>
</div>
<div id="sinan-action-center-tab" class="sinan-tab-pane">
<div class="control-block-with-switch" style="margin-bottom: 15px; padding: 8px; border: 2px solid #4a9eff; border-radius: 5px; background: rgba(74, 158, 255, 0.1);">
<label for="table-system-master-switch" style="font-weight: bold; color: #4a9eff;">
<i class="fas fa-power-off"></i> 表格系统总开关
</label>
<label class="toggle-switch">
<input type="checkbox" id="table-system-master-switch" data-setting-key="table_system_enabled" data-type="boolean">
<span class="slider"></span>
</label>
</div>
<div class="control-block-with-switch" style="margin-bottom: 10px;">
<label for="table-injection-enabled-toggle">启用表格注入</label>
<label class="toggle-switch">
<input type="checkbox" id="table-injection-enabled" data-setting-key="table_injection_enabled" data-type="boolean">
<span class="slider"></span>
</label>
</div>
<div class="control-block-with-switch" style="margin-bottom: 10px;">
<label for="context-optimization-enabled-toggle">启用上下文优化 (合并世界书)</label>
<label class="toggle-switch">
<input type="checkbox" id="context-optimization-enabled" data-setting-key="context_optimization_enabled" data-type="boolean">
<span class="slider"></span>
</label>
</div>
<div class="control-block-with-switch" style="margin-bottom: 10px;">
<label>填表模式</label>
<div class="radio-group">
<input type="radio" id="main-api-mode" name="filling-mode" value="main-api" checked>
<label for="main-api-mode">原始</label>
<input type="radio" id="secondary-api-mode" name="filling-mode" value="secondary-api">
<label for="secondary-api-mode">分步</label>
<input type="radio" id="optimized-mode" name="filling-mode" value="optimized">
<label for="optimized-mode">兼容优化</label>
</div>
</div>
<!-- 分步填表高级控制 - 仅在分步模式下显示 -->
<div id="secondary-filler-controls" style="display: none; border-left: 2px solid #4a9eff; padding-left: 10px; margin-bottom: 10px;">
<!-- 上下文深度 -->
<div class="control-block-with-switch" style="margin-bottom: 10px; flex-direction: column; align-items: flex-start;">
<label for="secondary-filler-context">上下文深度</label>
<input type="number" id="secondary-filler-context" min="0" max="20" step="1" value="2" class="text_pole" style="width: 80px; margin-top: 5px;">
<small class="notes" style="margin-top: 5px; display: block;">填表时参考的历史上下文消息数量。</small>
</div>
<!-- 填表批次 -->
<div class="control-block-with-switch" style="margin-bottom: 10px; flex-direction: column; align-items: flex-start;">
<label for="secondary-filler-batch">填表批次 (Batch)</label>
<input type="number" id="secondary-filler-batch" min="0" max="20" step="1" value="0" class="text_pole" style="width: 80px; margin-top: 5px;">
<small class="notes" style="margin-top: 5px; display: block;">单次填表处理的消息数量 (0 = 实时单条模式)。</small>
</div>
<!-- 保留楼层 -->
<div class="control-block-with-switch" style="margin-bottom: 10px; flex-direction: column; align-items: flex-start;">
<label for="secondary-filler-buffer">保留楼层 (Buffer)</label>
<input type="number" id="secondary-filler-buffer" min="0" max="10" step="1" value="0" class="text_pole" style="width: 80px; margin-top: 5px;">
<small class="notes" style="margin-top: 5px; display: block;">始终保留不填表的最新消息数量 (缓冲防抖)。</small>
</div>
<!-- 最大重试次数 -->
<div class="control-block-with-switch" style="margin-bottom: 10px; flex-direction: column; align-items: flex-start;">
<label for="secondary-filler-max-retries">最大重试次数</label>
<input type="number" id="secondary-filler-max-retries" min="0" max="10" step="1" value="2" class="text_pole" style="width: 80px; margin-top: 5px;">
<small class="notes" style="margin-top: 5px; display: block;">分步填表失败时的自动重试次数 (0 = 不重试)。</small>
</div>
<!-- 触发延迟(防抖) -->
<div class="control-block-with-switch" style="margin-bottom: 10px; flex-direction: column; align-items: flex-start;">
<label for="secondary-filler-delay">触发延迟 (毫秒)</label>
<input type="number" id="secondary-filler-delay" min="0" max="60000" step="100" value="0" class="text_pole" style="width: 80px; margin-top: 5px;">
<small class="notes" style="margin-top: 5px; display: block;">收到新消息后延迟多少毫秒再触发分步填表 (0 = 立即触发);延迟期内若再次收到消息会重置计时,起到防抖作用。</small>
</div>
</div>
<div class="control-block-with-switch" style="margin-bottom: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 8px;">
<label style="font-weight: bold;">提取规则配置</label>
<select id="table-rule-profile-select" class="text_pole" style="width: 100%;"></select>
<small class="notes">选择在「规则配置中心」里创建的提取规则,应用于分步填表和批量填表。未选择时使用默认行为。</small>
</div>
<div class="action-center-buttons" style="gap: 8px;">
<button id="amily2-open-relationship-graph-btn" class="menu_button accent small_button interactable"><i class="fas fa-project-diagram"></i> 关系图谱</button>
<button id="amily2-export-preset-btn" class="menu_button primary small_button interactable"><i class="fas fa-file-export"></i> 导出预设</button>
<button id="amily2-export-preset-full-btn" class="menu_button primary small_button interactable"><i class="fas fa-file-archive"></i> 导出备份</button>
<button id="amily2-import-preset-btn" class="menu_button secondary small_button interactable"><i class="fas fa-file-upload"></i> 导入预设</button>
<button id="amily2-import-global-preset-btn" class="menu_button secondary small_button interactable"><i class="fas fa-globe"></i> 导入全局</button>
<button id="amily2-clear-global-preset-btn" class="menu_button danger small_button interactable"><i class="fas fa-undo"></i> 清除全局</button>
<button id="amily2-clear-all-tables-btn" class="menu_button danger small_button interactable"><i class="fas fa-trash-alt"></i> 清空内容</button>
</div>
<p class="notes" style="margin-top: 8px; margin-bottom: 10px;">说明:可以导出不含剧情的"纯净预设"用于分享,或导出包含剧情的"完整备份"用于存档。</p>
<hr class="section-divider" style="margin: 10px 0;">
<!-- 历史记录清理区域 -->
<fieldset class="settings-group" style="border-style: dashed; padding: 8px; margin-bottom: 10px;">
<legend><i class="fas fa-trash-alt"></i> 历史记录清理</legend>
<div class="control-block-with-switch" style="margin-bottom: 10px; flex-direction: column; align-items: flex-start;">
<label for="clear-records-before-floor">清除此楼层前的表格记录</label>
<div style="display: flex; gap: 10px; align-items: center; width: 100%; margin-top: 5px;">
<input type="number" id="clear-records-before-floor" class="text_pole" style="flex: 1;" placeholder="输入楼层号 (例如: 100)">
<button id="clear-records-btn" class="menu_button danger small_button interactable">
<i class="fas fa-eraser"></i> 一键清除
</button>
</div>
<small class="notes" style="margin-top: 5px; display: block;">
警告:此操作将永久删除指定楼层之前所有消息中存储的表格快照。这可以显著减小聊天记录文件的大小,但会导致无法回退到这些楼层的表格状态。当前最新的表格状态不会受影响。
</small>
</div>
</fieldset>
<hr class="section-divider" style="margin: 10px 0;">
<!-- Function Call 填表 -->
<div class="control-block-with-switch" style="margin-bottom: 6px;">
<label for="table-fill-function-call-enabled" title="使用 OpenAI Function Call工具调用进行填表模型直接返回结构化操作列表无需解析 &lt;Amily2Edit&gt; 指令块。仅支持 openai 直连模式。">使用 Function Call 填表</label>
<label class="toggle-switch">
<input type="checkbox" id="table-fill-function-call-enabled">
<span class="slider"></span>
</label>
</div>
<p class="notes" style="margin-bottom: 10px;">仅支持 openai 直连接口tableFilling 槽位)。启用后跳过 &lt;Amily2Edit&gt; 文本解析,由模型直接返回操作列表。</p>
<hr class="section-divider" style="margin: 10px 0;">
<!-- Nccs API 控制区域 -->
<fieldset class="settings-group" style="border-style: dashed; padding: 8px; margin-bottom: 10px;">
<legend><i class="fas fa-brain"></i> Nccs API 系统</legend>
<div class="control-block-with-switch" style="margin-bottom: 10px;">
<label for="nccs-api-enabled">启用 Nccs API</label>
<label class="toggle-switch">
<input type="checkbox" id="nccs-api-enabled" data-setting-key="nccsEnabled" data-type="boolean">
<span class="slider"></span>
</label>
</div>
<div id="nccs-api-config" style="display: none;">
<div class="amily2_opt_settings_block" style="margin-bottom: 10px;">
<label for="nccs-api-mode">API 模式</label>
<select id="nccs-api-mode" class="text_pole">
<option value="openai_test">全兼容模式</option>
<option value="sillytavern_preset">SillyTavern预设模式</option>
</select>
</div>
<div class="amily2_opt_settings_block" style="margin-bottom: 10px;">
<label for="nccs-api-url">API URL</label>
<input type="text" id="nccs-api-url" class="text_pole" placeholder="https://api.openai.com/v1">
</div>
<div class="amily2_opt_settings_block" style="margin-bottom: 10px;">
<label for="nccs-api-key">API Key</label>
<input type="password" id="nccs-api-key" class="text_pole" placeholder="输入您的API密钥">
</div>
<div class="amily2_opt_settings_block" style="margin-bottom: 10px;">
<label for="nccs-api-model">模型</label>
<div style="display: flex; gap: 5px; align-items: center;">
<input type="text" id="nccs-api-model" class="text_pole" placeholder="选择或输入模型">
</div>
</div>
<div class="amily2_opt_settings_block" style="margin-bottom: 10px;">
<label for="nccs-api-fakestream-enabled">启用流式支持: </label>
<input type="checkbox" id="nccs-api-fakestream-enabled" data-setting-key="nccsFakeStreamEnabled" data-type="boolean">
</div>
<div class="amily2_opt_settings_block" style="margin-bottom: 10px;">
<label for="nccs-sillytavern-preset">SillyTavern 预设</label>
<select id="nccs-sillytavern-preset" class="text_pole">
<option value="">选择预设</option>
</select>
</div>
<div class="nccs-button-row" style="display: flex; gap: 10px; justify-content: center; margin-top: 15px;">
<button id="nccs-test-connection" class="menu_button primary small_button interactable">
<i class="fas fa-plug"></i> 测试连接
</button>
<button id="nccs-fetch-models" class="menu_button secondary small_button interactable">
<i class="fas fa-download"></i> 获取模型
</button>
</div>
</div>
</fieldset>
<hr class="section-divider" style="margin: 10px 0;">
<div class="action-center-buttons" id="theme-action-buttons" style="gap: 8px;">
<button id="amily2-import-theme-btn" class="menu_button small_button interactable"><i class="fas fa-palette"></i> 导入主题</button>
<button id="amily2-export-theme-btn" class="menu_button small_button interactable"><i class="fas fa-paint-brush"></i> 导出主题</button>
<button id="amily2-reset-theme-btn" class="menu_button small_button interactable"><i class="fas fa-undo"></i> 恢复默认</button>
</div>
<p class="notes" style="margin-top: 8px;">说明导入下载的主题JSON文件或将当前的外观导出分享。</p>
</div>
<div id="sinan-ai-template-tab" class="sinan-tab-pane">
<fieldset class="settings-group" style="border-style: dashed; padding: 8px; margin-bottom: 10px;">
<legend><i class="fas fa-scroll"></i> 规则提示词</legend>
<div class="amily2_settings_block prompt-editor-area">
<textarea id="ai-rule-template-editor" class="text_pole" rows="2"></textarea>
<div class="editor-buttons-panel">
<button id="ai-rule-template-save-btn" class="menu_button accent small_button interactable"><i class="fas fa-save"></i> 保存</button>
<button id="ai-rule-template-restore-btn" class="menu_button secondary small_button interactable"><i class="fas fa-undo"></i> 默认</button>
</div>
</div>
</fieldset>
<fieldset class="settings-group" style="border-style: dashed; padding: 8px;">
<legend><i class="fas fa-tasks"></i> 流程提示词</legend>
<div class="amily2_settings_block prompt-editor-area">
<textarea id="ai-flow-template-editor" class="text_pole" rows="2"></textarea>
<div class="editor-buttons-panel">
<button id="ai-flow-template-save-btn" class="menu_button accent small_button interactable"><i class="fas fa-save"></i> 保存</button>
<button id="ai-flow-template-restore-btn" class="menu_button secondary small_button interactable"><i class="fas fa-undo"></i> 默认</button>
</div>
</div>
</fieldset>
<hr class="section-divider" style="margin: 10px 0;">
<div id="table-filling-controls" style="display: flex; flex-direction: column; gap: 10px; align-items: center;">
<!-- 楼层选择区域 -->
<div style="display: flex; gap: 10px; align-items: center; justify-content: center;">
<label for="floor-start-input" style="font-size: 12px; white-space: nowrap;">起始楼层:</label>
<input type="number" id="floor-start-input" class="text_pole" style="width: 80px;" placeholder="1" min="1">
<label for="floor-end-input" style="font-size: 12px; white-space: nowrap;">结束楼层:</label>
<input type="number" id="floor-end-input" class="text_pole" style="width: 80px;" placeholder="10" min="1">
</div>
<!-- 填表按钮区域 -->
<div style="display: flex; gap: 10px; align-items: center; justify-content: center; flex-wrap: wrap;">
<button id="fill-table-now-btn" class="menu_button small_button">立即填表</button>
<button id="fill-selected-floors-btn" class="menu_button accent small_button">选定楼层填表</button>
<button id="fill-current-floor-btn" class="menu_button secondary small_button">填当前楼层</button>
<button id="rollback-and-refill-btn" class="menu_button secondary small_button">回退重填</button>
<button id="reorganize-table-btn" class="menu_button warning small_button">重新整理</button>
</div>
</div>
</div>
</div>
</fieldset>
<div id="table-log-display" class="hly-log-display" style="margin-top: 10px; margin-bottom: 10px;">
</div>
</div>
<div id="all-tables-container" class="hly-scroll">
<div id="add-table-placeholder" title="敕令新表">
<i class="fas fa-plus"></i>
</div>
</div>
</body>
</html>