|
|
{% extends "base.html" %} {% block title %}配置编辑器 - Gemini Balance{% |
|
|
endblock %} {% block head_extra_styles %} |
|
|
<style> |
|
|
/* config_editor.html specific styles */ |
|
|
/* Animations (already in base.html, but keep fade-in class usage) */ |
|
|
.fade-in { |
|
|
animation: fadeIn 0.3s ease forwards; |
|
|
} |
|
|
/* Modal specific styles (already in base.html) */ |
|
|
.array-container { |
|
|
max-height: 300px; |
|
|
overflow-y: auto; |
|
|
padding: 1rem; /* p-4 consistency */ |
|
|
margin-bottom: 0.5rem; /* mb-2 consistency */ |
|
|
background-color: rgba(255, 255, 255, 0.95) !important; /* light theme */ |
|
|
border: 1px solid rgba(0, 0, 0, 0.12) !important; /* light gray border */ |
|
|
color: #374151 !important; /* gray-700 for light theme */ |
|
|
border-radius: 0.5rem; /* rounded-lg consistency */ |
|
|
} |
|
|
#API_KEYS_container { |
|
|
/* Keep specific ID styling if needed */ |
|
|
max-height: 300px; |
|
|
overflow-y: auto; |
|
|
} |
|
|
.config-section { |
|
|
display: none; |
|
|
/* theming: new background and border for sections */ |
|
|
background-color: rgba(255, 255, 255, 0.95); |
|
|
backdrop-filter: blur(5px); |
|
|
-webkit-backdrop-filter: blur(5px); |
|
|
border: 1px solid rgba(0, 0, 0, 0.08); |
|
|
border-radius: 0.75rem; /* rounded-xl */ |
|
|
padding: 1.5rem; /* p-6 */ |
|
|
margin-bottom: 1.5rem; /* mb-6 */ |
|
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), |
|
|
0 2px 4px -1px rgba(0, 0, 0, 0.06); /* shadow-lg */ |
|
|
} |
|
|
.config-section.active { |
|
|
display: block; |
|
|
animation: fadeIn 0.3s ease forwards; /* Use base animation */ |
|
|
} |
|
|
.provider-config { |
|
|
display: none; |
|
|
} |
|
|
.provider-config.active { |
|
|
display: block; |
|
|
} |
|
|
/* Tailwind Toggle Switch Helper CSS */ |
|
|
.toggle-checkbox:checked { |
|
|
@apply: right-0 border-blue-600; /* theming: changed to blue for light theme */ |
|
|
right: 0; |
|
|
border-color: #2563eb; /* theming: blue-600 */ |
|
|
} |
|
|
.toggle-checkbox:checked + .toggle-label { |
|
|
@apply: bg-blue-600; /* theming: changed to blue for light theme */ |
|
|
background-color: #2563eb; /* theming: blue-600 */ |
|
|
} |
|
|
.toggle-label { |
|
|
/* theming: style for unchecked state */ |
|
|
background-color: rgba(156, 163, 175, 0.3); /* gray-400 */ |
|
|
} |
|
|
/* 统一通知样式为黑色半透明,确保与 keys_status 一致 */ |
|
|
.notification { |
|
|
background: rgba(0, 0, 0, 0.8) !important; |
|
|
color: #fff !important; |
|
|
} |
|
|
|
|
|
/* Theming for input fields - 修复边框重影问题 */ |
|
|
.form-input-themed { |
|
|
background-color: rgba(255, 255, 255, 0.95) !important; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12) !important; /* 为独立输入框提供边框 */ |
|
|
color: #374151 !important; /* gray-700 */ |
|
|
outline: none !important; /* 移除默认outline */ |
|
|
box-shadow: none !important; /* 移除默认box-shadow */ |
|
|
transition: border-color 0.15s ease-in-out !important; |
|
|
} |
|
|
.form-input-themed::placeholder { |
|
|
color: #9ca3af !important; /* gray-400 */ |
|
|
} |
|
|
.form-input-themed:focus { |
|
|
border-color: #3b82f6 !important; /* focus时改变边框颜色 */ |
|
|
box-shadow: none !important; /* 移除focus阴影,只保留边框变化 */ |
|
|
outline: none !important; /* 确保没有outline */ |
|
|
} |
|
|
|
|
|
/* 对于在数组容器内的输入框,移除边框 */ |
|
|
.array-container .form-input-themed { |
|
|
border: none !important; /* 在数组容器内的输入框移除边框 */ |
|
|
} |
|
|
|
|
|
.array-container .form-input-themed:focus { |
|
|
border: none !important; /* 确保focus时也没有边框 */ |
|
|
} |
|
|
|
|
|
/* 为独立的模型选择输入框保留边框 */ |
|
|
.flex.items-center .form-input-themed { |
|
|
border: 1px solid rgba(0, 0, 0, 0.12) !important; /* 保留边框 */ |
|
|
} |
|
|
|
|
|
.flex.items-center .form-input-themed:focus { |
|
|
border-color: #3b82f6 !important; /* focus时改变边框颜色 */ |
|
|
} |
|
|
|
|
|
/* Theming for select fields - 改进下拉框样式 */ |
|
|
.form-select-themed { |
|
|
background-color: rgba(255, 255, 255, 0.95) !important; /* 白色背景 */ |
|
|
border: 1px solid rgba(0, 0, 0, 0.12) !important; /* 灰色边框 */ |
|
|
color: #374151 !important; /* gray-700 文字颜色 */ |
|
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 8l4 4 4-4'/%3e%3c/svg%3e") !important; /* 灰色箭头 */ |
|
|
appearance: none !important; |
|
|
padding: 0.6rem 2.5rem 0.6rem 0.8rem !important; /* 调整内边距 */ |
|
|
background-repeat: no-repeat !important; |
|
|
background-position: right 0.6rem center !important; |
|
|
background-size: 1.5em 1.5em !important; |
|
|
border-radius: 0.5rem !important; /* 圆角 */ |
|
|
font-weight: 500 !important; /* 半粗体 */ |
|
|
height: auto !important; /* 自动高度 */ |
|
|
box-shadow: none !important; /* 移除阴影 */ |
|
|
cursor: pointer !important; |
|
|
} |
|
|
|
|
|
.form-select-themed:focus { |
|
|
border-color: #3b82f6 !important; /* blue-500 */ |
|
|
box-shadow: none !important; /* 移除focus阴影 */ |
|
|
outline: none !important; |
|
|
} |
|
|
|
|
|
.form-select-themed option { |
|
|
background-color: rgba( |
|
|
255, |
|
|
255, |
|
|
255, |
|
|
0.98 |
|
|
) !important; /* white background */ |
|
|
color: #374151 !important; /* gray-700 */ |
|
|
padding: 8px !important; |
|
|
} |
|
|
|
|
|
/* 日志级别样式 - 浅色主题统一设计 */ |
|
|
#LOG_LEVEL { |
|
|
font-weight: 600 !important; |
|
|
} |
|
|
|
|
|
/* 统一的日志级别选项样式 - 使用浅色主题 */ |
|
|
#LOG_LEVEL option[value="DEBUG"] { |
|
|
background-color: rgba(255, 255, 255, 0.98) !important; /* 白色背景 */ |
|
|
color: #374151 !important; /* gray-700 深灰色文字 */ |
|
|
} |
|
|
|
|
|
#LOG_LEVEL option[value="INFO"] { |
|
|
background-color: rgba( |
|
|
249, |
|
|
250, |
|
|
251, |
|
|
0.98 |
|
|
) !important; /* gray-50 浅灰背景 */ |
|
|
color: #374151 !important; /* gray-700 深灰色文字 */ |
|
|
} |
|
|
|
|
|
#LOG_LEVEL option[value="WARNING"] { |
|
|
background-color: rgba( |
|
|
243, |
|
|
244, |
|
|
246, |
|
|
0.98 |
|
|
) !important; /* gray-100 稍深灰背景 */ |
|
|
color: #374151 !important; /* gray-700 深灰色文字 */ |
|
|
} |
|
|
|
|
|
#LOG_LEVEL option[value="ERROR"] { |
|
|
background-color: rgba( |
|
|
229, |
|
|
231, |
|
|
235, |
|
|
0.98 |
|
|
) !important; /* gray-200 中灰背景 */ |
|
|
color: #374151 !important; /* gray-700 深灰色文字 */ |
|
|
} |
|
|
|
|
|
#LOG_LEVEL option[value="CRITICAL"] { |
|
|
background-color: rgba( |
|
|
209, |
|
|
213, |
|
|
219, |
|
|
0.98 |
|
|
) !important; /* gray-300 深灰背景 */ |
|
|
color: #374151 !important; /* gray-700 深灰色文字 */ |
|
|
} |
|
|
|
|
|
/* 思考模型预算映射样式 */ |
|
|
.map-item { |
|
|
background-color: rgba(60, 40, 130, 0.2) !important; |
|
|
border-radius: 0.5rem !important; |
|
|
padding: 0.5rem !important; |
|
|
border: 1px solid rgba(167, 139, 250, 0.3) !important; |
|
|
transition: all 0.2s ease-in-out !important; |
|
|
} |
|
|
|
|
|
.map-item:hover { |
|
|
background-color: rgba(60, 40, 130, 0.3) !important; |
|
|
border-color: rgba(167, 139, 250, 0.5) !important; |
|
|
} |
|
|
|
|
|
.map-key-input { |
|
|
background-color: rgba(255, 255, 255, 0.95) !important; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12) !important; |
|
|
color: #374151 !important; /* gray-700 */ |
|
|
font-weight: 500 !important; |
|
|
border-radius: 0.375rem !important; |
|
|
} |
|
|
|
|
|
.map-value-input { |
|
|
background-color: rgba(255, 255, 255, 0.95) !important; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12) !important; |
|
|
color: #374151 !important; /* gray-700 */ |
|
|
font-weight: 600 !important; |
|
|
border-radius: 0.375rem !important; |
|
|
box-shadow: none !important; |
|
|
transition: all 0.2s !important; |
|
|
} |
|
|
|
|
|
.map-value-input:focus { |
|
|
background-color: rgba(255, 255, 255, 1) !important; |
|
|
border-color: #3b82f6 !important; /* blue-500 */ |
|
|
box-shadow: none !important; /* 移除focus阴影 */ |
|
|
outline: none !important; |
|
|
} |
|
|
|
|
|
/* 警告文字样式 */ |
|
|
.warning-text { |
|
|
color: #f87171 !important; /* red-400 */ |
|
|
font-weight: 600 !important; |
|
|
background-color: rgba(248, 113, 113, 0.15) !important; |
|
|
padding: 0.5rem 0.75rem !important; |
|
|
border-radius: 0.375rem !important; |
|
|
border-left: 3px solid #ef4444 !important; /* red-500 */ |
|
|
display: flex !important; |
|
|
align-items: center !important; |
|
|
margin-top: 0.5rem !important; |
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important; |
|
|
} |
|
|
|
|
|
.warning-text i { |
|
|
margin-right: 0.5rem !important; |
|
|
color: #ef4444 !important; /* red-500 */ |
|
|
} |
|
|
|
|
|
/* 令牌生成按钮样式 */ |
|
|
.generate-btn { |
|
|
background-color: rgba(59, 130, 246, 0.1) !important; /* blue-500 light */ |
|
|
color: #3b82f6 !important; /* blue-500 */ |
|
|
border: 1px solid rgba(59, 130, 246, 0.3) !important; |
|
|
border-left: none !important; |
|
|
transition: all 0.2s ease !important; |
|
|
} |
|
|
|
|
|
.generate-btn:hover { |
|
|
background-color: rgba( |
|
|
59, |
|
|
130, |
|
|
246, |
|
|
0.2 |
|
|
) !important; /* blue-500 more opaque */ |
|
|
color: #1d4ed8 !important; /* blue-700 */ |
|
|
box-shadow: 0 0 8px rgba(59, 130, 246, 0.3) !important; |
|
|
} |
|
|
|
|
|
.generate-btn:focus { |
|
|
outline: none !important; |
|
|
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.5) !important; |
|
|
} |
|
|
|
|
|
/* 导航链接悬停样式 - 优化以避免遮挡内容 */ |
|
|
.nav-link { |
|
|
transition: all 0.2s ease-in-out; |
|
|
position: relative; |
|
|
z-index: 1; /* 确保不会遮挡重要内容 */ |
|
|
} |
|
|
|
|
|
.nav-link:hover { |
|
|
background-color: rgba(59, 130, 246, 0.1) !important; /* blue-500 light */ |
|
|
transform: scale(1.02); /* 使用缩放代替向上移动 */ |
|
|
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15); /* 增强阴影效果 */ |
|
|
} |
|
|
|
|
|
/* 导航按钮容器样式 - 为悬停效果预留空间 */ |
|
|
.nav-buttons-container { |
|
|
padding-top: 0.5rem; /* 为悬停效果预留上方空间 */ |
|
|
padding-bottom: 0.75rem; /* 为悬停效果预留下方空间 */ |
|
|
} |
|
|
|
|
|
/* 主导航按钮的优化悬停效果 */ |
|
|
.main-nav-btn:hover { |
|
|
transform: scale(1.02) !important; /* 使用缩放代替向上移动 */ |
|
|
box-shadow: 0 8px 16px rgba(59, 130, 246, 0.3) !important; /* 蓝色阴影 */ |
|
|
} |
|
|
|
|
|
/* 操作按钮的优化悬停效果 */ |
|
|
.action-btn { |
|
|
position: relative; |
|
|
z-index: 1; |
|
|
} |
|
|
|
|
|
.action-btn:hover { |
|
|
transform: scale(1.02) !important; /* 使用缩放代替向上移动 */ |
|
|
} |
|
|
|
|
|
.action-btn:hover#saveBtn { |
|
|
box-shadow: 0 8px 20px rgba(59, 130, 246, 0.4) !important; /* 蓝色阴影 */ |
|
|
} |
|
|
|
|
|
.action-btn:hover#resetBtn { |
|
|
box-shadow: 0 8px 20px rgba(107, 114, 128, 0.4) !important; /* 灰色阴影 */ |
|
|
} |
|
|
|
|
|
/* 刷新按钮样式 - 与监控面板页面保持一致 */ |
|
|
.bg-white.bg-opacity-20 { |
|
|
background-color: rgba(255, 255, 255, 0.9) !important; |
|
|
color: #3b82f6 !important; /* blue-500 - 与监控面板一致 */ |
|
|
} |
|
|
|
|
|
.bg-white.bg-opacity-20:hover { |
|
|
background-color: rgba(255, 255, 255, 1) !important; |
|
|
color: #2563eb !important; /* blue-600 - 悬停时稍深 */ |
|
|
} |
|
|
|
|
|
/* General label and small text theming for light theme */ |
|
|
label { |
|
|
color: #374151 !important; /* Dark gray for labels in light theme */ |
|
|
font-weight: 600; /* semibold */ |
|
|
} |
|
|
small { |
|
|
color: #6b7280 !important; /* Medium gray for small text */ |
|
|
} |
|
|
|
|
|
/* Override all violet/purple buttons to light blue */ |
|
|
.bg-violet-600, |
|
|
button.bg-violet-600 { |
|
|
background-color: #3b82f6 !important; /* blue-500 - light blue */ |
|
|
} |
|
|
|
|
|
.bg-violet-600:hover, |
|
|
button.bg-violet-600:hover, |
|
|
.hover\\:bg-violet-700:hover { |
|
|
background-color: #2563eb !important; /* blue-600 - darker light blue */ |
|
|
} |
|
|
|
|
|
/* Override blue buttons to light blue */ |
|
|
.bg-blue-600, |
|
|
button.bg-blue-600 { |
|
|
background-color: #3b82f6 !important; /* blue-500 - light blue */ |
|
|
} |
|
|
|
|
|
.bg-blue-600:hover, |
|
|
button.bg-blue-600:hover, |
|
|
.hover\\:bg-blue-700:hover { |
|
|
background-color: #2563eb !important; /* blue-600 - darker light blue */ |
|
|
} |
|
|
|
|
|
/* Override red buttons to bright light red */ |
|
|
.bg-red-600, |
|
|
button.bg-red-600, |
|
|
.bg-red-700, |
|
|
button.bg-red-700, |
|
|
.bg-red-800, |
|
|
button.bg-red-800 { |
|
|
background-color: #f87171 !important; /* red-400 - bright light red */ |
|
|
} |
|
|
|
|
|
.bg-red-600:hover, |
|
|
button.bg-red-600:hover, |
|
|
.bg-red-700:hover, |
|
|
button.bg-red-700:hover, |
|
|
.bg-red-800:hover, |
|
|
button.bg-red-800:hover, |
|
|
.hover\\:bg-red-700:hover, |
|
|
.hover\\:bg-red-800:hover { |
|
|
background-color: #ef4444 !important; /* red-500 - darker bright light red */ |
|
|
} |
|
|
|
|
|
/* Update section headings */ |
|
|
.config-section h2 { |
|
|
color: #1f2937 !important; /* gray-800 */ |
|
|
border-color: #d1d5db !important; /* gray-300 */ |
|
|
} |
|
|
|
|
|
.config-section h2 i { |
|
|
color: #3b82f6 !important; /* blue-500 */ |
|
|
} |
|
|
|
|
|
/* Update tab button active state - 增强选中态样式,提高优先级 */ |
|
|
button.tab-btn.active { |
|
|
background-color: #3b82f6 !important; /* blue-500 */ |
|
|
color: #ffffff !important; /* 确保白色文字 */ |
|
|
box-shadow: 0 4px 12px -2px rgba(59, 130, 246, 0.4), |
|
|
0 2px 6px -1px rgba(59, 130, 246, 0.2) !important; /* 蓝色阴影 */ |
|
|
transform: translateY(-2px) !important; /* 更明显的上移效果 */ |
|
|
border: 2px solid #2563eb !important; /* blue-600 边框 */ |
|
|
font-weight: 600 !important; /* 加粗字体 */ |
|
|
} |
|
|
|
|
|
/* Ensure inactive tabs have proper styling - 增强未选中态样式,提高优先级 */ |
|
|
button.tab-btn:not(.active) { |
|
|
background-color: #f8fafc !important; /* slate-50 更浅的背景 */ |
|
|
color: #64748b !important; /* slate-500 更明显的灰色文字 */ |
|
|
border: 2px solid #e2e8f0 !important; /* slate-200 边框 */ |
|
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1) !important; /* 轻微阴影 */ |
|
|
font-weight: 500 !important; /* 中等字体粗细 */ |
|
|
} |
|
|
|
|
|
button.tab-btn:not(.active):hover { |
|
|
background-color: #f1f5f9 !important; /* slate-100 */ |
|
|
color: #475569 !important; /* slate-600 更深的文字颜色 */ |
|
|
transform: translateY(-1px) !important; |
|
|
border-color: #cbd5e1 !important; /* slate-300 */ |
|
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1) !important; |
|
|
} |
|
|
|
|
|
/* Add transition for smooth state changes - 提高优先级 */ |
|
|
button.tab-btn { |
|
|
transition: all 0.2s ease-in-out !important; |
|
|
cursor: pointer !important; |
|
|
/* 确保基础样式不被Tailwind覆盖 */ |
|
|
padding: 0.5rem 1.25rem !important; /* px-5 py-2 */ |
|
|
border-radius: 9999px !important; /* rounded-full */ |
|
|
font-size: 0.875rem !important; /* text-sm */ |
|
|
font-weight: 500 !important; /* font-medium */ |
|
|
} |
|
|
|
|
|
/* 额外的高优先级规则确保样式生效 */ |
|
|
.flex.justify-center.mb-6.flex-wrap.gap-2 button.tab-btn.active { |
|
|
background-color: #3b82f6 !important; |
|
|
color: #ffffff !important; |
|
|
border: 2px solid #2563eb !important; |
|
|
box-shadow: 0 4px 12px -2px rgba(59, 130, 246, 0.4), |
|
|
0 2px 6px -1px rgba(59, 130, 246, 0.2) !important; |
|
|
transform: translateY(-2px) !important; |
|
|
font-weight: 600 !important; |
|
|
} |
|
|
|
|
|
.flex.justify-center.mb-6.flex-wrap.gap-2 button.tab-btn:not(.active) { |
|
|
background-color: #f8fafc !important; |
|
|
color: #64748b !important; |
|
|
border: 2px solid #e2e8f0 !important; |
|
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1) !important; |
|
|
font-weight: 500 !important; |
|
|
transform: none !important; |
|
|
} |
|
|
|
|
|
/* Fix all modal backgrounds - comprehensive override */ |
|
|
.modal .w-full[style*="background-color: rgba(70, 50, 150"], |
|
|
.modal .w-full.max-w-lg[style*="background-color: rgba(70, 50, 150"], |
|
|
.modal .w-full.max-w-md[style*="background-color: rgba(70, 50, 150"] { |
|
|
background-color: rgba(255, 255, 255, 0.98) !important; |
|
|
color: #374151 !important; /* gray-700 */ |
|
|
border-color: rgba(0, 0, 0, 0.08) !important; |
|
|
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), |
|
|
0 10px 10px -5px rgba(0, 0, 0, 0.04) !important; |
|
|
} |
|
|
|
|
|
/* Fix modal titles */ |
|
|
.modal h2.text-gray-800 { |
|
|
color: #1f2937 !important; /* gray-800 */ |
|
|
font-weight: 600 !important; |
|
|
} |
|
|
|
|
|
/* Fix modal close buttons */ |
|
|
.modal .text-gray-300 { |
|
|
color: #6b7280 !important; /* gray-500 */ |
|
|
} |
|
|
|
|
|
.modal .text-gray-300:hover { |
|
|
color: #374151 !important; /* gray-700 */ |
|
|
} |
|
|
|
|
|
/* Fix modal body text */ |
|
|
.modal p, |
|
|
.modal label, |
|
|
.modal span { |
|
|
color: #374151 !important; /* gray-700 */ |
|
|
} |
|
|
|
|
|
/* Fix modal textarea and input styling */ |
|
|
.modal textarea, |
|
|
.modal input { |
|
|
background-color: rgba(255, 255, 255, 0.95) !important; |
|
|
color: #374151 !important; /* gray-700 */ |
|
|
border: 1px solid rgba(0, 0, 0, 0.12) !important; |
|
|
} |
|
|
|
|
|
.modal textarea:focus, |
|
|
.modal input:focus { |
|
|
border-color: #3b82f6 !important; /* blue-500 */ |
|
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1) !important; |
|
|
} |
|
|
|
|
|
/* Fix modal button styling */ |
|
|
.modal .bg-violet-600, |
|
|
.modal button.bg-violet-600 { |
|
|
background-color: #3b82f6 !important; /* blue-500 - light blue */ |
|
|
color: #ffffff !important; |
|
|
border: 1px solid #2563eb !important; /* blue-600 */ |
|
|
} |
|
|
|
|
|
.modal .bg-violet-600:hover, |
|
|
.modal button.bg-violet-600:hover { |
|
|
background-color: #2563eb !important; /* blue-600 - darker light blue */ |
|
|
transform: translateY(-1px) !important; |
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important; |
|
|
} |
|
|
|
|
|
/* Fix modal blue button styling */ |
|
|
.modal .bg-blue-500, |
|
|
.modal button.bg-blue-500, |
|
|
.modal .bg-blue-600, |
|
|
.modal button.bg-blue-600, |
|
|
.modal .bg-blue-700, |
|
|
.modal button.bg-blue-700 { |
|
|
background-color: #3b82f6 !important; /* blue-500 - light blue */ |
|
|
color: #ffffff !important; |
|
|
border: 1px solid #2563eb !important; /* blue-600 */ |
|
|
} |
|
|
|
|
|
.modal .bg-blue-500:hover, |
|
|
.modal button.bg-blue-500:hover, |
|
|
.modal .bg-blue-600:hover, |
|
|
.modal button.bg-blue-600:hover, |
|
|
.modal .bg-blue-700:hover, |
|
|
.modal button.bg-blue-700:hover { |
|
|
background-color: #2563eb !important; /* blue-600 - darker light blue */ |
|
|
transform: translateY(-1px) !important; |
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important; |
|
|
} |
|
|
|
|
|
/* Fix modal cancel/secondary buttons */ |
|
|
.modal .bg-gray-500, |
|
|
.modal button.bg-gray-500, |
|
|
.modal .bg-gray-600, |
|
|
.modal button.bg-gray-600 { |
|
|
background-color: #e5e7eb !important; /* gray-200 - light gray */ |
|
|
color: #374151 !important; /* gray-700 - dark text for contrast */ |
|
|
border: 1px solid #d1d5db !important; /* gray-300 */ |
|
|
} |
|
|
|
|
|
.modal .bg-gray-500:hover, |
|
|
.modal button.bg-gray-500:hover, |
|
|
.modal .bg-gray-600:hover, |
|
|
.modal button.bg-gray-600:hover { |
|
|
background-color: #d1d5db !important; /* gray-300 - darker light gray */ |
|
|
color: #374151 !important; /* gray-700 - dark text for contrast */ |
|
|
transform: translateY(-1px) !important; |
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important; |
|
|
} |
|
|
|
|
|
/* Fix modal red/danger buttons */ |
|
|
.modal .bg-red-500, |
|
|
.modal button.bg-red-500, |
|
|
.modal .bg-red-600, |
|
|
.modal button.bg-red-600, |
|
|
.modal .bg-red-700, |
|
|
.modal button.bg-red-700 { |
|
|
background-color: #f87171 !important; /* red-400 - bright light red */ |
|
|
color: #ffffff !important; |
|
|
border: 1px solid #ef4444 !important; /* red-500 */ |
|
|
} |
|
|
|
|
|
.modal .bg-red-500:hover, |
|
|
.modal button.bg-red-500:hover, |
|
|
.modal .bg-red-600:hover, |
|
|
.modal button.bg-red-600:hover, |
|
|
.modal .bg-red-700:hover, |
|
|
.modal button.bg-red-700:hover { |
|
|
background-color: #ef4444 !important; /* red-500 - darker bright light red */ |
|
|
transform: translateY(-1px) !important; |
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important; |
|
|
} |
|
|
|
|
|
/* Fix all container backgrounds with purple */ |
|
|
[style*="background-color: rgba(255, 255, 255, 0.05)"], |
|
|
[style*="background-color: rgba(80, 60, 160"], |
|
|
[style*="background-color: rgba(70, 50, 150"], |
|
|
[style*="background-color: rgba(60, 40, 130"], |
|
|
[style*="background-color: rgba(120, 100, 200"] { |
|
|
background-color: rgba(255, 255, 255, 0.95) !important; |
|
|
border-color: rgba(0, 0, 0, 0.08) !important; |
|
|
color: #374151 !important; |
|
|
} |
|
|
|
|
|
/* Fix map item styling */ |
|
|
.map-item { |
|
|
background-color: rgba(249, 250, 251, 0.8) !important; /* gray-50 */ |
|
|
border: 1px solid rgba(0, 0, 0, 0.08) !important; |
|
|
color: #374151 !important; |
|
|
} |
|
|
|
|
|
.map-item:hover { |
|
|
background-color: rgba(243, 244, 246, 1) !important; /* gray-100 */ |
|
|
border-color: rgba(0, 0, 0, 0.12) !important; |
|
|
} |
|
|
|
|
|
/* Update model helper buttons */ |
|
|
.model-helper-trigger-btn { |
|
|
color: #3b82f6 !important; /* blue-500 */ |
|
|
background-color: rgba(59, 130, 246, 0.1) !important; |
|
|
} |
|
|
|
|
|
.model-helper-trigger-btn:hover { |
|
|
background-color: rgba(59, 130, 246, 0.2) !important; |
|
|
color: #1d4ed8 !important; /* blue-700 */ |
|
|
} |
|
|
|
|
|
/* Comprehensive button text color fixes */ |
|
|
.bg-blue-500, |
|
|
.bg-blue-600, |
|
|
.bg-blue-700, |
|
|
.bg-red-500, |
|
|
.bg-red-600, |
|
|
.bg-red-700, |
|
|
.bg-red-800, |
|
|
.bg-green-500, |
|
|
.bg-green-600, |
|
|
.bg-green-700, |
|
|
.bg-sky-500, |
|
|
.bg-sky-600, |
|
|
.bg-sky-700, |
|
|
.bg-purple-500, |
|
|
.bg-purple-600, |
|
|
.bg-purple-700, |
|
|
.bg-violet-500, |
|
|
.bg-violet-600, |
|
|
.bg-violet-700 { |
|
|
color: #ffffff !important; |
|
|
} |
|
|
|
|
|
/* Ensure button children inherit white text */ |
|
|
.bg-blue-500 *, |
|
|
.bg-blue-600 *, |
|
|
.bg-blue-700 *, |
|
|
.bg-red-500 *, |
|
|
.bg-red-600 *, |
|
|
.bg-red-700 *, |
|
|
.bg-red-800 *, |
|
|
.bg-green-500 *, |
|
|
.bg-green-600 *, |
|
|
.bg-green-700 *, |
|
|
.bg-sky-500 *, |
|
|
.bg-sky-600 *, |
|
|
.bg-sky-700 *, |
|
|
.bg-purple-500 *, |
|
|
.bg-purple-600 *, |
|
|
.bg-purple-700 *, |
|
|
.bg-violet-500 *, |
|
|
.bg-violet-600 *, |
|
|
.bg-violet-700 * { |
|
|
color: inherit !important; |
|
|
} |
|
|
|
|
|
/* Fix page title gradient - comprehensive override */ |
|
|
h1.text-transparent, |
|
|
.text-transparent.bg-clip-text, |
|
|
.bg-gradient-to-r.from-violet-400.to-pink-400 { |
|
|
background: none !important; |
|
|
color: #1f2937 !important; /* gray-800 - consistent with other pages */ |
|
|
-webkit-background-clip: unset !important; |
|
|
background-clip: unset !important; |
|
|
text-shadow: none !important; |
|
|
font-weight: 800 !important; /* font-extrabold */ |
|
|
} |
|
|
|
|
|
/* Fix all gradient buttons to use solid blue */ |
|
|
.bg-gradient-to-r.from-violet-500.to-pink-500, |
|
|
.bg-gradient-to-r.from-gray-600.to-gray-700 { |
|
|
background: none !important; |
|
|
} |
|
|
|
|
|
/* Ensure all violet/purple colors are converted to blue theme */ |
|
|
.text-violet-300, |
|
|
.text-violet-400, |
|
|
.text-violet-100 { |
|
|
color: #3b82f6 !important; /* blue-500 */ |
|
|
} |
|
|
|
|
|
.border-violet-300, |
|
|
.border-violet-400 { |
|
|
border-color: rgba( |
|
|
59, |
|
|
130, |
|
|
246, |
|
|
0.3 |
|
|
) !important; /* blue-500 with opacity */ |
|
|
} |
|
|
|
|
|
.hover\\:text-violet-400:hover, |
|
|
.hover\\:text-violet-100:hover { |
|
|
color: #2563eb !important; /* blue-600 */ |
|
|
} |
|
|
|
|
|
.hover\\:bg-violet-700:hover { |
|
|
background-color: #2563eb !important; /* blue-600 */ |
|
|
} |
|
|
|
|
|
/* Fix focus states for form elements */ |
|
|
.focus-within\\:border-violet-400:focus-within, |
|
|
.focus-within\\:ring-violet-400:focus-within { |
|
|
border-color: #3b82f6 !important; /* blue-500 */ |
|
|
box-shadow: none !important; /* 移除focus阴影 */ |
|
|
} |
|
|
|
|
|
/* Fix focus-within border color for auth token wrapper */ |
|
|
.focus-within\\:border-blue-500:focus-within { |
|
|
border-color: #3b82f6 !important; /* blue-500 */ |
|
|
} |
|
|
|
|
|
/* More specific selector for auth token wrapper */ |
|
|
div.flex.items-center.flex-grow.border.rounded-md.focus-within\\:border-blue-500:focus-within { |
|
|
border-color: #3b82f6 !important; /* blue-500 */ |
|
|
} |
|
|
|
|
|
/* Even more specific selector targeting the exact auth token wrapper */ |
|
|
.mb-6 |
|
|
.flex.items-center |
|
|
div.flex.items-center.flex-grow.border.rounded-md:focus-within { |
|
|
border-color: #3b82f6 !important; /* blue-500 */ |
|
|
} |
|
|
|
|
|
/* Fix primary color focus states - convert purple to blue */ |
|
|
.focus\\:border-primary-500:focus, |
|
|
.focus\\:border-primary-600:focus { |
|
|
border-color: #3b82f6 !important; /* blue-500 */ |
|
|
} |
|
|
|
|
|
.focus\\:ring-primary-200:focus, |
|
|
.focus\\:ring-primary-300:focus { |
|
|
--tw-ring-color: rgba( |
|
|
59, |
|
|
130, |
|
|
246, |
|
|
0.2 |
|
|
) !important; /* blue-500 with opacity */ |
|
|
} |
|
|
|
|
|
/* Fix select element styling */ |
|
|
.form-select-themed { |
|
|
background-color: rgba(255, 255, 255, 0.95) !important; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12) !important; |
|
|
color: #374151 !important; /* gray-700 */ |
|
|
outline: none !important; |
|
|
box-shadow: none !important; |
|
|
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important; |
|
|
} |
|
|
|
|
|
.form-select-themed:focus { |
|
|
border-color: #3b82f6 !important; /* blue-500 */ |
|
|
box-shadow: none !important; /* 移除focus阴影 */ |
|
|
outline: none !important; |
|
|
} |
|
|
|
|
|
/* Override any remaining primary colors */ |
|
|
.text-primary-600, |
|
|
.text-primary-500 { |
|
|
color: #3b82f6 !important; /* blue-500 */ |
|
|
} |
|
|
|
|
|
.bg-primary-600, |
|
|
.bg-primary-500 { |
|
|
background-color: #3b82f6 !important; /* blue-500 */ |
|
|
} |
|
|
|
|
|
.bg-primary-700:hover, |
|
|
.hover\\:bg-primary-700:hover { |
|
|
background-color: #2563eb !important; /* blue-600 */ |
|
|
} |
|
|
|
|
|
/* Fix dynamic input wrapper focus states - convert violet to blue */ |
|
|
.focus-within\\:border-violet-400:focus-within, |
|
|
.focus-within\\:ring-violet-400:focus-within { |
|
|
border-color: #3b82f6 !important; /* blue-500 */ |
|
|
box-shadow: none !important; /* 移除focus阴影 */ |
|
|
} |
|
|
|
|
|
/* Ensure all array input wrappers use blue theme */ |
|
|
.array-container .flex.items-center.flex-grow.rounded-md { |
|
|
border-color: rgba(0, 0, 0, 0.12) !important; |
|
|
} |
|
|
|
|
|
.array-container .flex.items-center.flex-grow.rounded-md:focus-within { |
|
|
border-color: #3b82f6 !important; /* blue-500 */ |
|
|
box-shadow: none !important; /* 移除focus阴影 */ |
|
|
} |
|
|
</style> |
|
|
{% endblock %} {% block content %} |
|
|
<div class="container max-w-6xl mx-auto px-4"> |
|
|
<div |
|
|
class="rounded-2xl shadow-xl p-6 md:p-8" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.95); |
|
|
backdrop-filter: blur(10px); |
|
|
-webkit-backdrop-filter: blur(10px); |
|
|
border: 1px solid rgba(0, 0, 0, 0.08); |
|
|
" |
|
|
> |
|
|
<button |
|
|
class="absolute top-6 right-6 bg-white bg-opacity-20 hover:bg-opacity-30 rounded-full w-8 h-8 flex items-center justify-center text-primary-600 transition-all duration-300" |
|
|
onclick="refreshPage(this)" |
|
|
title="手动刷新" |
|
|
> |
|
|
<i class="fas fa-sync-alt"></i> |
|
|
</button> |
|
|
|
|
|
<h1 class="text-3xl font-extrabold text-center text-gray-800 mb-4"> |
|
|
<img |
|
|
src="{{ static_url('icons/logo.png') }}" |
|
|
alt="Gemini Balance Logo" |
|
|
class="h-9 inline-block align-middle mr-2" |
|
|
/> |
|
|
Gemini Balance - 配置编辑 |
|
|
</h1> |
|
|
|
|
|
|
|
|
<div |
|
|
class="nav-buttons-container flex justify-center mb-8 overflow-x-auto gap-2" |
|
|
> |
|
|
<a |
|
|
href="/config" |
|
|
class="main-nav-btn whitespace-nowrap flex items-center justify-center gap-2 px-6 py-3 font-medium rounded-lg shadow-md hover:shadow-lg transition-all duration-200" |
|
|
style="background-color: #3b82f6 !important; color: #ffffff !important" |
|
|
> |
|
|
<i class="fas fa-cog"></i> 配置编辑 |
|
|
</a> |
|
|
<a |
|
|
href="/keys" |
|
|
class="nav-link whitespace-nowrap flex items-center justify-center gap-2 px-6 py-3 font-medium rounded-lg text-gray-700 hover:text-gray-900 transition-all duration-200" |
|
|
style="background-color: rgba(229, 231, 235, 0.8)" |
|
|
> |
|
|
<i class="fas fa-tachometer-alt"></i> 监控面板 |
|
|
</a> |
|
|
<a |
|
|
href="/logs" |
|
|
class="nav-link whitespace-nowrap flex items-center justify-center gap-2 px-6 py-3 font-medium rounded-lg text-gray-700 hover:text-gray-900 transition-all duration-200" |
|
|
style="background-color: rgba(229, 231, 235, 0.8)" |
|
|
> |
|
|
<i class="fas fa-exclamation-triangle"></i> 错误日志 |
|
|
</a> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="flex justify-center mb-6 flex-wrap gap-2"> |
|
|
<button |
|
|
class="tab-btn active px-5 py-2 rounded-full font-medium text-sm transition-all duration-200" |
|
|
data-tab="api" |
|
|
style=" |
|
|
background-color: #3b82f6 !important; |
|
|
color: #ffffff !important; |
|
|
border: 2px solid #2563eb !important; |
|
|
box-shadow: 0 4px 12px -2px rgba(59, 130, 246, 0.4), |
|
|
0 2px 6px -1px rgba(59, 130, 246, 0.2) !important; |
|
|
transform: translateY(-2px) !important; |
|
|
font-weight: 600 !important; |
|
|
" |
|
|
> |
|
|
API配置 |
|
|
</button> |
|
|
<button |
|
|
class="tab-btn px-5 py-2 rounded-full font-medium text-sm transition-all duration-200" |
|
|
data-tab="model" |
|
|
style=" |
|
|
background-color: #f8fafc !important; |
|
|
color: #64748b !important; |
|
|
border: 2px solid #e2e8f0 !important; |
|
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1) !important; |
|
|
font-weight: 500 !important; |
|
|
" |
|
|
> |
|
|
模型配置 |
|
|
</button> |
|
|
<button |
|
|
class="tab-btn px-5 py-2 rounded-full font-medium text-sm transition-all duration-200" |
|
|
data-tab="tts" |
|
|
style=" |
|
|
background-color: #f8fafc !important; |
|
|
color: #64748b !important; |
|
|
border: 2px solid #e2e8f0 !important; |
|
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1) !important; |
|
|
font-weight: 500 !important; |
|
|
" |
|
|
> |
|
|
TTS 配置 |
|
|
</button> |
|
|
<button |
|
|
class="tab-btn px-5 py-2 rounded-full font-medium text-sm transition-all duration-200" |
|
|
data-tab="image" |
|
|
style=" |
|
|
background-color: #f8fafc !important; |
|
|
color: #64748b !important; |
|
|
border: 2px solid #e2e8f0 !important; |
|
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1) !important; |
|
|
font-weight: 500 !important; |
|
|
" |
|
|
> |
|
|
图像生成 |
|
|
</button> |
|
|
<button |
|
|
class="tab-btn px-5 py-2 rounded-full font-medium text-sm transition-all duration-200" |
|
|
data-tab="stream" |
|
|
style=" |
|
|
background-color: #f8fafc !important; |
|
|
color: #64748b !important; |
|
|
border: 2px solid #e2e8f0 !important; |
|
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1) !important; |
|
|
font-weight: 500 !important; |
|
|
" |
|
|
> |
|
|
流式输出 |
|
|
</button> |
|
|
<button |
|
|
class="tab-btn px-5 py-2 rounded-full font-medium text-sm transition-all duration-200" |
|
|
data-tab="scheduler" |
|
|
style=" |
|
|
background-color: #f8fafc !important; |
|
|
color: #64748b !important; |
|
|
border: 2px solid #e2e8f0 !important; |
|
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1) !important; |
|
|
font-weight: 500 !important; |
|
|
" |
|
|
> |
|
|
定时任务 |
|
|
</button> |
|
|
<button |
|
|
class="tab-btn px-5 py-2 rounded-full font-medium text-sm transition-all duration-200" |
|
|
data-tab="logging" |
|
|
style=" |
|
|
background-color: #f8fafc !important; |
|
|
color: #64748b !important; |
|
|
border: 2px solid #e2e8f0 !important; |
|
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1) !important; |
|
|
font-weight: 500 !important; |
|
|
" |
|
|
> |
|
|
日志配置 |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<form id="configForm" class="mt-6"> |
|
|
|
|
|
<div class="config-section active" id="api-section"> |
|
|
<h2 |
|
|
class="text-xl font-bold mb-6 pb-3 border-b flex items-center gap-2 text-gray-800 border-gray-300" |
|
|
> |
|
|
<i class="fas fa-key text-blue-500"></i> API相关配置 |
|
|
</h2> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label for="API_KEYS" class="block font-semibold mb-2 text-gray-800" |
|
|
>API密钥列表 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="Gemini API密钥列表,每行一个"></i> |
|
|
</label> |
|
|
<div class="mb-2"> |
|
|
<input |
|
|
type="search" |
|
|
id="apiKeySearchInput" |
|
|
placeholder="搜索密钥..." |
|
|
class="w-full px-4 py-2 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
<div class="array-container" id="API_KEYS_container"> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div id="apiKeyPagination" class="flex items-center justify-between mt-2 mb-2" style="display: none;"> |
|
|
<div class="flex items-center gap-2"> |
|
|
<button |
|
|
type="button" |
|
|
id="apiKeyPrevBtn" |
|
|
class="px-3 py-1 rounded bg-blue-500 text-white hover:bg-blue-600 cursor-pointer" |
|
|
> |
|
|
<i class="fas fa-chevron-left"></i> 上一页 |
|
|
</button> |
|
|
<span id="apiKeyPageInfo" class="text-sm text-gray-600">第 1 页,共 1 页</span> |
|
|
<button |
|
|
type="button" |
|
|
id="apiKeyNextBtn" |
|
|
class="px-3 py-1 rounded bg-blue-500 text-white hover:bg-blue-600 cursor-pointer" |
|
|
> |
|
|
下一页 <i class="fas fa-chevron-right"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div class="text-xs text-gray-500"> |
|
|
每页显示 20 个密钥 |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex justify-end gap-2"> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
id="bulkDeleteApiKeyBtn" |
|
|
> |
|
|
<i class="fas fa-trash-alt"></i> 删除密钥 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
id="addApiKeyBtn" |
|
|
> |
|
|
<i class="fas fa-plus"></i> 添加密钥 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="ALLOWED_TOKENS" |
|
|
class="block font-semibold mb-2 text-gray-800" |
|
|
>允许的令牌列表 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="允许访问API的令牌列表"></i> |
|
|
</label> |
|
|
<div class="array-container" id="ALLOWED_TOKENS_container"> |
|
|
|
|
|
</div> |
|
|
<div class="flex justify-end"> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
onclick="addArrayItem('ALLOWED_TOKENS')" |
|
|
> |
|
|
<i class="fas fa-plus"></i> 添加令牌 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label for="AUTH_TOKEN" class="block font-semibold mb-2 text-gray-800" |
|
|
>认证令牌 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="用于API认证的令牌"></i> |
|
|
</label> |
|
|
<div class="flex items-center"> |
|
|
<div |
|
|
class="flex items-center flex-grow border rounded-md focus-within:border-blue-500" |
|
|
style="border-color: rgba(0, 0, 0, 0.12)" |
|
|
> |
|
|
<input |
|
|
type="text" |
|
|
id="AUTH_TOKEN" |
|
|
name="AUTH_TOKEN" |
|
|
placeholder="默认使用ALLOWED_TOKENS中的第一个" |
|
|
class="array-input flex-grow px-3 py-2 rounded-l-md sensitive-input form-input-themed" |
|
|
/> |
|
|
<button |
|
|
type="button" |
|
|
id="generateAuthTokenBtn" |
|
|
class="generate-btn px-2 py-2 text-gray-400 hover:text-blue-500 focus:outline-none rounded-r-md hover:bg-gray-600 transition-colors" |
|
|
title="生成随机令牌" |
|
|
style="background-color: rgba(59, 130, 246, 0.1)" |
|
|
> |
|
|
<i class="fas fa-dice"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label for="BASE_URL" class="block font-semibold mb-2 text-gray-700" |
|
|
>API基础URL |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="Gemini API的基础URL"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="BASE_URL" |
|
|
name="BASE_URL" |
|
|
placeholder="https://generativelanguage.googleapis.com/v1beta" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="CUSTOM_HEADERS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>自定义Headers |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="在这里添加的键值对将被添加到所有出站API请求的Header中"></i> |
|
|
</label> |
|
|
<div |
|
|
class="bg-white rounded-lg border border-gray-200 p-4 mb-2 space-y-3" |
|
|
id="CUSTOM_HEADERS_container" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.95); |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
color: #374151; |
|
|
" |
|
|
> |
|
|
|
|
|
<div class="text-gray-500 text-sm italic"> |
|
|
添加自定义请求头,例如 X-Api-Key: your-key |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex justify-end"> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
id="addCustomHeaderBtn" |
|
|
> |
|
|
<i class="fas fa-plus"></i> 添加Header |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="VERTEX_API_KEYS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>Vertex Express API密钥列表 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="Vertex AI Platform API密钥列表。点击按钮可批量添加或删除"></i> |
|
|
</label> |
|
|
<div class="array-container" id="VERTEX_API_KEYS_container"> |
|
|
|
|
|
</div> |
|
|
<div class="flex justify-end gap-2"> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
id="bulkDeleteVertexApiKeyBtn" |
|
|
> |
|
|
<i class="fas fa-trash-alt"></i> 删除Vertex密钥 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
id="addVertexApiKeyBtn" |
|
|
> |
|
|
<i class="fas fa-plus"></i> 添加Vertex密钥 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="VERTEX_EXPRESS_BASE_URL" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>Vertex Express API基础URL |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="Vertex Express API的基础URL"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="VERTEX_EXPRESS_BASE_URL" |
|
|
name="VERTEX_EXPRESS_BASE_URL" |
|
|
placeholder="https://aiplatform.googleapis.com/v1beta1/publishers/google/models" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<div class="flex items-center justify-between"> |
|
|
<label |
|
|
for="URL_NORMALIZATION_ENABLED" |
|
|
class="font-semibold text-gray-700" |
|
|
>启用智能路由映射 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="自动客户端请求的url拼接为正确格式(仅保证正常聊天,出现问题请关闭)"></i> |
|
|
</label> |
|
|
<div |
|
|
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in" |
|
|
> |
|
|
<input |
|
|
type="checkbox" |
|
|
name="URL_NORMALIZATION_ENABLED" |
|
|
id="URL_NORMALIZATION_ENABLED" |
|
|
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" |
|
|
/> |
|
|
<label |
|
|
for="URL_NORMALIZATION_ENABLED" |
|
|
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer" |
|
|
></label> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="MAX_FAILURES" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>最大失败次数 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="API密钥失败后标记为无效的次数"></i> |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="MAX_FAILURES" |
|
|
name="MAX_FAILURES" |
|
|
min="1" |
|
|
max="100" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label for="TIME_OUT" class="block font-semibold mb-2 text-gray-700" |
|
|
>请求超时时间(秒) |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="API请求的超时时间"></i> |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="TIME_OUT" |
|
|
name="TIME_OUT" |
|
|
min="1" |
|
|
max="600" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="MAX_RETRIES" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>最大重试次数 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="API请求失败后的最大重试次数"></i> |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="MAX_RETRIES" |
|
|
name="MAX_RETRIES" |
|
|
min="0" |
|
|
max="10" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<label for="PROXIES" class="block font-semibold mb-2 text-gray-700" |
|
|
>代理服务器列表 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="代理服务器列表,支持 http 和 socks5 格式,例如: http://user:pass@host:port 或 socks5://host:port。点击按钮可批量添加或删除"></i> |
|
|
</label> |
|
|
<div class="array-container" id="PROXIES_container"> |
|
|
|
|
|
</div> |
|
|
<div class="flex justify-end gap-2"> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
id="bulkDeleteProxyBtn" |
|
|
> |
|
|
<i class="fas fa-trash-alt"></i> 删除代理 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
id="checkAllProxiesBtn" |
|
|
> |
|
|
<i class="fas fa-globe"></i> 检测所有代理 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
id="addProxyBtn" |
|
|
> |
|
|
<i class="fas fa-plus"></i> 添加代理 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<div class="flex items-center justify-between"> |
|
|
<label |
|
|
for="PROXIES_USE_CONSISTENCY_HASH_BY_API_KEY" |
|
|
class="font-semibold text-gray-700" |
|
|
>是否开启固定代理策略 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="开启后,对于每一个API_KEY将根据算法从代理列表中选取同一个代理IP,防止一个API_KEY同时被多个IP访问,也同时防止了一个IP访问了过多的API_KEY"></i> |
|
|
</label> |
|
|
<div |
|
|
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in" |
|
|
> |
|
|
<input |
|
|
type="checkbox" |
|
|
name="PROXIES_USE_CONSISTENCY_HASH_BY_API_KEY" |
|
|
id="PROXIES_USE_CONSISTENCY_HASH_BY_API_KEY" |
|
|
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" |
|
|
/> |
|
|
<label |
|
|
for="PROXIES_USE_CONSISTENCY_HASH_BY_API_KEY" |
|
|
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer" |
|
|
></label> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="config-section" id="model-section"> |
|
|
<h2 |
|
|
class="text-xl font-bold mb-6 pb-3 border-b flex items-center gap-2 text-gray-800 border-violet-300 border-opacity-30" |
|
|
> |
|
|
<i class="fas fa-robot text-violet-400"></i> 模型相关配置 |
|
|
</h2> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label for="TEST_MODEL" class="block font-semibold mb-2 text-gray-700" |
|
|
>测试模型 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="用于测试API密钥的模型"></i> |
|
|
</label> |
|
|
<div class="flex items-center gap-2"> |
|
|
<input |
|
|
type="text" |
|
|
id="TEST_MODEL" |
|
|
name="TEST_MODEL" |
|
|
placeholder="gemini-1.5-flash" |
|
|
class="flex-grow px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
<button |
|
|
type="button" |
|
|
title="选择模型" |
|
|
class="model-helper-trigger-btn p-2 rounded-md text-violet-300 hover:bg-violet-700 transition-colors" |
|
|
data-target-input-id="TEST_MODEL" |
|
|
> |
|
|
<i class="fas fa-list-ul"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="IMAGE_MODELS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>图像模型列表 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="支持图像处理的模型列表"></i> |
|
|
</label> |
|
|
<div class="array-container" id="IMAGE_MODELS_container"> |
|
|
|
|
|
</div> |
|
|
<div class="flex justify-end gap-2 mt-2"> |
|
|
<button |
|
|
type="button" |
|
|
title="从列表选择模型添加到下方" |
|
|
class="model-helper-trigger-btn p-2 rounded-md text-violet-300 hover:bg-violet-700 transition-colors" |
|
|
data-target-array-key="IMAGE_MODELS" |
|
|
> |
|
|
<i class="fas fa-list-ul"></i> |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-violet-600 hover:bg-violet-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
onclick="addArrayItem('IMAGE_MODELS')" |
|
|
> |
|
|
<i class="fas fa-plus"></i> 添加模型 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="SEARCH_MODELS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>搜索模型列表 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="支持搜索功能的模型列表"></i> |
|
|
</label> |
|
|
<div class="array-container" id="SEARCH_MODELS_container"> |
|
|
|
|
|
</div> |
|
|
<div class="flex justify-end gap-2 mt-2"> |
|
|
<button |
|
|
type="button" |
|
|
title="从列表选择模型添加到下方" |
|
|
class="model-helper-trigger-btn p-2 rounded-md text-violet-300 hover:bg-violet-700 transition-colors" |
|
|
data-target-array-key="SEARCH_MODELS" |
|
|
> |
|
|
<i class="fas fa-list-ul"></i> |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-violet-600 hover:bg-violet-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
onclick="addArrayItem('SEARCH_MODELS')" |
|
|
> |
|
|
<i class="fas fa-plus"></i> 添加模型 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="FILTERED_MODELS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>过滤模型列表 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="需要过滤的模型列表"></i> |
|
|
</label> |
|
|
<div class="array-container" id="FILTERED_MODELS_container"> |
|
|
|
|
|
</div> |
|
|
<div class="flex justify-end gap-2 mt-2"> |
|
|
<button |
|
|
type="button" |
|
|
title="从列表选择模型添加到下方" |
|
|
class="model-helper-trigger-btn p-2 rounded-md text-violet-300 hover:bg-violet-700 transition-colors" |
|
|
data-target-array-key="FILTERED_MODELS" |
|
|
> |
|
|
<i class="fas fa-list-ul"></i> |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-violet-600 hover:bg-violet-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
onclick="addArrayItem('FILTERED_MODELS')" |
|
|
> |
|
|
<i class="fas fa-plus"></i> 添加模型 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<div class="flex items-center justify-between"> |
|
|
<label |
|
|
for="TOOLS_CODE_EXECUTION_ENABLED" |
|
|
class="font-semibold text-gray-700" |
|
|
>启用代码执行工具</label |
|
|
> |
|
|
<div |
|
|
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in" |
|
|
> |
|
|
<input |
|
|
type="checkbox" |
|
|
name="TOOLS_CODE_EXECUTION_ENABLED" |
|
|
id="TOOLS_CODE_EXECUTION_ENABLED" |
|
|
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" |
|
|
/> |
|
|
<label |
|
|
for="TOOLS_CODE_EXECUTION_ENABLED" |
|
|
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer" |
|
|
></label> |
|
|
</div> |
|
|
</div> |
|
|
<div class="warning-text"> |
|
|
<i class="fas fa-exclamation-triangle"></i> |
|
|
<span>启用代码执行工具与大多数工具调用冲突,不建议开启</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 flex items-center justify-between"> |
|
|
<label for="URL_CONTEXT_ENABLED" class="font-semibold text-gray-700" |
|
|
>启用网址上下文</label |
|
|
> |
|
|
<div |
|
|
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in" |
|
|
> |
|
|
<input |
|
|
type="checkbox" |
|
|
name="URL_CONTEXT_ENABLED" |
|
|
id="URL_CONTEXT_ENABLED" |
|
|
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" |
|
|
/> |
|
|
<label |
|
|
for="URL_CONTEXT_ENABLED" |
|
|
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer" |
|
|
></label> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="URL_CONTEXT_MODELS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>网址上下文模型列表 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="支持网址上下文功能的模型列表"></i> |
|
|
</label> |
|
|
<div class="array-container" id="URL_CONTEXT_MODELS_container"> |
|
|
|
|
|
</div> |
|
|
<div class="flex justify-end gap-2 mt-2"> |
|
|
<button |
|
|
type="button" |
|
|
title="从列表选择模型添加到下方" |
|
|
class="model-helper-trigger-btn p-2 rounded-md text-violet-300 hover:bg-violet-700 transition-colors" |
|
|
data-target-array-key="URL_CONTEXT_MODELS" |
|
|
> |
|
|
<i class="fas fa-list-ul"></i> |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-violet-600 hover:bg-violet-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
onclick="addArrayItem('URL_CONTEXT_MODELS')" |
|
|
> |
|
|
<i class="fas fa-plus"></i> 添加模型 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 flex items-center justify-between"> |
|
|
<label for="SHOW_SEARCH_LINK" class="font-semibold text-gray-700" |
|
|
>显示搜索链接</label |
|
|
> |
|
|
<div |
|
|
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in" |
|
|
> |
|
|
<input |
|
|
type="checkbox" |
|
|
name="SHOW_SEARCH_LINK" |
|
|
id="SHOW_SEARCH_LINK" |
|
|
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" |
|
|
/> |
|
|
<label |
|
|
for="SHOW_SEARCH_LINK" |
|
|
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer" |
|
|
></label> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 flex items-center justify-between"> |
|
|
<label for="SHOW_THINKING_PROCESS" class="font-semibold text-gray-700" |
|
|
>显示思考过程</label |
|
|
> |
|
|
<div |
|
|
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in" |
|
|
> |
|
|
<input |
|
|
type="checkbox" |
|
|
name="SHOW_THINKING_PROCESS" |
|
|
id="SHOW_THINKING_PROCESS" |
|
|
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" |
|
|
/> |
|
|
<label |
|
|
for="SHOW_THINKING_PROCESS" |
|
|
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer" |
|
|
></label> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="THINKING_MODELS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>思考模型列表 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="用于思考过程的模型列表"></i> |
|
|
</label> |
|
|
<div class="array-container" id="THINKING_MODELS_container"> |
|
|
|
|
|
</div> |
|
|
<div class="flex justify-end gap-2 mt-2"> |
|
|
<button |
|
|
type="button" |
|
|
title="从列表选择模型添加到下方" |
|
|
class="model-helper-trigger-btn p-2 rounded-md text-violet-300 hover:bg-violet-700 transition-colors" |
|
|
data-target-array-key="THINKING_MODELS" |
|
|
> |
|
|
<i class="fas fa-list-ul"></i> |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-violet-600 hover:bg-violet-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
onclick="addArrayItem('THINKING_MODELS')" |
|
|
> |
|
|
<i class="fas fa-plus"></i> 添加模型 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="THINKING_BUDGET_MAP" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>思考模型预算映射 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="为每个思考模型设置预算(-1为auto,最大值32767),此项与上方模型列表自动关联"></i> |
|
|
</label> |
|
|
<div |
|
|
class="bg-white rounded-lg border border-gray-200 p-4 mb-2 space-y-3" |
|
|
id="THINKING_BUDGET_MAP_container" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.95); |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
color: #374151; |
|
|
" |
|
|
> |
|
|
|
|
|
<div class="text-gray-500 text-sm italic"> |
|
|
请先在上方添加思考模型,然后在此处配置预算。 |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="SAFETY_SETTINGS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>安全设置 (Safety Settings) |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="配置模型的安全过滤级别,例如 HARM_CATEGORY_HARASSMENT: BLOCK_NONE"></i> |
|
|
</label> |
|
|
<div |
|
|
class="bg-white rounded-lg border border-gray-200 p-4 mb-2 space-y-3" |
|
|
id="SAFETY_SETTINGS_container" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.95); |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
color: #374151; |
|
|
" |
|
|
> |
|
|
|
|
|
<div class="text-gray-500 text-sm italic"> |
|
|
定义模型的安全过滤阈值。 |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex justify-end"> |
|
|
<button |
|
|
type="button" |
|
|
class="bg-violet-600 hover:bg-violet-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" |
|
|
id="addSafetySettingBtn" |
|
|
> |
|
|
<i class="fas fa-plus"></i> 添加安全设置 |
|
|
</button> |
|
|
</div> |
|
|
<div class="warning-text"> |
|
|
<i class="fas fa-exclamation-triangle"></i> |
|
|
<span |
|
|
>建议设置成OFF,其他值会影响输出速度,非必要不要随便改动。</span |
|
|
> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="config-section" id="tts-section"> |
|
|
<h2 |
|
|
class="text-xl font-bold mb-6 pb-3 border-b flex items-center gap-2 text-gray-800 border-violet-300 border-opacity-30" |
|
|
> |
|
|
<i class="fas fa-volume-up text-violet-400"></i> TTS 相关配置 |
|
|
</h2> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label for="TTS_MODEL" class="block font-semibold mb-2 text-gray-700" |
|
|
>TTS 模型 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="用于TTS的模型"></i> |
|
|
</label> |
|
|
<select |
|
|
id="TTS_MODEL" |
|
|
name="TTS_MODEL" |
|
|
class="w-full px-4 py-3 rounded-lg form-select-themed" |
|
|
> |
|
|
<option value="gemini-2.5-flash-preview-tts"> |
|
|
gemini-2.5-flash-preview-tts |
|
|
</option> |
|
|
<option value="gemini-2.5-pro-preview-tts"> |
|
|
gemini-2.5-pro-preview-tts |
|
|
</option> |
|
|
</select> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="TTS_VOICE_NAME" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>TTS 语音名称 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="TTS 的语音名称,控制风格、语调、口音和节奏"></i> |
|
|
</label> |
|
|
<select |
|
|
id="TTS_VOICE_NAME" |
|
|
name="TTS_VOICE_NAME" |
|
|
class="w-full px-4 py-3 rounded-lg form-select-themed" |
|
|
> |
|
|
<option value="Zephyr">Zephyr (明亮)</option> |
|
|
<option value="Puck">Puck (欢快)</option> |
|
|
<option value="Charon">Charon (信息丰富)</option> |
|
|
<option value="Kore">Kore (坚定)</option> |
|
|
<option value="Fenrir">Fenrir (易激动)</option> |
|
|
<option value="Leda">Leda (年轻)</option> |
|
|
<option value="Orus">Orus (坚定)</option> |
|
|
<option value="Aoede">Aoede (轻松)</option> |
|
|
<option value="Callirrhoe">Callirrhoe (随和)</option> |
|
|
<option value="Autonoe">Autonoe (明亮)</option> |
|
|
<option value="Enceladus">Enceladus (呼吸感)</option> |
|
|
<option value="Iapetus">Iapetus (清晰)</option> |
|
|
<option value="Umbriel">Umbriel (随和)</option> |
|
|
<option value="Algieba">Algieba (平滑)</option> |
|
|
<option value="Despina">Despina (平滑)</option> |
|
|
<option value="Erinome">Erinome (清晰)</option> |
|
|
<option value="Algenib">Algenib (沙哑)</option> |
|
|
<option value="Rasalgethi">Rasalgethi (信息丰富)</option> |
|
|
<option value="Laomedeia">Laomedeia (欢快)</option> |
|
|
<option value="Achernar">Achernar (轻柔)</option> |
|
|
<option value="Alnilam">Alnilam (坚定)</option> |
|
|
<option value="Schedar">Schedar (平稳)</option> |
|
|
<option value="Gacrux">Gacrux (成熟)</option> |
|
|
<option value="Pulcherrima">Pulcherrima (向前)</option> |
|
|
<option value="Achird">Achird (友好)</option> |
|
|
<option value="Zubenelgenubi">Zubenelgenubi (休闲)</option> |
|
|
<option value="Vindemiatrix">Vindemiatrix (温柔)</option> |
|
|
<option value="Sadachbia">Sadachbia (活泼)</option> |
|
|
<option value="Sadaltager">Sadaltager (博学)</option> |
|
|
<option value="Sulafat">Sulafat (温暖)</option> |
|
|
</select> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label for="TTS_SPEED" class="block font-semibold mb-2 text-gray-700" |
|
|
>TTS 语速 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="选择 TTS 的语速"></i> |
|
|
</label> |
|
|
<select |
|
|
id="TTS_SPEED" |
|
|
name="TTS_SPEED" |
|
|
class="w-full px-4 py-3 rounded-lg form-select-themed" |
|
|
> |
|
|
<option value="slow">慢</option> |
|
|
<option value="normal">正常</option> |
|
|
<option value="fast">快</option> |
|
|
</select> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="config-section" id="image-section"> |
|
|
<h2 |
|
|
class="text-xl font-bold mb-6 pb-3 border-b flex items-center gap-2 text-gray-800 border-violet-300 border-opacity-30" |
|
|
> |
|
|
<i class="fas fa-image text-violet-400"></i> 图像生成配置 |
|
|
</h2> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label for="PAID_KEY" class="block font-semibold mb-2 text-gray-700" |
|
|
>付费API密钥 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="用于图像生成的付费API密钥"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="PAID_KEY" |
|
|
name="PAID_KEY" |
|
|
placeholder="AIzaSyxxxxxxxxxxxxxxxxxxx" |
|
|
class="w-full px-4 py-3 rounded-lg sensitive-input form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="CREATE_IMAGE_MODEL" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>图像生成模型 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="用于图像生成的模型"></i> |
|
|
</label> |
|
|
<div class="flex items-center gap-2"> |
|
|
<input |
|
|
type="text" |
|
|
id="CREATE_IMAGE_MODEL" |
|
|
name="CREATE_IMAGE_MODEL" |
|
|
placeholder="imagen-3.0-generate-002" |
|
|
class="flex-grow px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
<button |
|
|
type="button" |
|
|
title="选择模型" |
|
|
class="model-helper-trigger-btn p-2 rounded-md text-violet-300 hover:bg-violet-700 transition-colors" |
|
|
data-target-input-id="CREATE_IMAGE_MODEL" |
|
|
> |
|
|
<i class="fas fa-list-ul"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="UPLOAD_PROVIDER" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>上传提供商 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="图片上传服务提供商"></i> |
|
|
</label> |
|
|
<select |
|
|
id="UPLOAD_PROVIDER" |
|
|
name="UPLOAD_PROVIDER" |
|
|
class="w-full px-4 py-3 rounded-lg form-select-themed" |
|
|
> |
|
|
<option value="smms" selected>SM.MS</option> |
|
|
<option value="picgo">PicGo</option> |
|
|
<option value="cloudflare_imgbed">Cloudflare</option> |
|
|
<option value="aliyun_oss">阿里云OSS</option> |
|
|
</select> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config active" data-provider="smms"> |
|
|
<label |
|
|
for="SMMS_SECRET_TOKEN" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>SM.MS密钥 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="SM.MS图床的密钥"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="SMMS_SECRET_TOKEN" |
|
|
name="SMMS_SECRET_TOKEN" |
|
|
placeholder="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" |
|
|
class="w-full px-4 py-3 rounded-lg sensitive-input form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config" data-provider="picgo"> |
|
|
<label |
|
|
for="PICGO_API_URL" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>PicGo API地址 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="PicGo服务器的API地址,默认为 https://www.picgo.net/api/1/upload"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="PICGO_API_URL" |
|
|
name="PICGO_API_URL" |
|
|
placeholder="https://www.picgo.net/api/1/upload" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config" data-provider="picgo"> |
|
|
<label |
|
|
for="PICGO_API_KEY" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>PicGo API密钥 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="PicGo的API密钥"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="PICGO_API_KEY" |
|
|
name="PICGO_API_KEY" |
|
|
placeholder="xxxx" |
|
|
class="w-full px-4 py-3 rounded-lg sensitive-input form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config" data-provider="cloudflare_imgbed"> |
|
|
<label |
|
|
for="CLOUDFLARE_IMGBED_URL" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>Cloudflare图床URL |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="Cloudflare图床的URL"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="CLOUDFLARE_IMGBED_URL" |
|
|
name="CLOUDFLARE_IMGBED_URL" |
|
|
placeholder="https://xxxxxxx.pages.dev/upload" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config" data-provider="cloudflare_imgbed"> |
|
|
<label |
|
|
for="CLOUDFLARE_IMGBED_AUTH_CODE" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>Cloudflare认证码 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="Cloudflare图床的认证码"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="CLOUDFLARE_IMGBED_AUTH_CODE" |
|
|
name="CLOUDFLARE_IMGBED_AUTH_CODE" |
|
|
placeholder="xxxxxxxxx" |
|
|
class="w-full px-4 py-3 rounded-lg sensitive-input form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config" data-provider="cloudflare_imgbed"> |
|
|
<label |
|
|
for="CLOUDFLARE_IMGBED_UPLOAD_FOLDER" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>Cloudflare上传文件夹 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="Cloudflare图床的上传文件夹路径(可选)"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="CLOUDFLARE_IMGBED_UPLOAD_FOLDER" |
|
|
name="CLOUDFLARE_IMGBED_UPLOAD_FOLDER" |
|
|
placeholder="" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config" data-provider="aliyun_oss"> |
|
|
<label |
|
|
for="OSS_ENDPOINT" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>OSS Endpoint |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="阿里云OSS的Endpoint地址"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="OSS_ENDPOINT" |
|
|
name="OSS_ENDPOINT" |
|
|
placeholder="oss-cn-shanghai.aliyuncs.com" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config" data-provider="aliyun_oss"> |
|
|
<label |
|
|
for="OSS_ACCESS_KEY" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>OSS Access Key |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="阿里云OSS的Access Key ID"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="OSS_ACCESS_KEY" |
|
|
name="OSS_ACCESS_KEY" |
|
|
placeholder="LTAI5txxxxxxxxxx" |
|
|
class="w-full px-4 py-3 rounded-lg sensitive-input form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config" data-provider="aliyun_oss"> |
|
|
<label |
|
|
for="OSS_ACCESS_KEY_SECRET" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>OSS Access Key Secret |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="阿里云OSS的Access Key Secret"></i> |
|
|
</label> |
|
|
<input |
|
|
type="password" |
|
|
id="OSS_ACCESS_KEY_SECRET" |
|
|
name="OSS_ACCESS_KEY_SECRET" |
|
|
placeholder="yXxxxxxxxxxxxx" |
|
|
class="w-full px-4 py-3 rounded-lg sensitive-input form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config" data-provider="aliyun_oss"> |
|
|
<label |
|
|
for="OSS_BUCKET_NAME" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>OSS Bucket名称 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="阿里云OSS的Bucket名称"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="OSS_BUCKET_NAME" |
|
|
name="OSS_BUCKET_NAME" |
|
|
placeholder="your-bucket-name" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config" data-provider="aliyun_oss"> |
|
|
<label |
|
|
for="OSS_REGION" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>OSS Region |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="阿里云OSS的Region区域"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="OSS_REGION" |
|
|
name="OSS_REGION" |
|
|
placeholder="cn-shanghai" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6 provider-config" data-provider="aliyun_oss"> |
|
|
<label |
|
|
for="OSS_ENDPOINT_INNER" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>OSS内网Endpoint(可选) |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="阿里云OSS的内网Endpoint地址(可选)"></i> |
|
|
</label> |
|
|
<input |
|
|
type="text" |
|
|
id="OSS_ENDPOINT_INNER" |
|
|
name="OSS_ENDPOINT_INNER" |
|
|
placeholder="oss-cn-shanghai-internal.aliyuncs.com" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="config-section" id="stream-section"> |
|
|
<h2 |
|
|
class="text-xl font-bold mb-6 pb-3 border-b flex items-center gap-2 text-gray-800 border-violet-300 border-opacity-30" |
|
|
> |
|
|
<i class="fas fa-stream text-violet-400"></i> 流式输出相关配置 |
|
|
</h2> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<div class="flex items-center justify-between"> |
|
|
<label |
|
|
for="STREAM_OPTIMIZER_ENABLED" |
|
|
class="font-semibold text-gray-700" |
|
|
>启用流式输出优化</label |
|
|
> |
|
|
<div |
|
|
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in" |
|
|
> |
|
|
<input |
|
|
type="checkbox" |
|
|
name="STREAM_OPTIMIZER_ENABLED" |
|
|
id="STREAM_OPTIMIZER_ENABLED" |
|
|
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" |
|
|
/> |
|
|
<label |
|
|
for="STREAM_OPTIMIZER_ENABLED" |
|
|
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer" |
|
|
></label> |
|
|
</div> |
|
|
</div> |
|
|
<div class="warning-text"> |
|
|
<i class="fas fa-exclamation-triangle"></i> |
|
|
<span>开启流式优化会在一定程度上减速返回,不建议开启</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="STREAM_MIN_DELAY" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>最小延迟(秒) |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="流式输出的最小延迟时间"></i> |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="STREAM_MIN_DELAY" |
|
|
name="STREAM_MIN_DELAY" |
|
|
min="0" |
|
|
max="1" |
|
|
step="0.001" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="STREAM_MAX_DELAY" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>最大延迟(秒) |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="流式输出的最大延迟时间"></i> |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="STREAM_MAX_DELAY" |
|
|
name="STREAM_MAX_DELAY" |
|
|
min="0" |
|
|
max="1" |
|
|
step="0.001" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="STREAM_SHORT_TEXT_THRESHOLD" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>短文本阈值 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="短文本的字符阈值"></i> |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="STREAM_SHORT_TEXT_THRESHOLD" |
|
|
name="STREAM_SHORT_TEXT_THRESHOLD" |
|
|
min="1" |
|
|
max="100" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="STREAM_LONG_TEXT_THRESHOLD" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>长文本阈值 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="长文本的字符阈值"></i> |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="STREAM_LONG_TEXT_THRESHOLD" |
|
|
name="STREAM_LONG_TEXT_THRESHOLD" |
|
|
min="1" |
|
|
max="1000" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="STREAM_CHUNK_SIZE" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>分块大小 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="流式输出的分块大小"></i> |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="STREAM_CHUNK_SIZE" |
|
|
name="STREAM_CHUNK_SIZE" |
|
|
min="1" |
|
|
max="100" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<h3 |
|
|
class="text-lg font-semibold mb-4 pt-4 border-t border-violet-300 border-opacity-20 text-gray-200" |
|
|
> |
|
|
<i class="fas fa-ghost text-violet-400"></i> 假流式配置 (Fake |
|
|
Streaming) |
|
|
</h3> |
|
|
|
|
|
|
|
|
<div class="mb-6 flex items-center justify-between"> |
|
|
<label for="FAKE_STREAM_ENABLED" class="font-semibold text-gray-700" |
|
|
>启用假流式输出 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="当启用时,将调用非流式接口,并在等待响应期间发送空数据以维持连接"></i> |
|
|
</label> |
|
|
<div |
|
|
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in" |
|
|
> |
|
|
<input |
|
|
type="checkbox" |
|
|
name="FAKE_STREAM_ENABLED" |
|
|
id="FAKE_STREAM_ENABLED" |
|
|
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" |
|
|
/> |
|
|
<label |
|
|
for="FAKE_STREAM_ENABLED" |
|
|
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer" |
|
|
></label> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="FAKE_STREAM_EMPTY_DATA_INTERVAL_SECONDS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>假流式空数据发送间隔(秒) |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="在启用假流式输出时,向客户端发送空数据以维持连接状态的时间间隔(建议 3-10 秒)"></i> |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="FAKE_STREAM_EMPTY_DATA_INTERVAL_SECONDS" |
|
|
name="FAKE_STREAM_EMPTY_DATA_INTERVAL_SECONDS" |
|
|
min="1" |
|
|
max="60" |
|
|
step="1" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="config-section" id="scheduler-section"> |
|
|
<h2 |
|
|
class="text-xl font-bold mb-6 pb-3 border-b flex items-center gap-2 text-gray-800 border-violet-300 border-opacity-30" |
|
|
> |
|
|
<i class="fas fa-clock text-violet-400"></i> 定时任务配置 |
|
|
</h2> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="CHECK_INTERVAL_HOURS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>检查间隔(小时) |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="定时检查密钥状态的间隔时间(单位:小时),设置为0时不进行定时检查"></i> |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="CHECK_INTERVAL_HOURS" |
|
|
name="CHECK_INTERVAL_HOURS" |
|
|
min="0" |
|
|
step="1" |
|
|
class="w-full px-4 py-3 rounded-lg form-input-themed" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="config-section" id="logging-section"> |
|
|
<h2 |
|
|
class="text-xl font-bold mb-6 pb-3 border-b flex items-center gap-2 text-gray-800 border-violet-300 border-opacity-30" |
|
|
> |
|
|
<i class="fas fa-file-alt text-violet-400"></i> 日志配置 |
|
|
</h2> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label for="LOG_LEVEL" class="block font-semibold mb-2 text-gray-700" |
|
|
>日志级别 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="设置应用程序的日志记录详细程度"></i> |
|
|
</label> |
|
|
<select |
|
|
id="LOG_LEVEL" |
|
|
name="LOG_LEVEL" |
|
|
class="w-full px-4 py-3 rounded-lg form-select-themed" |
|
|
> |
|
|
<option value="DEBUG">DEBUG</option> |
|
|
<option value="INFO">INFO</option> |
|
|
<option value="WARNING">WARNING</option> |
|
|
<option value="ERROR">ERROR</option> |
|
|
<option value="CRITICAL">CRITICAL</option> |
|
|
</select> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<div class="flex items-center justify-between"> |
|
|
<label |
|
|
for="ERROR_LOG_RECORD_REQUEST_BODY" |
|
|
class="font-semibold text-gray-700" |
|
|
>错误日志记录请求体 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="关闭可减少大量磁盘空间占用,默认关闭"></i> |
|
|
</label> |
|
|
<div |
|
|
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in" |
|
|
> |
|
|
<input |
|
|
type="checkbox" |
|
|
name="ERROR_LOG_RECORD_REQUEST_BODY" |
|
|
id="ERROR_LOG_RECORD_REQUEST_BODY" |
|
|
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" |
|
|
/> |
|
|
<label |
|
|
for="ERROR_LOG_RECORD_REQUEST_BODY" |
|
|
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer" |
|
|
></label> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<div class="flex items-center justify-between"> |
|
|
<label |
|
|
for="AUTO_DELETE_ERROR_LOGS_ENABLED" |
|
|
class="font-semibold text-gray-700" |
|
|
>是否开启自动删除错误日志 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="开启后,将自动删除指定天数前的错误日志"></i> |
|
|
</label> |
|
|
<div |
|
|
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in" |
|
|
> |
|
|
<input |
|
|
type="checkbox" |
|
|
name="AUTO_DELETE_ERROR_LOGS_ENABLED" |
|
|
id="AUTO_DELETE_ERROR_LOGS_ENABLED" |
|
|
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" |
|
|
/> |
|
|
<label |
|
|
for="AUTO_DELETE_ERROR_LOGS_ENABLED" |
|
|
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer" |
|
|
></label> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="AUTO_DELETE_ERROR_LOGS_DAYS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>自动删除多少天前的错误日志 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="选择自动删除错误日志的天数"></i> |
|
|
</label> |
|
|
<select |
|
|
id="AUTO_DELETE_ERROR_LOGS_DAYS" |
|
|
name="AUTO_DELETE_ERROR_LOGS_DAYS" |
|
|
class="w-full px-4 py-3 rounded-lg form-select-themed" |
|
|
> |
|
|
<option value="1">1 天</option> |
|
|
<option value="7">7 天</option> |
|
|
<option value="30">30 天</option> |
|
|
</select> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<div class="flex items-center justify-between"> |
|
|
<label |
|
|
for="AUTO_DELETE_REQUEST_LOGS_ENABLED" |
|
|
class="font-semibold text-gray-700" |
|
|
>是否开启自动删除请求日志 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="开启后,将自动删除指定天数前的请求日志"></i> |
|
|
</label> |
|
|
<div |
|
|
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in" |
|
|
> |
|
|
<input |
|
|
type="checkbox" |
|
|
name="AUTO_DELETE_REQUEST_LOGS_ENABLED" |
|
|
id="AUTO_DELETE_REQUEST_LOGS_ENABLED" |
|
|
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" |
|
|
/> |
|
|
<label |
|
|
for="AUTO_DELETE_REQUEST_LOGS_ENABLED" |
|
|
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer" |
|
|
></label> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<label |
|
|
for="AUTO_DELETE_REQUEST_LOGS_DAYS" |
|
|
class="block font-semibold mb-2 text-gray-700" |
|
|
>自动删除多少天前的请求日志 |
|
|
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="选择自动删除请求日志的天数"></i> |
|
|
</label> |
|
|
<select |
|
|
id="AUTO_DELETE_REQUEST_LOGS_DAYS" |
|
|
name="AUTO_DELETE_REQUEST_LOGS_DAYS" |
|
|
class="w-full px-4 py-3 rounded-lg form-select-themed" |
|
|
> |
|
|
<option value="1">1 天</option> |
|
|
<option value="7">7 天</option> |
|
|
<option value="30">30 天</option> |
|
|
</select> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div |
|
|
class="flex flex-col md:flex-row justify-center gap-4 mt-8 pt-4 pb-2" |
|
|
> |
|
|
<button |
|
|
type="button" |
|
|
id="saveBtn" |
|
|
class="action-btn text-white px-8 py-3 rounded-xl font-semibold transition-all duration-300 hover:shadow-lg flex items-center justify-center gap-2" |
|
|
style=" |
|
|
background-color: #3b82f6 !important; |
|
|
color: #ffffff !important; |
|
|
" |
|
|
> |
|
|
<i class="fas fa-save"></i> 保存配置 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
id="resetBtn" |
|
|
class="action-btn bg-gradient-to-r from-gray-600 to-gray-700 text-white px-8 py-3 rounded-xl font-semibold transition-all duration-300 hover:shadow-lg flex items-center justify-center gap-2" |
|
|
style=" |
|
|
background-color: #6b7280 !important; |
|
|
color: #ffffff !important; |
|
|
" |
|
|
> |
|
|
<i class="fas fa-undo"></i> 重置配置 |
|
|
</button> |
|
|
</div> |
|
|
</form> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="scroll-buttons"> |
|
|
<button class="scroll-button" onclick="scrollToTop()" title="回到顶部"> |
|
|
<i class="fas fa-chevron-up"></i> |
|
|
</button> |
|
|
<button class="scroll-button" onclick="scrollToBottom()" title="滚动到底部"> |
|
|
<i class="fas fa-chevron-down"></i> |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="notification" class="notification"></div> |
|
|
|
|
|
|
|
|
|
|
|
<div id="apiKeyModal" class="modal"> |
|
|
<div |
|
|
class="w-full max-w-lg mx-auto rounded-2xl shadow-2xl overflow-hidden animate-fade-in" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.98); |
|
|
color: #374151; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
" |
|
|
> |
|
|
<div class="p-6"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h2 class="text-xl font-bold text-gray-800">批量添加 API 密钥</h2> |
|
|
<button |
|
|
id="closeApiKeyModalBtn" |
|
|
class="text-gray-300 hover:text-gray-800 text-xl" |
|
|
> |
|
|
× |
|
|
</button> |
|
|
</div> |
|
|
<p class="text-gray-300 mb-4"> |
|
|
每行粘贴一个或多个密钥,将自动提取有效密钥并去重。 |
|
|
</p> |
|
|
<textarea |
|
|
id="apiKeyBulkInput" |
|
|
rows="10" |
|
|
placeholder="在此处粘贴 API 密钥..." |
|
|
class="w-full px-4 py-3 rounded-lg font-mono text-sm form-input-themed" |
|
|
></textarea> |
|
|
<div class="flex justify-end gap-3 mt-6"> |
|
|
<button |
|
|
type="button" |
|
|
id="confirmAddApiKeyBtn" |
|
|
class="bg-violet-600 hover:bg-violet-700 text-white px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
确认添加 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
id="cancelAddApiKeyBtn" |
|
|
class="bg-gray-500 bg-opacity-50 hover:bg-opacity-70 text-gray-200 px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
取消 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="bulkDeleteApiKeyModal" class="modal"> |
|
|
<div |
|
|
class="w-full max-w-lg mx-auto rounded-2xl shadow-2xl overflow-hidden animate-fade-in" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.98); |
|
|
color: #374151; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
" |
|
|
> |
|
|
<div class="p-6"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h2 class="text-xl font-bold text-gray-800">批量删除 API 密钥</h2> |
|
|
<button |
|
|
id="closeBulkDeleteModalBtn" |
|
|
class="text-gray-300 hover:text-gray-800 text-xl" |
|
|
> |
|
|
× |
|
|
</button> |
|
|
</div> |
|
|
<p class="text-gray-300 mb-4"> |
|
|
每行粘贴一个或多个密钥,将自动提取有效密钥并从列表中删除。 |
|
|
</p> |
|
|
<textarea |
|
|
id="bulkDeleteApiKeyInput" |
|
|
rows="10" |
|
|
placeholder="在此处粘贴要删除的 API 密钥..." |
|
|
class="w-full px-4 py-3 rounded-lg font-mono text-sm form-input-themed" |
|
|
></textarea> |
|
|
<div class="flex justify-end gap-3 mt-6"> |
|
|
<button |
|
|
type="button" |
|
|
id="confirmBulkDeleteApiKeyBtn" |
|
|
class="bg-red-600 hover:bg-red-700 text-white px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
确认删除 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
id="cancelBulkDeleteApiKeyBtn" |
|
|
class="bg-gray-500 bg-opacity-50 hover:bg-opacity-70 text-gray-200 px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
取消 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="proxyModal" class="modal"> |
|
|
<div |
|
|
class="w-full max-w-lg mx-auto rounded-2xl shadow-2xl overflow-hidden animate-fade-in" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.98); |
|
|
color: #374151; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
" |
|
|
> |
|
|
<div class="p-6"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h2 class="text-xl font-bold text-gray-800">批量添加代理服务器</h2> |
|
|
<button |
|
|
id="closeProxyModalBtn" |
|
|
class="text-gray-300 hover:text-gray-800 text-xl" |
|
|
> |
|
|
× |
|
|
</button> |
|
|
</div> |
|
|
<p class="text-gray-300 mb-4"> |
|
|
每行粘贴一个或多个代理地址,将自动提取有效地址并去重。 |
|
|
</p> |
|
|
<textarea |
|
|
id="proxyBulkInput" |
|
|
rows="10" |
|
|
placeholder="在此处粘贴代理地址 (例如 http://user:pass@host:port 或 socks5://host:port)..." |
|
|
class="w-full px-4 py-3 rounded-lg font-mono text-sm form-input-themed" |
|
|
></textarea> |
|
|
<div class="flex justify-end gap-3 mt-6"> |
|
|
<button |
|
|
type="button" |
|
|
id="confirmAddProxyBtn" |
|
|
class="bg-violet-600 hover:bg-violet-700 text-white px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
确认添加 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
id="cancelAddProxyBtn" |
|
|
class="bg-gray-500 bg-opacity-50 hover:bg-opacity-70 text-gray-200 px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
取消 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="bulkDeleteProxyModal" class="modal"> |
|
|
<div |
|
|
class="w-full max-w-lg mx-auto rounded-2xl shadow-2xl overflow-hidden animate-fade-in" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.98); |
|
|
color: #374151; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
" |
|
|
> |
|
|
<div class="p-6"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h2 class="text-xl font-bold text-gray-800">批量删除代理服务器</h2> |
|
|
<button |
|
|
id="closeBulkDeleteProxyModalBtn" |
|
|
class="text-gray-300 hover:text-gray-800 text-xl" |
|
|
> |
|
|
× |
|
|
</button> |
|
|
</div> |
|
|
<p class="text-gray-300 mb-4"> |
|
|
每行粘贴一个或多个代理地址,将自动提取有效地址并从列表中删除。 |
|
|
</p> |
|
|
<textarea |
|
|
id="bulkDeleteProxyInput" |
|
|
rows="10" |
|
|
placeholder="在此处粘贴要删除的代理地址..." |
|
|
class="w-full px-4 py-3 rounded-lg font-mono text-sm form-input-themed" |
|
|
></textarea> |
|
|
<div class="flex justify-end gap-3 mt-6"> |
|
|
<button |
|
|
type="button" |
|
|
id="confirmBulkDeleteProxyBtn" |
|
|
class="bg-red-600 hover:bg-red-700 text-white px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
确认删除 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
id="cancelBulkDeleteProxyBtn" |
|
|
class="bg-gray-500 bg-opacity-50 hover:bg-opacity-70 text-gray-200 px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
取消 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="resetConfirmModal" class="modal"> |
|
|
<div |
|
|
class="w-full max-w-md mx-auto rounded-2xl shadow-2xl overflow-hidden animate-fade-in" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.98); |
|
|
color: #374151; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
" |
|
|
> |
|
|
<div class="p-6"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h2 class="text-xl font-bold text-gray-800">确认重置配置</h2> |
|
|
<button |
|
|
id="closeResetModalBtn" |
|
|
class="text-gray-300 hover:text-gray-800 text-xl" |
|
|
> |
|
|
× |
|
|
</button> |
|
|
</div> |
|
|
<p class="text-gray-300 mb-6"> |
|
|
确定要重置所有配置吗?<br />这将恢复到默认值,此操作不可撤销。 |
|
|
</p> |
|
|
<div class="flex justify-end gap-3"> |
|
|
<button |
|
|
type="button" |
|
|
id="confirmResetBtn" |
|
|
class="bg-red-500 hover:bg-red-600 text-white px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
确认重置 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
id="cancelResetBtn" |
|
|
class="bg-violet-600 hover:bg-violet-700 text-white px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
取消 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="vertexApiKeyModal" class="modal"> |
|
|
<div |
|
|
class="w-full max-w-lg mx-auto rounded-2xl shadow-2xl overflow-hidden animate-fade-in" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.98); |
|
|
color: #374151; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
" |
|
|
> |
|
|
<div class="p-6"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h2 class="text-xl font-bold text-gray-800"> |
|
|
批量添加 Vertex Express API 密钥 |
|
|
</h2> |
|
|
<button |
|
|
id="closeVertexApiKeyModalBtn" |
|
|
class="text-gray-300 hover:text-gray-800 text-xl" |
|
|
> |
|
|
× |
|
|
</button> |
|
|
</div> |
|
|
<p class="text-gray-300 mb-4"> |
|
|
每行粘贴一个或多个密钥,将自动提取有效密钥 (格式: AQ.开头,共53位) |
|
|
并去重。 |
|
|
</p> |
|
|
<textarea |
|
|
id="vertexApiKeyBulkInput" |
|
|
rows="10" |
|
|
placeholder="在此处粘贴 Vertex Express API 密钥..." |
|
|
class="w-full px-4 py-3 rounded-lg font-mono text-sm form-input-themed" |
|
|
></textarea> |
|
|
<div class="flex justify-end gap-3 mt-6"> |
|
|
<button |
|
|
type="button" |
|
|
id="confirmAddVertexApiKeyBtn" |
|
|
class="bg-violet-600 hover:bg-violet-700 text-white px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
确认添加 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
id="cancelAddVertexApiKeyBtn" |
|
|
class="bg-gray-500 bg-opacity-50 hover:bg-opacity-70 text-gray-200 px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
取消 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="bulkDeleteVertexApiKeyModal" class="modal"> |
|
|
<div |
|
|
class="w-full max-w-lg mx-auto rounded-2xl shadow-2xl overflow-hidden animate-fade-in" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.98); |
|
|
color: #374151; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
" |
|
|
> |
|
|
<div class="p-6"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h2 class="text-xl font-bold text-gray-800"> |
|
|
批量删除 Vertex Express API 密钥 |
|
|
</h2> |
|
|
<button |
|
|
id="closeBulkDeleteVertexModalBtn" |
|
|
class="text-gray-300 hover:text-gray-800 text-xl" |
|
|
> |
|
|
× |
|
|
</button> |
|
|
</div> |
|
|
<p class="text-gray-300 mb-4"> |
|
|
每行粘贴一个或多个密钥,将自动提取有效密钥并从列表中删除。 |
|
|
</p> |
|
|
<textarea |
|
|
id="bulkDeleteVertexApiKeyInput" |
|
|
rows="10" |
|
|
placeholder="在此处粘贴要删除的 Vertex Express API 密钥..." |
|
|
class="w-full px-4 py-3 rounded-lg font-mono text-sm form-input-themed" |
|
|
></textarea> |
|
|
<div class="flex justify-end gap-3 mt-6"> |
|
|
<button |
|
|
type="button" |
|
|
id="confirmBulkDeleteVertexApiKeyBtn" |
|
|
class="bg-red-600 hover:bg-red-700 text-white px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
确认删除 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
id="cancelBulkDeleteVertexApiKeyBtn" |
|
|
class="bg-gray-500 bg-opacity-50 hover:bg-opacity-70 text-gray-200 px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
取消 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="proxyCheckModal" class="modal"> |
|
|
<div |
|
|
class="w-full max-w-4xl mx-auto rounded-2xl shadow-2xl overflow-hidden animate-fade-in" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.98); |
|
|
color: #374151; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
" |
|
|
> |
|
|
<div class="p-6"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h2 class="text-xl font-bold text-gray-800">代理检测结果</h2> |
|
|
<button |
|
|
id="closeProxyCheckModalBtn" |
|
|
class="text-gray-300 hover:text-gray-800 text-xl" |
|
|
> |
|
|
× |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="proxyCheckProgress" class="mb-4 hidden"> |
|
|
<div class="flex items-center gap-2 mb-2"> |
|
|
<div class="w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin"></div> |
|
|
<span class="text-sm text-gray-600">检测中...</span> |
|
|
</div> |
|
|
<div class="w-full bg-gray-200 rounded-full h-2"> |
|
|
<div id="progressBar" class="bg-blue-500 h-2 rounded-full transition-all duration-300" style="width: 0%"></div> |
|
|
</div> |
|
|
<div class="text-xs text-gray-500 mt-1"> |
|
|
<span id="progressText">准备开始检测...</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="proxyCheckSummary" class="mb-4 hidden"> |
|
|
<div class="grid grid-cols-3 gap-4 text-center"> |
|
|
<div class="bg-green-50 border border-green-200 rounded-lg p-3"> |
|
|
<div class="text-2xl font-bold text-green-600" id="availableCount">0</div> |
|
|
<div class="text-sm text-green-700">可用</div> |
|
|
</div> |
|
|
<div class="bg-red-50 border border-red-200 rounded-lg p-3"> |
|
|
<div class="text-2xl font-bold text-red-600" id="unavailableCount">0</div> |
|
|
<div class="text-sm text-red-700">不可用</div> |
|
|
</div> |
|
|
<div class="bg-blue-50 border border-blue-200 rounded-lg p-3"> |
|
|
<div class="text-2xl font-bold text-blue-600" id="totalCount">0</div> |
|
|
<div class="text-sm text-blue-700">总数</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="proxyCheckResults" class="space-y-2" style="max-height: 400px; overflow-y: auto;"> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div class="flex justify-end gap-3 mt-6"> |
|
|
<button |
|
|
type="button" |
|
|
id="retryFailedProxiesBtn" |
|
|
class="bg-orange-600 hover:bg-orange-700 text-white px-6 py-2 rounded-lg font-medium transition hidden" |
|
|
> |
|
|
重试失败的代理 |
|
|
</button> |
|
|
<button |
|
|
type="button" |
|
|
id="closeProxyCheckBtn" |
|
|
class="bg-gray-500 bg-opacity-50 hover:bg-opacity-70 text-gray-200 px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
关闭 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="modelHelperModal" class="modal"> |
|
|
<div |
|
|
class="w-full max-w-lg mx-auto rounded-2xl shadow-2xl overflow-hidden animate-fade-in" |
|
|
style=" |
|
|
background-color: rgba(255, 255, 255, 0.98); |
|
|
color: #374151; |
|
|
border: 1px solid rgba(0, 0, 0, 0.12); |
|
|
" |
|
|
> |
|
|
<div class="p-6"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h2 id="modelHelperTitle" class="text-xl font-bold text-gray-800"> |
|
|
选择模型 |
|
|
</h2> |
|
|
<button |
|
|
id="closeModelHelperModalBtn" |
|
|
class="text-gray-300 hover:text-gray-800 text-xl" |
|
|
> |
|
|
× |
|
|
</button> |
|
|
</div> |
|
|
<input |
|
|
type="text" |
|
|
id="modelHelperSearchInput" |
|
|
placeholder="搜索模型..." |
|
|
class="w-full px-4 py-3 mb-4 rounded-lg font-mono text-sm form-input-themed" |
|
|
/> |
|
|
<div |
|
|
id="modelHelperListContainer" |
|
|
class="array-container" |
|
|
style="max-height: 300px; overflow-y: auto" |
|
|
> |
|
|
|
|
|
<p class="text-gray-400 text-sm italic">正在加载模型列表...</p> |
|
|
</div> |
|
|
<div class="flex justify-end gap-3 mt-6"> |
|
|
<button |
|
|
type="button" |
|
|
id="cancelModelHelperBtn" |
|
|
class="bg-gray-500 bg-opacity-50 hover:bg-opacity-70 text-gray-200 px-6 py-2 rounded-lg font-medium transition" |
|
|
> |
|
|
关闭 |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
{% endblock %} {% block body_scripts %} |
|
|
<script src="{{ static_url('js/config_editor.js') }}"></script> |
|
|
|
|
|
<script> |
|
|
document.addEventListener("DOMContentLoaded", function () { |
|
|
|
|
|
const selects = document.querySelectorAll(".form-select-themed"); |
|
|
|
|
|
selects.forEach((select) => { |
|
|
|
|
|
select.addEventListener("change", function () { |
|
|
this.classList.add("selected"); |
|
|
|
|
|
this.style.transition = "all 0.2s ease"; |
|
|
this.style.transform = "scale(1.02)"; |
|
|
setTimeout(() => { |
|
|
this.style.transform = "scale(1)"; |
|
|
}, 200); |
|
|
}); |
|
|
|
|
|
|
|
|
select.addEventListener("focus", function () { |
|
|
this.style.boxShadow = "0 0 0 3px rgba(216, 180, 254, 0.5)"; |
|
|
}); |
|
|
|
|
|
|
|
|
if (select.value && select.value !== "") { |
|
|
select.classList.add("selected"); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const logLevelSelect = document.getElementById("LOG_LEVEL"); |
|
|
if (logLevelSelect) { |
|
|
|
|
|
const updateLogLevelStyle = () => { |
|
|
const value = logLevelSelect.value; |
|
|
|
|
|
|
|
|
switch (value) { |
|
|
case "DEBUG": |
|
|
logLevelSelect.style.borderColor = "#3b82f6"; |
|
|
logLevelSelect.style.color = "#374151"; |
|
|
break; |
|
|
case "INFO": |
|
|
logLevelSelect.style.borderColor = "#3b82f6"; |
|
|
logLevelSelect.style.color = "#374151"; |
|
|
break; |
|
|
case "WARNING": |
|
|
logLevelSelect.style.borderColor = "#6b7280"; |
|
|
logLevelSelect.style.color = "#374151"; |
|
|
break; |
|
|
case "ERROR": |
|
|
logLevelSelect.style.borderColor = "#6b7280"; |
|
|
logLevelSelect.style.color = "#374151"; |
|
|
break; |
|
|
case "CRITICAL": |
|
|
logLevelSelect.style.borderColor = "#4b5563"; |
|
|
logLevelSelect.style.color = "#374151"; |
|
|
break; |
|
|
default: |
|
|
logLevelSelect.style.borderColor = "rgba(0, 0, 0, 0.12)"; |
|
|
logLevelSelect.style.color = "#374151"; |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
updateLogLevelStyle(); |
|
|
logLevelSelect.addEventListener("change", updateLogLevelStyle); |
|
|
} |
|
|
|
|
|
|
|
|
const budgetInputs = document.querySelectorAll(".map-value-input"); |
|
|
budgetInputs.forEach((input) => { |
|
|
|
|
|
input.addEventListener("focus", function () { |
|
|
const parentItem = this.closest(".map-item"); |
|
|
if (parentItem) { |
|
|
parentItem.style.backgroundColor = |
|
|
"rgba(243, 244, 246, 1)"; |
|
|
parentItem.style.borderColor = |
|
|
"rgba(59, 130, 246, 0.5)"; |
|
|
} |
|
|
}); |
|
|
|
|
|
input.addEventListener("blur", function () { |
|
|
const parentItem = this.closest(".map-item"); |
|
|
if (parentItem) { |
|
|
parentItem.style.backgroundColor = ""; |
|
|
parentItem.style.borderColor = ""; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
input.addEventListener("input", function () { |
|
|
let val = this.value.replace(/[^0-9]/g, ""); |
|
|
if (val !== "") { |
|
|
val = parseInt(val, 10); |
|
|
if (val > 32767) val = 32767; |
|
|
} |
|
|
this.value = val; |
|
|
|
|
|
|
|
|
this.style.transform = "scale(1.05)"; |
|
|
setTimeout(() => { |
|
|
this.style.transform = "scale(1)"; |
|
|
}, 150); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
</script> |
|
|
{% endblock %} |
|
|
|