mirror of
https://github.com/Wx-2025/ST-Amily2-Chat-Optimisation.git
synced 2026-06-06 17:25:51 +00:00
298 lines
12 KiB
JavaScript
298 lines
12 KiB
JavaScript
import * as state from './prese_state.js';
|
|
import * as ui from './prese_ui.js';
|
|
import { bindDragEvents } from './prese_dragdrop.js';
|
|
import { sectionTitles } from './config.js';
|
|
|
|
function updatePresetsFromUI(context) {
|
|
const currentPresets = state.getCurrentPresets();
|
|
context.find('.prompt-section').each(function() {
|
|
const sectionKey = $(this).data('section');
|
|
if (sectionKey && currentPresets[sectionKey]) {
|
|
$(this).find('.mixed-list .mixed-item[data-type="prompt"]').each(function() {
|
|
const promptIndex = $(this).data('prompt-index');
|
|
const role = $(this).find('.role-select').val();
|
|
const content = $(this).find('.content-textarea').val();
|
|
|
|
if (currentPresets[sectionKey][promptIndex]) {
|
|
currentPresets[sectionKey][promptIndex] = { role, content };
|
|
}
|
|
});
|
|
}
|
|
});
|
|
state.setCurrentPresets(currentPresets);
|
|
}
|
|
|
|
function exportSectionPreset(sectionKey) {
|
|
const sectionConfig = {
|
|
presets: { [sectionKey]: state.getCurrentPresets()[sectionKey] },
|
|
mixedOrder: { [sectionKey]: state.getCurrentMixedOrder()[sectionKey] },
|
|
version: 'v2.1_section',
|
|
sectionName: sectionTitles[sectionKey],
|
|
exportTime: new Date().toISOString()
|
|
};
|
|
|
|
const blob = new Blob([JSON.stringify(sectionConfig, null, 2)], {
|
|
type: 'application/json'
|
|
});
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = `amily2_${sectionKey}_preset.json`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
|
|
toastr.success(`${sectionTitles[sectionKey]} 已导出!`);
|
|
}
|
|
|
|
function importSectionPreset(sectionKey, context) {
|
|
const input = document.createElement('input');
|
|
input.type = 'file';
|
|
input.accept = '.json';
|
|
input.onchange = (event) => {
|
|
const file = event.target.files[0];
|
|
if (file) {
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
try {
|
|
const imported = JSON.parse(e.target.result);
|
|
const currentPresets = state.getCurrentPresets();
|
|
const currentMixedOrder = state.getCurrentMixedOrder();
|
|
|
|
if (imported.version === 'v2.1_section' && imported.presets && imported.mixedOrder) {
|
|
if (imported.presets[sectionKey] && imported.mixedOrder[sectionKey]) {
|
|
currentPresets[sectionKey] = imported.presets[sectionKey];
|
|
currentMixedOrder[sectionKey] = imported.mixedOrder[sectionKey];
|
|
toastr.success(`${sectionTitles[sectionKey]} 已成功导入!`);
|
|
} else {
|
|
throw new Error("文件中不包含对应的section数据");
|
|
}
|
|
} else if (imported.version === 'v2.1' && imported.presets && imported.mixedOrder) {
|
|
if (imported.presets[sectionKey] && imported.mixedOrder[sectionKey]) {
|
|
currentPresets[sectionKey] = imported.presets[sectionKey];
|
|
currentMixedOrder[sectionKey] = imported.mixedOrder[sectionKey];
|
|
toastr.success(`${sectionTitles[sectionKey]} 已成功导入!`);
|
|
} else {
|
|
throw new Error("文件中不包含对应的section数据");
|
|
}
|
|
} else if (imported[sectionKey]) {
|
|
currentPresets[sectionKey] = imported[sectionKey];
|
|
toastr.success(`${sectionTitles[sectionKey]} 已成功导入(使用默认条件块顺序)!`);
|
|
} else {
|
|
throw new Error("无法识别的文件格式或不包含对应section数据");
|
|
}
|
|
|
|
state.setCurrentPresets(currentPresets);
|
|
state.setCurrentMixedOrder(currentMixedOrder);
|
|
state.savePresets();
|
|
if (context && context.length) {
|
|
ui.renderEditor(context);
|
|
}
|
|
} catch (error) {
|
|
console.error("Import section error:", error);
|
|
toastr.error(`导入失败:${error.message}`);
|
|
}
|
|
};
|
|
reader.readAsText(file);
|
|
}
|
|
};
|
|
input.click();
|
|
}
|
|
|
|
function exportAllPresets() {
|
|
const activePresetName = state.getPresetManager().activePreset;
|
|
const exportData = {
|
|
version: 'v2.1',
|
|
presets: state.getCurrentPresets(),
|
|
mixedOrder: state.getCurrentMixedOrder(),
|
|
presetName: activePresetName,
|
|
exportTime: new Date().toISOString()
|
|
};
|
|
|
|
const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = `amily2_all_presets_${activePresetName}.json`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
|
|
toastr.success(`预设 "${activePresetName}" 的所有配置已导出!`);
|
|
}
|
|
|
|
function importAllPresets(context) {
|
|
const input = document.createElement('input');
|
|
input.type = 'file';
|
|
input.accept = '.json';
|
|
input.onchange = (event) => {
|
|
const file = event.target.files[0];
|
|
if (file) {
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
try {
|
|
const imported = JSON.parse(e.target.result);
|
|
|
|
if (imported.version === 'v2.1' && imported.presets && imported.mixedOrder) {
|
|
state.setCurrentPresets(imported.presets);
|
|
state.setCurrentMixedOrder(imported.mixedOrder);
|
|
state.savePresets();
|
|
toastr.success(`所有配置已成功导入!`);
|
|
if (context && context.length) {
|
|
ui.renderEditor(context);
|
|
}
|
|
} else {
|
|
throw new Error("无法识别的文件格式或不是完整的预设配置");
|
|
}
|
|
} catch (error) {
|
|
console.error("Import all presets error:", error);
|
|
toastr.error(`导入失败:${error.message}`);
|
|
}
|
|
};
|
|
reader.readAsText(file);
|
|
}
|
|
};
|
|
input.click();
|
|
}
|
|
|
|
export function bindEvents(context) {
|
|
context.find('.add-prompt-item').off('click.amily2').on('click.amily2', function() {
|
|
const sectionKey = $(this).closest('.prompt-section').data('section');
|
|
const currentPresets = state.getCurrentPresets();
|
|
const currentMixedOrder = state.getCurrentMixedOrder();
|
|
|
|
currentPresets[sectionKey].push({ role: 'system', content: '' });
|
|
currentMixedOrder[sectionKey].push({ type: 'prompt', index: currentPresets[sectionKey].length - 1 });
|
|
|
|
state.setCurrentPresets(currentPresets);
|
|
state.setCurrentMixedOrder(currentMixedOrder);
|
|
|
|
ui.renderEditor(context);
|
|
toastr.info('新提示词已添加,点击保存按钮完成操作');
|
|
});
|
|
|
|
context.find('.delete-mixed-item').off('click.amily2').on('click.amily2', function() {
|
|
const item = $(this).closest('.mixed-item');
|
|
const sectionKey = item.data('section');
|
|
const orderIndex = item.data('order-index');
|
|
const itemType = item.data('type');
|
|
|
|
const currentPresets = state.getCurrentPresets();
|
|
const currentMixedOrder = state.getCurrentMixedOrder();
|
|
|
|
if (itemType === 'prompt') {
|
|
const promptIndex = item.data('prompt-index');
|
|
currentPresets[sectionKey].splice(promptIndex, 1);
|
|
currentMixedOrder[sectionKey].forEach(orderItem => {
|
|
if (orderItem.type === 'prompt' && orderItem.index > promptIndex) {
|
|
orderItem.index--;
|
|
}
|
|
});
|
|
}
|
|
|
|
currentMixedOrder[sectionKey].splice(orderIndex, 1);
|
|
|
|
state.setCurrentPresets(currentPresets);
|
|
state.setCurrentMixedOrder(currentMixedOrder);
|
|
|
|
ui.renderEditor(context);
|
|
toastr.info('项目已删除,点击保存按钮完成操作');
|
|
});
|
|
|
|
context.off('change.amily2', '.role-select').on('change.amily2', '.role-select', function() {
|
|
updatePresetsFromUI(context);
|
|
});
|
|
|
|
context.off('input.amily2 paste.amily2 keyup.amily2', '.content-textarea').on('input.amily2 paste.amily2 keyup.amily2', function() {
|
|
updatePresetsFromUI(context);
|
|
});
|
|
|
|
context.find('#preset-select').off('change.amily2').on('change.amily2', function() {
|
|
const selectedPreset = $(this).val();
|
|
if (state.switchPreset(selectedPreset)) {
|
|
ui.renderEditor(context);
|
|
}
|
|
});
|
|
|
|
context.find('#new-preset').off('click.amily2').on('click.amily2', () => {
|
|
if (state.createNewPreset()) {
|
|
ui.renderPresetManager(context);
|
|
ui.renderEditor(context);
|
|
}
|
|
});
|
|
|
|
context.find('#rename-preset').off('click.amily2').on('click.amily2', () => {
|
|
if (state.renamePreset()) {
|
|
ui.renderPresetManager(context);
|
|
ui.renderEditor(context);
|
|
}
|
|
});
|
|
|
|
context.find('#delete-preset').off('click.amily2').on('click.amily2', () => {
|
|
if (state.deletePreset()) {
|
|
ui.renderPresetManager(context);
|
|
ui.renderEditor(context);
|
|
}
|
|
});
|
|
|
|
context.find('.save-section-preset').off('click.amily2').on('click.amily2', function() {
|
|
const sectionKey = $(this).closest('.prompt-section').data('section');
|
|
updatePresetsFromUI(context);
|
|
state.savePresets();
|
|
toastr.success(`${sectionTitles[sectionKey]} in preset "${state.getPresetManager().activePreset}" has been saved!`);
|
|
});
|
|
|
|
context.find('.import-section-preset').off('click.amily2').on('click.amily2', function() {
|
|
const sectionKey = $(this).closest('.prompt-section').data('section');
|
|
importSectionPreset(sectionKey, context);
|
|
});
|
|
|
|
context.find('.export-section-preset').off('click.amily2').on('click.amily2', function() {
|
|
const sectionKey = $(this).closest('.prompt-section').data('section');
|
|
exportSectionPreset(sectionKey);
|
|
});
|
|
|
|
context.find('.reset-section-preset').off('click.amily2').on('click.amily2', function() {
|
|
const sectionKey = $(this).closest('.prompt-section').data('section');
|
|
if (confirm(`您确定要将 ${sectionTitles[sectionKey]} 恢复为默认设置吗?`)) {
|
|
state.resetSectionPreset(sectionKey);
|
|
ui.renderEditor(context);
|
|
}
|
|
});
|
|
|
|
// 全局按钮事件绑定
|
|
context.find('#save-all-presets').off('click.amily2').on('click.amily2', function() {
|
|
updatePresetsFromUI(context);
|
|
state.savePresets();
|
|
toastr.success(`预设 "${state.getPresetManager().activePreset}" 的所有配置已保存!`);
|
|
});
|
|
|
|
context.find('#export-all-presets').off('click.amily2').on('click.amily2', function() {
|
|
exportAllPresets();
|
|
});
|
|
|
|
context.find('#import-all-presets').off('click.amily2').on('click.amily2', function() {
|
|
importAllPresets(context);
|
|
});
|
|
|
|
context.find('#reset-all-presets').off('click.amily2').on('click.amily2', function() {
|
|
if (confirm("您确定要将当前预设的所有配置恢复为默认状态吗?此操作无法撤销。")) {
|
|
state.resetPresets();
|
|
ui.renderEditor(context);
|
|
}
|
|
});
|
|
|
|
context.find('.collapsible-header').off('click.amily2').on('click.amily2', function() {
|
|
const sectionKey = $(this).closest('.prompt-section').data('section');
|
|
const content = $(this).next('.collapsible-content');
|
|
const icon = $(this).find('.collapse-icon');
|
|
const globalCollapseState = ui.getGlobalCollapseState();
|
|
|
|
content.slideToggle(200, function() {
|
|
const isVisible = content.is(':visible');
|
|
icon.text(isVisible ? '▼' : '▶');
|
|
globalCollapseState[sectionKey] = isVisible;
|
|
});
|
|
});
|
|
|
|
bindDragEvents(context);
|
|
}
|