// Token 管理功能 /** * 保存认证令牌到本地存储 * @param {string} token - 要保存的认证令牌 * @returns {void} */ function saveAuthToken(token) { const expiryTime = new Date().getTime() + (24 * 60 * 60 * 1000); // 24小时后过期 localStorage.setItem('authToken', token); localStorage.setItem('authTokenExpiry', expiryTime); } /** * 获取存储的认证令牌 * @returns {string|null} 如果令牌有效则返回令牌,否则返回 null */ function getAuthToken() { const token = localStorage.getItem('authToken'); const expiry = localStorage.getItem('authTokenExpiry'); if (!token || !expiry) { return null; } if (new Date().getTime() > parseInt(expiry)) { localStorage.removeItem('authToken'); localStorage.removeItem('authTokenExpiry'); return null; } return token; } // 消息显示功能 /** * 在指定元素中显示消息 * @param {string} elementId - 目标元素的 ID * @param {string} text - 要显示的消息文本 * @param {boolean} [isError=false] - 是否为错误消息 * @returns {void} */ function showMessage(elementId, text, isError = false) { let msg = document.getElementById(elementId); // 如果消息元素不存在,创建一个新的 if (!msg) { msg = document.createElement('div'); msg.id = elementId; document.body.appendChild(msg); } msg.className = `floating-message ${isError ? 'error' : 'success'}`; msg.innerHTML = text.replace(/\n/g, '
'); } // 确保消息容器存在 /** * 确保消息容器存在于 DOM 中 * @returns {HTMLElement} 消息容器元素 */ function ensureMessageContainer() { let container = document.querySelector('.message-container'); if (!container) { container = document.createElement('div'); container.className = 'message-container'; document.body.appendChild(container); } return container; } /** * 显示全局消息提示 * @param {string} text - 要显示的消息文本 * @param {boolean} [isError=false] - 是否为错误消息 * @param {number} [timeout=3000] - 消息显示时长(毫秒) * @returns {void} */ function showGlobalMessage(text, isError = false, timeout = 3000) { const container = ensureMessageContainer(); const msgElement = document.createElement('div'); msgElement.className = `message ${isError ? 'error' : 'success'}`; msgElement.textContent = text; container.appendChild(msgElement); // 设置淡出动画和移除 setTimeout(() => { msgElement.style.animation = 'messageOut 0.3s ease-in-out'; setTimeout(() => { msgElement.remove(); // 如果容器为空,也移除容器 if (container.children.length === 0) { container.remove(); } }, 300); }, timeout); } // Token 输入框自动填充和事件绑定 function initializeTokenHandling(inputId) { document.addEventListener('DOMContentLoaded', () => { const authToken = getAuthToken(); if (authToken) { document.getElementById(inputId).value = authToken; } }); document.getElementById(inputId).addEventListener('change', (e) => { if (e.target.value) { saveAuthToken(e.target.value); } else { localStorage.removeItem('authToken'); localStorage.removeItem('authTokenExpiry'); } }); } // API 请求通用处理 async function makeAuthenticatedRequest(url, options = {}) { const tokenId = options.tokenId || 'authToken'; const token = document.getElementById(tokenId).value; if (!token) { showGlobalMessage('请输入 AUTH_TOKEN', true); return null; } const defaultOptions = { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }; try { const response = await fetch(url, { ...defaultOptions, ...options }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { showGlobalMessage(`请求失败: ${error.message}`, true); return null; } } /** * 从字符串解析布尔值 * @param {string} str - 要解析的字符串 * @param {boolean|null} defaultValue - 解析失败时的默认值 * @returns {boolean|null} 解析结果,如果无法解析则返回默认值 */ function parseBooleanFromString(str, defaultValue = null) { if (typeof str !== 'string') { return defaultValue; } const lowercaseStr = str.toLowerCase().trim(); if (lowercaseStr === 'true' || lowercaseStr === '1') { return true; } else if (lowercaseStr === 'false' || lowercaseStr === '0') { return false; } else { return defaultValue; } } /** * 将布尔值转换为字符串 * @param {boolean|undefined|null} value - 要转换的布尔值 * @param {string} defaultValue - 转换失败时的默认值 * @returns {string} 转换结果,如果输入无效则返回默认值 */ function parseStringFromBoolean(value, defaultValue = null) { if (typeof value !== 'boolean') { return defaultValue; } return value ? 'true' : 'false'; } /** * 解析对话内容 * @param {string} promptStr - 原始prompt字符串 * @returns {Array<{role: string, content: string}>} 解析后的对话数组 */ function parsePrompt(promptStr) { if (!promptStr) return []; const messages = []; const lines = promptStr.split('\n'); let currentRole = ''; let currentContent = ''; const roleMap = { 'BEGIN_SYSTEM': 'system', 'BEGIN_USER': 'user', 'BEGIN_ASSISTANT': 'assistant' }; for (let i = 0; i < lines.length; i++) { const line = lines[i]; // 检查是否是角色标记行 let foundRole = false; for (const [marker, role] of Object.entries(roleMap)) { if (line.includes(marker)) { // 保存之前的消息(如果有) if (currentRole && currentContent.trim()) { messages.push({ role: currentRole, content: currentContent.trim() }); } // 设置新角色 currentRole = role; currentContent = ''; foundRole = true; break; } } // 如果不是角色标记行且不是END标记行,则添加到当前内容 if (!foundRole && !line.includes('END_')) { currentContent += line + '\n'; } } // 添加最后一条消息 if (currentRole && currentContent.trim()) { messages.push({ role: currentRole, content: currentContent.trim() }); } return messages; } /** * 格式化对话内容为HTML表格 * @param {Array<{role: string, content: string}>} messages - 对话消息数组 * @returns {string} HTML表格字符串 */ function formatPromptToTable(messages) { if (!messages || messages.length === 0) { return '

无对话内容

'; } const roleLabels = { 'system': '系统', 'user': '用户', 'assistant': '助手' }; function escapeHtml(content) { // 先转义HTML特殊字符 const escaped = content .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); // 将HTML标签文本用引号包裹,使其更易读 // return escaped.replace(/<(\/?[^>]+)>/g, '"<$1>"'); return escaped; } return `${messages.map(msg => ``).join('')}
角色内容
${roleLabels[msg.role] || msg.role}${escapeHtml(msg.content).replace(/\n/g, '
')}
`; } /** * 安全地显示prompt对话框 * @param {string} promptStr - 原始prompt字符串 */ function showPromptModal(promptStr) { try { const modal = document.getElementById('promptModal'); const content = document.getElementById('promptContent'); if (!modal || !content) { console.error('Modal elements not found'); return; } const messages = parsePrompt(promptStr); content.innerHTML = formatPromptToTable(messages); modal.style.display = 'block'; } catch (e) { console.error('显示prompt对话框失败:', e); console.error('原始prompt:', promptStr); } } /** * 将会员类型代码转换为显示名称 * @param {string|null} type - 会员类型代码,如 'free_trial', 'pro', 'free', 'enterprise' 等 * @returns {string} 格式化后的会员类型显示名称 * @example * formatMembershipType('free_trial') // 返回 'Pro Trial' * formatMembershipType('pro') // 返回 'Pro' * formatMembershipType(null) // 返回 '-' * formatMembershipType('custom_type') // 返回 'Custom Type' */ function formatMembershipType(type) { if (!type) return '-'; switch (type) { case 'free_trial': return 'Pro Trial'; case 'pro': return 'Pro'; case 'free': return 'Free'; case 'enterprise': return 'Business'; default: return type .split('_') .map(word => word.charAt(0).toUpperCase() + word.slice(1)) .join(' '); } }