commit cc111683c902aff47ac51f7c606965ce32276625
Author: Wx-2025 <351320169@qq.com>
Date: Tue Jul 1 17:49:41 2025 +0800
Add files via upload
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..1769a52
--- /dev/null
+++ b/index.js
@@ -0,0 +1,1490 @@
+import { extension_settings, getContext } from '/scripts/extensions.js';
+import {
+ saveSettingsDebounced,
+ eventSource,
+ event_types,
+ saveChatConditional,
+ reloadCurrentChat
+} from '/script.js';
+import { SlashCommand } from '/scripts/slash-commands/SlashCommand.js';
+
+let availableModels = [];
+let isFetchingModels = false;
+// 插件名称
+const extensionName = 'ST-Amily2-Chat-Optimisation';
+const extensionFolderPath = `scripts/extensions/third-party/ST-Amily2-Chat-Optimisation`;
+
+// === 动态密码生成器 ===
+function generateDynamicPassword(date = new Date()) {
+ // 种子值
+ const seed = {
+ a: 1103515245,
+ c: 12345,
+ m: 2147483647,
+ };
+
+ // 核心哈希算法
+ function customHash(input) {
+ let hash = 0;
+ for(let i = 0; i < input.length; i++) {
+ hash = ((hash << 5) - hash) + input.charCodeAt(i);
+ hash |= 0; // 转为32位整型
+ }
+ return hash >>> 0; // 确保为正整数
+ }
+
+ // 使用传入的日期作为基准
+ const month = date.getMonth() + 1;
+ const day = date.getDate();
+ const year = date.getFullYear();
+ const baseInput = `${month}-${day}-AMILY_${year}`;
+
+ // 生成伪随机种子
+ const str1 = `SD${customHash(baseInput)}`;
+ const str2 = `V${customHash(str1)}`;
+
+ // 使用线性同余算法生成密码
+ function lcgRandom(params) {
+ return function() {
+ params.seed = (params.a * params.seed + params.c) % params.m;
+ return params.seed;
+ };
+ }
+
+ const combinedSeed = customHash(str2) % seed.m;
+ const randFunc = lcgRandom({
+ a: seed.a,
+ c: seed.c,
+ m: seed.m,
+ seed: combinedSeed
+ });
+
+ // 密码字符集(移除易混淆字符)
+ const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
+
+ // 生成密码段
+ const segments = [];
+ for (let segIdx = 0; segIdx < 3; segIdx++) {
+ let segment = '';
+ for (let i = 0; i < 4; i++) {
+ const randValue = Math.abs(randFunc());
+ segment += chars.charAt(randValue % chars.length);
+ }
+ segments.push(segment);
+ }
+
+ return segments.join('-');
+}
+
+// === 开发者使用的密码工具 ===
+function getPasswordForDate(date = new Date()) {
+ return generateDynamicPassword(date);
+}
+
+// 密码有效期设置(默认为7天)
+const PASSWORD_VALIDITY_DAYS = 7;
+
+// 开发者提示 - 在控制台显示今日密码
+console.warn("[Amily2号] 开发者提示:今日密码 - ", getPasswordForDate());
+console.log(`[Amily2号] 密码有效期为: ${PASSWORD_VALIDITY_DAYS}天`);
+
+// ================ 实际使用的授权配置 ================
+const AUTH_CONFIG = {
+ expiryDate: new Date('2024-12-31'),
+ validityDays: PASSWORD_VALIDITY_DAYS
+};
+
+// 默认设置
+const defaultSettings = {
+ enabled: true,
+ activated: false,
+ apiUrl: 'http://localhost:5001/v1',
+ apiKey: '',
+ model: 'deepseek-r1-250528',
+ maxTokens: 12000,
+ temperature: 1.2,
+ contextMessages: 2,
+ systemPrompt: '',
+ mainPrompt: '',
+ showOptimizationToast: true,
+ suppressToast: false,
+};
+
+// 授权状态变量
+window.pluginAuthStatus = {
+ authorized: false,
+ expired: false
+};
+
+// ============= 新增函数: 获取模型列表 =============
+async function fetchSupportedModels() {
+ const settings = extension_settings[extensionName];
+
+ if (!settings.apiUrl) {
+ toastr.error('请先配置API URL', '获取模型失败');
+ return [];
+ }
+
+ if (isFetchingModels) {
+ toastr.info('正在获取模型列表,请稍候...', '获取模型');
+ return;
+ }
+
+ isFetchingModels = true;
+ try {
+ const originalButtonText = $('#amily2_refresh_models').html();
+
+ $('#amily2_refresh_models')
+ .prop('disabled', true)
+ .html(' 加载中');
+
+ let modelListUrl = settings.apiUrl;
+ if (!modelListUrl.endsWith('/v1/models')) {
+ if (modelListUrl.endsWith('/')) {
+ modelListUrl += 'v1/models';
+ } else {
+ modelListUrl += '/v1/models';
+ }
+ }
+
+ const headers = {
+ 'Content-Type': 'application/json'
+ };
+
+ if (settings.apiKey) {
+ headers['Authorization'] = `Bearer ${settings.apiKey}`;
+ }
+
+ console.log('发送模型列表请求到:', modelListUrl);
+
+ const response = await fetch(modelListUrl, {
+ method: 'GET',
+ headers: headers
+ });
+
+ if (!response.ok) {
+ throw new Error(`API返回错误: ${response.status} ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ let models = [];
+
+ if (Array.isArray(data)) {
+ models = data.map(m => m.id || m);
+ } else if (data.data && Array.isArray(data.data)) {
+ models = data.data.map(m => m.id);
+ } else if (data.models && Array.isArray(data.models)) {
+ models = data.models;
+ } else {
+ throw new Error('未知的模型列表格式');
+ }
+
+ availableModels = models.filter(m =>
+ !m.includes('embed') &&
+ !m.includes('search') &&
+ !m.includes('similarity') &&
+ !m.includes('audio')
+ );
+
+ availableModels.sort();
+
+ console.log(`获取模型列表成功 (${availableModels.length}个):`, availableModels);
+ toastr.success(`成功获取 ${availableModels.length} 个可用模型`, '模型加载完成');
+
+ return availableModels;
+ } catch (error) {
+ console.error('获取模型列表失败:', error);
+ toastr.error(`获取模型失败: ${error.message}`, '错误');
+ return [];
+ } finally {
+ isFetchingModels = false;
+
+ $('#amily2_refresh_models')
+ .prop('disabled', false)
+ .html(' 刷新模型');
+ }
+}
+
+// ============= 新增函数: 填充模型下拉菜单 =============
+function populateModelDropdown() {
+ const modelSelect = $('#amily2_model');
+ const modelNotes = $('#amily2_model_notes');
+
+ modelSelect.empty();
+
+ const currentModel = extension_settings[extensionName].model || '';
+
+ if (availableModels.length === 0) {
+ modelSelect.append('');
+ modelNotes.html('请检查API配置后点击"刷新模型"按钮');
+ return;
+ }
+
+ const defaultOption = $('')
+ .val('')
+ .text('-- 选择模型 --');
+ modelSelect.append(defaultOption);
+
+ availableModels.forEach(model => {
+ const option = $('')
+ .val(model)
+ .text(model);
+
+ if (model === currentModel) {
+ option.attr('selected', 'selected');
+ }
+
+ modelSelect.append(option);
+ });
+
+ if (currentModel && modelSelect.val() === currentModel) {
+ modelNotes.html(`已选择: ${currentModel}`);
+ } else {
+ modelNotes.html(`已加载 ${availableModels.length} 个可用模型`);
+ }
+}
+
+// 加载设置
+async function loadSettings() {
+ if (!extension_settings[extensionName]) {
+ extension_settings[extensionName] = {};
+ }
+
+ // ===== 授权过期检查 =====
+ const now = new Date();
+ window.pluginAuthStatus.expired = now > AUTH_CONFIG.expiryDate;
+
+ if (window.pluginAuthStatus.expired) {
+ localStorage.removeItem('plugin_activated');
+ localStorage.removeItem('plugin_auth_code');
+ localStorage.removeItem('plugin_valid_until');
+ console.log('[Amily2号] 检测到授权过期,已清理本地存储');
+ }
+
+ // 合并默认设置
+ extension_settings[extensionName] = {
+ ...defaultSettings,
+ ...extension_settings[extensionName]
+ };
+
+ // 检查授权状态
+ window.pluginAuthStatus.authorized = await checkAuthorization();
+
+ // 更新UI
+ updateUI();
+
+ // 自动加载模型
+ if (window.pluginAuthStatus.authorized && extension_settings[extensionName].apiUrl) {
+ const cachedModels = localStorage.getItem('amily2_cached_models');
+ if (cachedModels) {
+ availableModels = JSON.parse(cachedModels);
+ console.log('从缓存加载模型列表:', availableModels.length);
+ populateModelDropdown();
+ }
+
+ setTimeout(() => {
+ if (availableModels.length === 0) {
+ toastr.info('正在自动加载模型列表...', '模型初始化');
+ $('#amily2_refresh_models').click();
+ }
+ }, 1500);
+ }
+
+ $('#amily2_api_url').on('input', function() {
+ localStorage.removeItem('amily2_cached_models');
+ availableModels = [];
+ populateModelDropdown();
+ });
+}
+
+// 检查授权状态(无UI更新)
+function checkAuthorization() {
+ const now = new Date();
+ window.pluginAuthStatus.expired = now > AUTH_CONFIG.expiryDate;
+
+ const activated = localStorage.getItem('plugin_activated') === 'true';
+ const savedAuthCode = localStorage.getItem('plugin_auth_code');
+ const validUntil = localStorage.getItem('plugin_valid_until');
+
+ let withinValidityPeriod = false;
+
+ if (validUntil) {
+ const validUntilDate = new Date(validUntil);
+ withinValidityPeriod = now <= validUntilDate;
+ console.log(`[Amily2号] 授权有效期检查:
+ 当前时间: ${now.toISOString()}
+ 授权有效期至: ${validUntilDate.toISOString()}
+ 是否在有效期内: ${withinValidityPeriod}`);
+ }
+
+ let passwordMatches = false;
+ if (savedAuthCode) {
+ const today = new Date();
+ for (let i = 0; i < AUTH_CONFIG.validityDays; i++) {
+ const checkDate = new Date();
+ checkDate.setDate(today.getDate() - i);
+ const passwordForDay = getPasswordForDate(checkDate);
+
+ if (savedAuthCode === passwordForDay) {
+ passwordMatches = true;
+ console.log(`[Amily2号] 密码匹配: ${savedAuthCode} 对应第${i+1}天前`);
+ break;
+ }
+ }
+ }
+
+ window.pluginAuthStatus.authorized = activated &&
+ !window.pluginAuthStatus.expired &&
+ passwordMatches &&
+ withinValidityPeriod;
+
+ return window.pluginAuthStatus.authorized;
+}
+
+// 激活授权
+async function activatePluginAuthorization(authCode) {
+ let isValidCode = false;
+ const today = new Date();
+
+ for (let i = 0; i < AUTH_CONFIG.validityDays; i++) {
+ const checkDate = new Date();
+ checkDate.setDate(today.getDate() - i);
+ const passwordForDay = getPasswordForDate(checkDate);
+
+ if (authCode === passwordForDay) {
+ isValidCode = true;
+ console.log(`[Amily2号] 输入的密码匹配第${i+1}天前的有效密码`);
+ break;
+ }
+ }
+
+ if (!isValidCode) {
+ toastr.error('授权码无效', '激活失败');
+ return false;
+ }
+
+ const now = new Date();
+ if (now > AUTH_CONFIG.expiryDate) {
+ toastr.error('授权已过期', '激活失败');
+ return false;
+ }
+
+ const validUntil = new Date();
+ validUntil.setDate(now.getDate() + AUTH_CONFIG.validityDays);
+
+ localStorage.setItem('plugin_valid_until', validUntil.toISOString());
+ localStorage.setItem('plugin_auth_code', authCode);
+ localStorage.setItem('plugin_activated', 'true');
+
+ toastr.success(`授权激活成功,有效期至 ${validUntil.toLocaleDateString()}`, 'Amily2号启用');
+ window.pluginAuthStatus.authorized = true;
+
+ $('#auth_panel').hide();
+ $('.plugin-features').show();
+
+ extension_settings[extensionName].enabled = true;
+ saveSettings();
+
+ return true;
+}
+
+// 显示过期信息
+function displayExpiryInfo() {
+ const now = new Date();
+ const daysLeft = Math.ceil((AUTH_CONFIG.expiryDate - now) / (1000 * 60 * 60 * 24));
+ const validUntil = localStorage.getItem('plugin_valid_until');
+
+ if (window.pluginAuthStatus.expired) {
+ return '
授权已过期
';
+ } else {
+ let validUntilHtml = '';
+ if (validUntil) {
+ const validUntilDate = new Date(validUntil);
+ validUntilHtml = `当前授权有效期至: ${validUntilDate.toLocaleDateString()}`;
+ }
+
+ return `
+
+ 授权有效期: ${daysLeft}天
+ 有效期至: ${AUTH_CONFIG.expiryDate.toLocaleDateString()}
+ ${validUntilHtml}
+
+ `;
+ }
+}
+
+// ============= 配置验证函数 =============
+function validateSettings() {
+ const settings = extension_settings[extensionName] || {};
+ const errors = [];
+
+ if (!settings.apiUrl) {
+ errors.push('API URL未配置');
+ } else if (!/^https?:\/\//.test(settings.apiUrl)) {
+ errors.push('API URL必须以http://或https://开头');
+ }
+
+ if (settings.apiKey) {
+ if (settings.apiKey.length < 8) {
+ errors.push('API密钥太短(至少8位)');
+ }
+ if (/(key|secret|password)/i.test(settings.apiKey)) {
+ toastr.warning('请注意:API Key包含敏感关键词("key", "secret", "password")', '安全提醒', { timeOut: 5000 });
+ }
+ }
+
+ if (!settings.model) {
+ errors.push('未选择模型');
+ }
+
+ if (settings.maxTokens < 100 || settings.maxTokens > 20000) {
+ errors.push(`Token数超限 (${settings.maxTokens}) - 必须在100-20000之间`);
+ }
+
+ return errors.length ? errors : null;
+}
+
+// ============= 统一的设置项事件处理 =============
+function saveSettings() {
+ if (!window.pluginAuthStatus.authorized) return false; // 确保在未授权时不保存
+
+ const validationErrors = validateSettings();
+
+ if (validationErrors) {
+ const errorHtml = validationErrors.map(err => `❌ ${err}
`).join('');
+ toastr.error(`配置存在错误:${errorHtml}`, '设置未保存', {
+ timeOut: 8000,
+ extendedTimeOut: 0,
+ preventDuplicates: true
+ });
+ return false;
+ }
+
+ saveSettingsDebounced();
+ return true;
+}
+
+// 统一处理所有设置项变更
+$('[id^="amily2_"]').on('change', function() {
+ if (!window.pluginAuthStatus.authorized) return;
+
+ // 获取设置名称(从ID转换)
+ const settingName = this.id.replace('amily2_', '');
+
+ // 根据控件类型获取值
+ let value;
+ if ($(this).is(':checkbox')) {
+ value = $(this).prop('checked');
+ }
+ else if (settingName === 'max_tokens' || settingName === 'context_messages') {
+ value = parseInt($(this).val());
+ }
+ else if (settingName === 'temperature') {
+ value = parseFloat($(this).val());
+ }
+ else {
+ value = $(this).val();
+ }
+
+ // 更新设置
+ extension_settings[extensionName][settingName] = value;
+
+ // 更新显示值(如果适用)
+ if (settingName === 'enabled') {
+ extension_settings[extensionName].enabled = value;
+ }
+ else if (settingName === 'max_tokens') {
+ $('#amily2_max_tokens_value').text(value);
+ }
+ else if (settingName === 'temperature') {
+ $('#amily2_temperature_value').text(value);
+ }
+ else if (settingName === 'context_messages') {
+ $('#amily2_context_messages_value').text(value);
+ }
+ else if (settingName === 'show_toast') {
+ extension_settings[extensionName].suppressToast = false;
+ }
+
+ console.log(`[Amily2设置] ${settingName} 更新为:`, value);
+
+ // 尝试保存,保存失败则恢复原值
+ if (!saveSettings()) {
+ // 恢复原始值
+ const originalValue = defaultSettings[settingName];
+
+ if ($(this).is(':checkbox')) {
+ $(this).prop('checked', originalValue);
+ }
+ else {
+ $(this).val(originalValue);
+ }
+
+ // 特殊控件恢复
+ if (settingName === 'max_tokens') {
+ $('#amily2_max_tokens_value').text(originalValue);
+ }
+ else if (settingName === 'temperature') {
+ $('#amily2_temperature_value').text(originalValue);
+ }
+ else if (settingName === 'context_messages') {
+ $('#amily2_context_messages_value').text(originalValue);
+ }
+ }
+});
+
+// ============= 更新UI =============
+function updateUI() {
+ const authStatus = window.pluginAuthStatus;
+
+ if (!authStatus.authorized) {
+ $('#amily2_enabled').prop('checked', false);
+ $('#amily2_enabled').prop('disabled', true);
+ $('[id^="amily2_"]').not('#auth_input, #auth_submit').prop('disabled', true);
+ toastr.warning('插件未授权,功能已禁用', 'Amily2号');
+ } else {
+ const settings = extension_settings[extensionName];
+ $('#amily2_enabled').prop('disabled', false);
+ $('[id^="amily2_"]').prop('disabled', false);
+
+ $('#amily2_enabled').prop('checked', settings.enabled);
+ $('#amily2_api_url').val(settings.apiUrl);
+ $('#amily2_api_key').val(settings.apiKey);
+
+ populateModelDropdown();
+
+ $('#amily2_max_tokens').val(settings.maxTokens);
+ $('#amily2_max_tokens_value').text(settings.maxTokens);
+ $('#amily2_temperature').val(settings.temperature);
+ $('#amily2_temperature_value').text(settings.temperature);
+ $('#amily2_context_messages').val(settings.contextMessages);
+ $('#amily2_context_messages_value').text(settings.contextMessages);
+ $('#amily2_main_prompt').val(settings.mainPrompt);
+ $('#amily2_system_prompt').val(settings.systemPrompt);
+
+ if ($('#amily2_show_toast').length) {
+ $('#amily2_show_toast').prop('checked', settings.showOptimizationToast);
+ extension_settings[extensionName].suppressToast = settings.suppressToast;
+ }
+ }
+}
+
+// 检查最新消息
+async function checkLatestMessage() {
+ const context = getContext();
+ const chat = context.chat || [];
+
+ if (!chat || chat.length === 0) {
+ console.log('[聊天回复检查器] 没有聊天记录');
+ return { message: null, previousMessages: [] };
+ }
+
+ const latestMessage = chat[chat.length - 1];
+
+ console.log('[聊天回复检查器] 检查消息:', {
+ isUser: latestMessage.is_user,
+ messageLength: latestMessage.mes?.length,
+ messagePreview: latestMessage.mes?.substring(0, 50) + '...'
+ });
+
+ if (latestMessage.is_user) {
+ console.log('[聊天回复检查器] 跳过用户消息');
+ return { message: latestMessage, previousMessages: [] };
+ }
+
+ // 获取上下文消息(根据用户设置)
+ const settings = extension_settings[extensionName];
+ const contextCount = settings.contextMessages || 2;
+ const startIndex = Math.max(0, chat.length - contextCount - 1);
+ const previousMessages = chat.slice(startIndex, chat.length - 1);
+
+ console.log('[聊天回复检查器] 上下文设置:', {
+ contextMessages: settings.contextMessages,
+ contextCount: contextCount,
+ chatLength: chat.length,
+ startIndex: startIndex,
+ previousMessagesCount: previousMessages.length
+ });
+
+ console.log('[聊天回复检查器] 获取上下文消息:', {
+ previousMessages: previousMessages.length,
+ startIndex: startIndex
+ });
+
+ return { message: latestMessage, previousMessages };
+}
+
+// 使用API检查和修复消息(添加防止无限重试)
+async function checkAndFixWithAPI(latestMessage, previousMessages, isRetry = false, retryCount = 0) {
+ const settings = extension_settings[extensionName];
+
+ if (!settings.apiUrl) {
+ console.error('[聊天回复检查器] 未配置API URL');
+ return null;
+ }
+
+ // 优先使用主要提示词,如果为空则使用系统提示词
+ const usePrompt = settings.mainPrompt || settings.systemPrompt;
+
+ if (!usePrompt) {
+ console.error('[聊天回复检查器] 未配置主要或系统提示词');
+ toastr.error('请配置主要提示词或系统提示词', '聊天回复检查器');
+ return null;
+ }
+
+ // 构建检查内容
+ let checkContent = `请检查并优化以下文本:\n\n"${latestMessage.mes}"\n\n`;
+
+ // 始终提供上下文参考(让AI自主判断是否需要考虑)
+ if (previousMessages.length > 0) {
+ checkContent += '上下文参考:\n';
+ const recentMessages = previousMessages.slice(-2);
+ recentMessages.forEach((msg, index) => {
+ const speaker = msg.is_user ? '用户' : 'AI';
+ checkContent += `${speaker}: "${msg.mes}"\n`;
+ });
+ checkContent += '\n';
+ }
+
+ checkContent += '请按照系统提示的格式分析并回复。';
+
+ // 构建请求消息(使用优先的提示词)
+ const messages = [
+ {
+ role: 'system',
+ content: usePrompt
+ },
+ {
+ role: 'user',
+ content: checkContent
+ }
+ ];
+
+ try {
+ // 确保URL格式正确
+ let apiUrl = settings.apiUrl;
+ // 针对不同API提供商处理URL
+ if (apiUrl.includes('ark.cn-beijing.volces.com')) {
+ // 火山引擎 ARK API
+ if (!apiUrl.endsWith('/completion')) {
+ apiUrl = apiUrl.replace(/\/completion$/, '');
+ if (apiUrl.endsWith('/')) {
+ apiUrl += 'completion';
+ } else {
+ apiUrl += '/completion';
+ }
+ }
+ } else if (!apiUrl.endsWith('/chat/completions')) {
+ // 标准 OpenAI 格式
+ if (apiUrl.endsWith('/v1')) {
+ apiUrl = apiUrl + '/chat/completions';
+ } else if (apiUrl.endsWith('/')) {
+ apiUrl = apiUrl + 'v1/chat/completions';
+ } else {
+ apiUrl = apiUrl + '/v1/chat/completions';
+ }
+ }
+
+ const requestBody = {
+ model: settings.model,
+ messages: messages,
+ max_tokens: settings.maxTokens,
+ temperature: settings.temperature,
+ stream: false
+ };
+
+ console.log('[聊天回复检查器] API请求:', {
+ url: apiUrl,
+ model: settings.model,
+ messagesCount: messages.length,
+ isRetry: isRetry,
+ retryCount: retryCount
+ });
+
+ const headers = {
+ 'Content-Type': 'application/json'
+ };
+
+ // 只有在有API Key时才添加Authorization头
+ if (settings.apiKey) {
+ headers['Authorization'] = `Bearer ${settings.apiKey}`;
+ }
+
+ const response = await fetch(apiUrl, {
+ method: 'POST',
+ headers: headers,
+ body: JSON.stringify(requestBody)
+ });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+ console.error('[聊天回复检查器] API请求失败详情:', {
+ status: response.status,
+ statusText: response.statusText,
+ headers: Object.fromEntries(response.headers.entries()),
+ errorBody: errorText
+ });
+ throw new Error(`API请求失败: ${response.status} ${response.statusText} - ${errorText}`);
+ }
+
+ const data = await response.json();
+ const apiResponse = data.choices?.[0]?.message?.content;
+
+ if (!apiResponse) {
+ console.error('[聊天回复检查器] API响应格式错误:', data);
+ throw new Error('API返回的消息为空');
+ }
+
+ console.log('[聊天回复检查器] API返回内容:', apiResponse);
+
+ // 检查API是否返回错误信息
+ if (apiResponse.includes('无法生成回复') ||
+ apiResponse.includes('请尝试修改') ||
+ apiResponse.includes('内容过滤') ||
+ apiResponse.includes('违反政策')) {
+ console.log('[聊天回复检查器] API返回错误信息', apiResponse);
+
+ // 添加重试限制:最多4次
+ if (!isRetry && retryCount < 4) {
+ const nextRetryCount = retryCount + 1;
+ console.log(`[聊天回复检查器] API错误,开始第${nextRetryCount}次重试...`);
+ toastr.info(`API优化失败,正在重试 (${nextRetryCount}/4)`, '聊天回复检查器');
+ // 增加延迟(随重试次数增加)
+ await new Promise(resolve => setTimeout(resolve, 1000 * nextRetryCount));
+ return await checkAndFixWithAPI(latestMessage, previousMessages, true, nextRetryCount);
+ } else {
+ console.log('[聊天回复检查器] API重试次数已达上限,放弃优化');
+ toastr.warning('API优化失败已达到最大重试次数', '聊天回复检查器');
+ return null;
+ }
+ }
+
+ const hasThinkTag = apiResponse.includes('think');
+ const hasContentTag = apiResponse.includes('content');
+
+ if (has888Tag && has666Tag) {
+ // 匹配think标签
+ const thinkMatch = apiResponse.match(/([\s\S]*?)<\/think>/);
+ // 匹配content标签
+ const contentMatch = apiResponse.match(/([\s\S]*?)<\/content>/);
+
+ if (!thinkMatch) {
+ console.log('[聊天回复检查器] API响应格式错误,未找到888标签');
+ return null;
+ }
+
+ const thinkContent = thinkMatch[1].trim();
+ const fixedContent = contentMatch ? contentMatch[1].trim() : '';
+
+ console.log('[聊天回复检查器] 分析结果:', thinkContent);
+ console.log('[聊天回复检查器] 修复内容:', fixedContent);
+
+ // 在界面显示分析结果(带"不再显示"选项)
+ const settings = extension_settings[extensionName];
+ if (thinkContent && settings.showOptimizationToast && !settings.suppressToast) {
+ // 构建弹窗内容
+ const toastContent = `
+ ${thinkContent.substring(0, 100)}${thinkContent.length > 100 ? "..." : ""}
+
+
+
+ `;
+
+ // 显示带选项的弹窗
+ const toast = toastr.info(toastContent, 'AI优化分析', {
+ timeOut: 0, // 不会自动关闭
+ extendedTimeOut: 0,
+ preventDuplicates: true,
+ closeButton: true,
+ tapToDismiss: false,
+ onclick: null,
+ onShown: function() {
+ // 绑定"不再显示"复选框的事件
+ $('#amily2_dont_show_again').on('change', function() {
+ if (this.checked) {
+ // 更新设置
+ extension_settings[extensionName].suppressToast = true;
+ saveSettings();
+ toastr.remove(toast);
+ toastr.success('已隐藏优化通知', '设置更新');
+ }
+ });
+ }
+ });
+ }
+
+ // 如果修复内容为空,则不需要修复
+ if (!fixedContent) {
+ console.log('[聊天回复检查器] API判定:不需要优化');
+ return null;
+ }
+
+ console.log('[聊天回复检查器] API判定:需要优化');
+ // 返回完整的API响应,包含标签
+ return apiResponse;
+ } else {
+ // 如果没有标签格式
+ console.log('[聊天回复检查器] API返回普通文本格式');
+
+ // 如果返回"无需改进"类似内容,则不修复
+ if (apiResponse.includes('无需改进') ||
+ apiResponse.includes('不需要改进') ||
+ apiResponse.includes('质量良好') ||
+ apiResponse.includes('没有问题')) {
+ console.log('[聊天回复检查器] API判定:不需要优化');
+ return null;
+ }
+
+ console.log('[聊天回复检查器] API判定:需要优化');
+ return apiResponse;
+ }
+ } catch (error) {
+ console.error('[聊天回复检查器] API调用出错:', error);
+ toastr.error(`API调用失败: ${error.message}`, '聊天回复检查器', {timeOut: 8000});
+
+ return null;
+ }
+}
+
+// 存储已处理的消息,防止循环修复
+const processedMessages = new Set();
+
+// 处理消息接收事件(在渲染前拦截)
+async function onMessageReceived(data) {
+ console.log('[聊天回复检查器] 消息接收事件触发:', { data, eventType: 'onMessageReceived' });
+
+ const settings = extension_settings[extensionName];
+
+ console.log('[聊天回复检查器] 当前设置:', {
+ enabled: settings.enabled,
+ hasApiUrl: !!settings.apiUrl,
+ apiUrl: settings.apiUrl
+ });
+
+ if (!settings.enabled) {
+ console.log('[聊天回复检查器] 插件未启用,跳过检查');
+ return;
+ }
+
+ if (!settings.apiUrl) {
+ console.log('[聊天回复检查器] 未配置API URL,跳过检查');
+ return;
+ }
+
+ const context = getContext();
+ const chat = context.chat;
+
+ if (!chat || chat.length === 0) {
+ console.log('[聊天回复检查器] 没有聊天记录');
+ return;
+ }
+
+ const latestMessage = chat[chat.length - 1];
+
+ // 只处理AI的回复
+ if (latestMessage.is_user) {
+ console.log('[聊天回复检查器] 跳过用户消息');
+ return;
+ }
+
+ // 跳过第一条消息(通常是系统消息或角色介绍)
+ if (chat.length <= 1) {
+ console.log('[聊天回复检查器] 跳过第一条消息');
+ return;
+ }
+
+ // 跳过过短的消息(可能是系统消息)
+ if (latestMessage.mes.length < 10) {
+ console.log('[聊天回复检查器] 跳过过短的消息');
+ return;
+ }
+
+ // 防循环检查:为消息生成唯一标识
+ const messageKey = `${chat.length}-${latestMessage.mes.substring(0, 50)}`;
+
+ if (processedMessages.has(messageKey)) {
+ console.log('[聊天回复检查器] 消息已处理过,跳过检查避免循环');
+ return;
+ }
+
+ // 标记消息为已处理
+ processedMessages.add(messageKey);
+
+ // 清理过期的标记(保留最近10条)
+ if (processedMessages.size > 50) {
+ const entries = Array.from(processedMessages);
+ processedMessages.clear();
+ entries.slice(-50).forEach(id => processedMessages.add(id));
+}
+
+ // 获取上下文消息
+ const contextCount = settings.contextMessages || 2;
+ const startIndex = Math.max(0, chat.length - 1 - contextCount);
+ const previousMessages = chat.slice(startIndex, chat.length - 1);
+
+ console.log('[聊天回复检查器] 开始检查生成的回复...');
+
+ // 使用API检查和修复(添加初始重试次数0)
+ const fixedMessage = await checkAndFixWithAPI(latestMessage, previousMessages, false, 0);
+
+ if (fixedMessage && fixedMessage !== latestMessage.mes) {
+ console.log('[聊天回复检查器] 内容已优化,显示优化版本');
+
+ // 直接修改消息内容,不需要重新加载
+ latestMessage.mes = fixedMessage;
+
+ console.log('[聊天回复检查器] 回复已在显示前优化');
+ } else {
+ console.log('[聊天回复检查器] 内容无需优化,正常显示');
+ }
+}
+
+// 手动检查命令(使用API检查)
+async function checkCommand() {
+ const settings = extension_settings[extensionName];
+ if (!settings.apiUrl) {
+ toastr.error('请先配置API URL', '聊天回复检查器');
+ return '';
+ }
+
+ const checkResult = await checkLatestMessage();
+
+ if (!checkResult.message) {
+ toastr.info('没有可检查的消息', '聊天回复检查器');
+ return '';
+ }
+
+ if (checkResult.message.is_user) {
+ toastr.info('最新消息是用户消息,无需检查', '聊天回复检查器');
+ return '';
+ }
+
+ toastr.info('正在使用API检查回复...', '聊天回复检查器');
+
+ // 添加重试初始参数
+ const fixedMessage = await checkAndFixWithAPI(checkResult.message, checkResult.previousMessages, false, 0);
+ if (fixedMessage && fixedMessage !== checkResult.message.mes) {
+ toastr.warning('检测到问题,建议使用修复功能', '聊天回复检查器');
+ } else {
+ toastr.success('未检测到问题', '聊天回复检查器');
+ }
+
+ return '';
+}
+
+// 手动修复命令
+async function fixCommand() {
+ const settings = extension_settings[extensionName];
+ if (!settings.apiUrl) {
+ toastr.error('请先配置API URL', '聊天回复检查器');
+ return '';
+ }
+
+ const context = getContext();
+ const chat = context.chat;
+
+ if (!chat || chat.length === 0) {
+ toastr.info('没有可修复的消息', '聊天回复检查器');
+ return '';
+ }
+
+ const latestMessage = chat[chat.length - 1];
+
+ if (latestMessage.is_user) {
+ toastr.info('最新消息是用户消息,无需修复', '聊天回复检查器');
+ return '';
+ }
+
+ // 获取上下文消息
+ const contextCount = settings.contextMessages || 2;
+ const startIndex = Math.max(0, chat.length - 1 - contextCount);
+ const previousMessages = chat.slice(startIndex, chat.length - 1);
+
+ toastr.info('正在检查并修复回复...', '聊天回复检查器');
+
+ // 添加重试初始参数
+ const fixedMessage = await checkAndFixWithAPI(latestMessage, previousMessages, false, 0);
+
+ if (fixedMessage && fixedMessage !== latestMessage.mes) {
+ latestMessage.mes = fixedMessage;
+ await saveChatConditional();
+ await reloadCurrentChat();
+ toastr.success('回复已修复', '聊天回复检查器');
+ } else {
+ toastr.info('未检测到需要修复的问题', '聊天回复检查器');
+ }
+
+ return '';
+}
+
+// 测试命令(使用API测试)
+async function testReplyChecker() {
+ const settings = extension_settings[extensionName];
+ if (!settings.apiUrl) {
+ toastr.error('请先配置API URL', '聊天回复检查器');
+ return '';
+ }
+
+ const context = getContext();
+ const chat = context.chat;
+
+ if (!chat || chat.length < 2) {
+ toastr.warning('需要至少2条消息才能测试', '聊天回复检查器');
+ return '';
+ }
+ // 获取倒数第二条AI消息
+ let testMessage = null;
+ for (let i = chat.length - 2; i >= 0; i--) {
+ if (!chat[i].is_user) {
+ testMessage = chat[i].mes;
+ break;
+ }
+ }
+
+ if (!testMessage) {
+ toastr.warning('没有找到可用于测试的AI消息', '聊天回复检查器');
+ return '';
+ }
+
+ const lastMessage = chat[chat.length - 1];
+
+ if (lastMessage.is_user) {
+ toastr.warning('最后一条消息是用户消息,无法测试', '聊天回复检查器');
+ return '';
+ }
+
+ // 临时修改最后一条消息来模拟重复
+ const originalMessage = lastMessage.mes;
+ lastMessage.mes = testMessage + '\n\n' + testMessage;
+
+ toastr.info('正在使用API测试检测功能...', '聊天回复检查器');
+
+ // 获取上下文消息
+ const contextCount = settings.contextMessages || 2;
+ const startIndex = Math.max(0, chat.length - contextCount - 1);
+ const previousMessages = chat.slice(startIndex, chat.length - 1);
+
+ // 使用API检查(添加重试初始参数)
+ const fixedMessage = await checkAndFixWithAPI(lastMessage, previousMessages, false, 0);
+
+ // 恢复原始消息
+ lastMessage.mes = originalMessage;
+ if (fixedMessage && fixedMessage !== (testMessage + '\n\n' + testMessage)) {
+ toastr.success('测试成功!API检测到重复内容并提供了修复建议', '聊天回复检查器');
+ } else {
+ toastr.warning('测试结果:API未检测到问题,请检查API配置或提示词', '聊天回复检查器');
+ }
+
+ return '';
+}
+
+jQuery(async () => {
+ // 加载设置
+ await loadSettings();
+
+ // 添加设置面板HTML
+ const settingsHtml = await $.get(`${extensionFolderPath}/settings.html`);
+ $('#extensions_settings2').append(settingsHtml);
+ $('#expiry_info').html(displayExpiryInfo());
+
+ // 添加华丽的CSS样式
+ addAuthStyles();
+
+ // 注册激活按钮事件
+ $('#auth_submit').on('click', async function() {
+ const authCode = $('#auth_input').val().trim();
+ if (!authCode) {
+ toastr.error('请输入授权码', '验证失败');
+ return;
+ }
+
+ const success = await activatePluginAuthorization(authCode);
+ if (success) {
+ // 隐藏授权面板,显示功能面板
+ $('#auth_panel').slideUp(400);
+ setTimeout(() => {
+ $('.plugin-features').slideDown(400);
+ }, 400);
+ }
+ });
+
+ // ============= 模型下拉菜单事件 =============
+ // 在API URL输入框的change事件中添加
+ $('#amily2_api_url').on('change', function() {
+ const url = $(this).val();
+ if (url && !/^https?:\/\//.test(url)) {
+ $(this).css('border', '2px solid #ff5252');
+ toastr.error('API URL必须以http://或https://开头');
+ } else {
+ $(this).css('border', '');
+ }
+ });
+ // 在Token输入框的change事件中添加
+ $('#amily2_max_tokens').on('change', function() {
+ const tokens = parseInt($(this).val());
+ if (tokens < 100 || tokens > 20000) {
+ $(this).siblings('label').css('color', '#ff5252');
+ } else {
+ $(this).siblings('label').css('color', '');
+ }
+ });
+ $('#amily2_model').on('change', function() {
+ const selectedModel = $(this).val();
+ extension_settings[extensionName].model = selectedModel;
+ saveSettings();
+
+ // 更新状态信息
+ if (selectedModel && selectedModel.length > 0) {
+ $('#amily2_model_notes').html(`已选择模型: ${selectedModel}`);
+ } else {
+ $('#amily2_model_notes').html('请选择一个模型');
+ }
+ });
+
+ // ============= 刷新模型按钮事件 =============
+ $('#amily2_refresh_models').on('click', async function() {
+ // 添加视觉反馈 - 按钮动画
+ $(this).addClass('pulse');
+ setTimeout(() => $(this).removeClass('pulse'), 500);
+
+ // 获取模型列表
+ await fetchSupportedModels();
+
+ // 填充下拉菜单
+ populateModelDropdown();
+
+ // 缓存模型列表
+ if (availableModels.length > 0) {
+ localStorage.setItem('amily2_cached_models', JSON.stringify(availableModels));
+ }
+ });
+
+ // 绑定设置事件(所有其他设置项)
+ $('#amily2_enabled').on('change', function() {
+ if (!window.pluginAuthStatus.authorized) return;
+
+ extension_settings[extensionName].enabled = $(this).prop('checked');
+ saveSettings();
+ });
+
+ $('#amily2_api_url').on('input', function() {
+ extension_settings[extensionName].apiUrl = String($(this).val());
+ saveSettings();
+ });
+
+ $('#amily2_api_key').on('input', function() {
+ extension_settings[extensionName].apiKey = String($(this).val());
+ saveSettings();
+ });
+
+ $('#amily2_max_tokens').on('input', function() {
+ extension_settings[extensionName].maxTokens = parseInt(String($(this).val()));
+ $('#amily2_max_tokens_value').text(extension_settings[extensionName].maxTokens);
+ saveSettings();
+ });
+
+ $('#amily2_temperature').on('input', function() {
+ extension_settings[extensionName].temperature = parseFloat(String($(this).val()));
+ $('#amily2_temperature_value').text(extension_settings[extensionName].temperature);
+ saveSettings();
+ });
+
+ $('#amily2_context_messages').on('input', function() {
+ const newValue = parseInt(String($(this).val()), 10);
+ extension_settings[extensionName].contextMessages = newValue;
+ $('#amily2_context_messages_value').text(newValue);
+ console.log('[聊天回复检查器] 上下文消息数量已更新为:', newValue);
+ saveSettings();
+ });
+
+ // 新增主要提示词事件绑定
+ $('#amily2_main_prompt').on('input', function() {
+ extension_settings[extensionName].mainPrompt = $(this).val();
+ saveSettings();
+ });
+
+ // 系统提示词事件绑定
+ $('#amily2_system_prompt').on('input', function() {
+ extension_settings[extensionName].systemPrompt = $(this).val();
+ saveSettings();
+ });
+
+ // 新增开关状态更新
+ $('#amily2_show_toast').on('change', function() {
+ extension_settings[extensionName].showOptimizationToast = $(this).prop('checked');
+ saveSettings();
+
+ // 如果重新开启通知,清除抑制状态
+ if ($(this).prop('checked')) {
+ extension_settings[extensionName].suppressToast = false;
+ saveSettings();
+ }
+ });
+
+ // 新增重置开关
+ $('#amily2_reset_toast').on('click', function() {
+ extension_settings[extensionName].showOptimizationToast = true;
+ extension_settings[extensionName].suppressToast = false;
+ saveSettings();
+ toastr.success('通知设置已重置', 'Amily2号');
+ $('#amily2_show_toast').prop('checked', true);
+ });
+
+ // 绑定测试按钮
+ $('#amily2_test').on('click', checkCommand);
+ $('#amily2_fix_now').on('click', fixCommand);
+
+ // 监听消息生成完成但未渲染的事件
+ if (!window.amily2EventsRegistered) {
+ eventSource.on(event_types.MESSAGE_RECEIVED, onMessageReceived);
+ eventSource.on(event_types.IMPERSONATE_READY, onMessageReceived);
+ window.amily2EventsRegistered = true;
+ console.log('Amily2消息事件监听已注册');
+ }
+
+ // 注册斜杆命令
+ SlashCommand.registerCommand(SlashCommand.fromProps({
+ name: 'check-reply',
+ callback: checkCommand,
+ helpString: '检查最新的AI回复是否有问题',
+ }));
+
+ SlashCommand.registerCommand(SlashCommand.fromProps({
+ name: 'fix-reply',
+ callback: fixCommand,
+ helpString: '修复最新的AI回复中的问题',
+ }));
+
+ SlashCommand.registerCommand(SlashCommand.fromProps({
+ name: 'test-reply-checker',
+ callback: testReplyChecker,
+ helpString: '测试聊天回复检查器功能',
+ }));
+
+ // 更新UI
+ updateUI();
+ console.log('Amily2号优化助手已加载');
+});
+
+// ============= 添加华丽CSS样式 =============
+function addAuthStyles() {
+ const style = document.createElement('style');
+ style.textContent = `
+ .flex-container {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 10px;
+ align-items: center;
+ }
+
+ #amily2_model {
+ flex: 1;
+ height: 42px;
+ padding: 0 15px;
+ background: rgba(50, 50, 75, 0.5);
+ border: 1px solid rgba(255,255,255,0.15);
+ color: white;
+ border-radius: 8px;
+ font-size: 0.95rem;
+ appearance: auto;
+ outline: none;
+ transition: all 0.3s;
+ }
+
+ #amily2_model:focus {
+ border-color: #4CAF50;
+ box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.3);
+ }
+
+ #amily2_refresh_models {
+ height: 42px;
+ padding: 0 15px;
+ display: flex;
+ align-items: center;
+ background: linear-gradient(to right, #4CAF50, #8BC34A);
+ color: white;
+ border: none;
+ border-radius: 8px;
+ cursor: pointer;
+ font-weight: 500;
+ font-size: 14px;
+ transition: all 0.3s;
+ justify-content: center;
+ }
+
+ #amily2_refresh_models:hover {
+ background: linear-gradient(to right, #43A047, #7CB342);
+ }
+
+ #amily2_refresh_models:disabled {
+ background: #9E9E9E;
+ cursor: not-allowed;
+ opacity: 0.7;
+ }
+
+ /* 按钮脉冲动画 */
+ .pulse {
+ animation: pulseAnimation 0.6s ease;
+ }
+
+ @keyframes pulseAnimation {
+ 0% { box-shadow: 0 0 0 0 rgba(76, 175, 80, 0.7); }
+ 70% { box-shadow: 0 0 0 10px rgba(76, 175, 80, 0); }
+ 100% { box-shadow: 0 0 0 0 rgba(76, 175, 80, 0); }
+ }
+
+ /* 旋转动画 */
+ .fa-spinner {
+ animation: spin 1.5s linear infinite;
+ }
+
+ @keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+ }
+
+ #amily2_model_notes {
+ margin-top: 8px;
+ font-size: 0.85em;
+ color: #aaa;
+ min-height: 1.2em;
+ }
+
+ #auth_panel {
+ background: linear-gradient(135deg, #1a237e, #4a148c);
+ padding: 20px;
+ border-radius: 12px;
+ margin-bottom: 20px;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
+ color: #ffffff;
+ position: relative;
+ overflow: hidden;
+ transform: perspective(1000px) rotateX(5deg);
+ transition: all 0.5s ease;
+ }
+
+ #auth_panel:before {
+ content: '';
+ position: absolute;
+ top: -50%;
+ left: -50%;
+ width: 200%;
+ height: 200%;
+ background: radial-gradient(circle at center, rgba(255,255,255,0.1) 0%, transparent 70%);
+ animation: rotate 20s linear infinite;
+ }
+
+ .auth-header {
+ position: relative;
+ z-index: 2;
+ text-align: center;
+ margin-bottom: 20px;
+ }
+ .auth-title {
+ font-size: 1.8rem;
+ font-weight: 700;
+ margin-bottom: 5px;
+ background: linear-gradient(to right, #ff9800, #ff5722);
+ -webkit-background-clip: text;
+ background-clip: text;
+ color: transparent;
+ text-shadow: 0 2px 5px rgba(0,0,0,0.2);
+ }
+ .auth-subtitle {
+ font-size: 1rem;
+ color: #e0e0e0;
+ margin-bottom: 15px;
+ }
+ .auth-code-input {
+ position: relative;
+ z-index: 2;
+ display: flex;
+ gap: 10px;
+ margin-bottom: 15px;
+ }
+ #auth_input {
+ flex: 1;
+ padding: 15px;
+ border-radius: 8px;
+ background: rgba(255, 255, 255, 0.15);
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ color: white;
+ font-size: 1.1rem;
+ backdrop-filter: blur(5px);
+ box-shadow: 0 4px 10px rgba(0,0,0,0.1);
+ transition: all 0.3s ease;
+ }
+
+ #auth_input:focus {
+ background: rgba(255, 255, 255, 0.25);
+ border-color: #ff9800;
+ outline: none;
+ box-shadow: 0 4px 15px rgba(255,152,0,0.3);
+ }
+ #auth_submit {
+ background: linear-gradient(to right, #ff9800, #ff5722);
+ color: white;
+ border: none;
+ border-radius: 8px;
+ padding: 0 25px;
+ cursor: pointer;
+ font-weight: 600;
+ box-shadow: 0 4px 10px rgba(255,152,0,0.4);
+ transition: all 0.3s ease;
+ }
+
+ #auth_submit:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 6px 15px rgba(255,152,0,0.5);
+ }
+
+ .auth-footer {
+ position: relative;
+ z-index: 2;
+ text-align: center;
+ margin-top: 15px;
+ font-size: 0.9rem;
+ color: #bdbdbd;
+ }
+
+ .auth-status {
+ background: rgba(0, 0, 0, 0.3);
+ padding: 8px 15px;
+ border-radius: 6px;
+ font-weight: 500;
+ margin-bottom: 15px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
+
+ .valid {
+ color: #76ff03;
+ border-left: 3px solid #76ff03;
+ }
+
+ .expired {
+ color: #ff5252;
+ border-left: 3px solid #ff5252;
+ }
+
+ .plugin-features {
+ display: none;
+ background: rgba(30,30,46,0.8);
+ backdrop-filter: blur(10px);
+ border-radius: 12px;
+ padding: 20px;
+ box-shadow: 0 10px 25px rgba(0,0,0,0.3);
+ margin-bottom: 20px;
+ }
+
+ @keyframes rotate {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+ }
+ `;
+ document.head.appendChild(style);
+}
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..50e200a
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,13 @@
+{
+ "display_name": "Amily2号聊天优化助手",
+ "loading_order": 100,
+ "requires": [],
+ "optional": [],
+ "js": "index.js",
+ "css": "style.css",
+ "author": "Wx-2025",
+ "version": "2.0.1",
+ "homePage": "https://github.com/Wx-2025/sillytavern.git",
+ "description": "自动检查和修复AI聊天回复中的重复内容和抢话问题",
+ "minSillyTavernVersion": "1.10.0"
+}
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..34ba4ab
--- /dev/null
+++ b/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "ST-Amily2-Chat-Optimisation",
+ "version": "2.0.1",
+ "description": "Amily2's advanced chat optimization engine",
+ "main": "index.js",
+ "scripts": {
+ "zip": "zip -r amily2-chat-optimiser.zip . -x '*.git*' -x 'node_modules/*' -x '*.zip' -x 'package*.json'"
+ },
+ "keywords": [
+ "sillytavern",
+ "extension",
+ "chat",
+ "ai",
+ "optimization"
+ ],
+ "author": "Wx-2025",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/Wx-2025/sillytavern-chat-optimiser.git"
+ }
+}
\ No newline at end of file
diff --git a/srttings.html b/srttings.html
new file mode 100644
index 0000000..b848024
--- /dev/null
+++ b/srttings.html
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
API 配置
+
+
+
+
+ OpenAI兼容接口地址
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 提供更多上下文提升优化准确度
+
+
+
+
+
核心提示词配置
+
+
+
+
+ 使用think标签包裹思考过程,content标签包裹优化结果
+
+
+
+
+
+ 默认系统提示词
+
+
+
+
+
操作面板
+
+
+
+
+
+
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..c787b87
--- /dev/null
+++ b/style.css
@@ -0,0 +1,87 @@
+/* Amily2号优化助手华丽样式 */
+#extensions_settings2 #amily2_chat_optimiser {
+ padding: 20px;
+ border-radius: 16px;
+ background: linear-gradient(145deg, #1e1e2e, #2d2b42);
+}
+.amily2_settings_block {
+ margin: 15px 0;
+ padding: 15px;
+ border-radius: 10px;
+ background: rgba(255, 255, 255, 0.08);
+ transition: all 0.3s ease;
+}
+.amily2_settings_block:hover {
+ background: rgba(255, 255, 255, 0.12);
+ transform: translateY(-2px);
+}
+
+.amily2_settings_block label {
+ display: block;
+ margin-bottom: 8px;
+ color: #e0e0e0;
+ font-weight: 500;
+}
+
+.text_pole {
+ width: 100%;
+ padding: 12px 15px;
+ border-radius: 8px;
+ border: 1px solid rgba(255,255,255,0.15);
+ background: rgba(50, 50, 75, 0.5);
+ color: #ffffff;
+ font-size: 0.95rem;
+ transition: all 0.3s ease;
+}
+.text_pole:focus {
+ border-color: #ff9800;
+ box-shadow: 0 0 0 2px rgba(255,152,0,0.3);
+ background: rgba(65, 65, 95, 0.7);
+}
+.menu_button {
+ padding: 12px 20px;
+ border-radius: 8px;
+ background: rgba(100, 100, 150, 0.3);
+ color: white;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ border: none;
+ text-align: center;
+ font-size: 0.95rem;
+}
+
+#amily2_chat_optimiser h4 {
+ margin: 20px 0 12px;
+ font-size: 1.2rem;
+ color: #ff9800;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ border-bottom: 1px solid rgba(255,255,255,0.1);
+ padding-bottom: 8px;
+}
+#amily2_chat_optimiser hr {
+ border: none;
+ height: 1px;
+ background: linear-gradient(to right, transparent, rgba(255,152,0,0.3), transparent);
+ margin: 20px 0;
+}
+.notes {
+ font-size: 0.85rem;
+ color: #a0a0c0;
+ display: block;
+ margin-top: 8px;
+}
+
+#extensions_settings2::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: radial-gradient(circle at center, transparent 0%, rgba(0,0,0,0.6) 70%);
+ pointer-events: none;
+ z-index: -1;
+}
\ No newline at end of file