From 9197fde723a9973899fb1111e4ead85dc0e31447 Mon Sep 17 00:00:00 2001
From: Wx-2025 <351320169@qq.com>
Date: Mon, 7 Jul 2025 01:59:28 +0800
Subject: [PATCH] Delete index.js
---
index.js | 1490 ------------------------------------------------------
1 file changed, 1490 deletions(-)
delete mode 100644 index.js
diff --git a/index.js b/index.js
deleted file mode 100644
index 1769a52..0000000
--- a/index.js
+++ /dev/null
@@ -1,1490 +0,0 @@
-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);
-}