2048 lines
80 KiB
HTML
2048 lines
80 KiB
HTML
{% extends "base.html" %} {% block title %}配置编辑器 - Gemini Balance{%endblock %}
|
||
{% block head_extra_styles %}{% 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/icons/logo.png"
|
||
alt="Gemini Balance Logo"
|
||
class="h-9 inline-block align-middle mr-2"
|
||
/>
|
||
Gemini Balance - 系统设置
|
||
</h1>
|
||
|
||
<!-- Navigation Tabs -->
|
||
<div
|
||
class="nav-buttons-container flex justify-center mb-8 overflow-x-auto gap-2"
|
||
>
|
||
<a
|
||
href="/settings"
|
||
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="/dashboard"
|
||
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>
|
||
|
||
<!-- Config Tabs -->
|
||
<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>
|
||
|
||
<!-- Save Status Banner (Removed - using notification component now) -->
|
||
|
||
<!-- Configuration Form -->
|
||
<form id="configForm" class="mt-6">
|
||
<!-- API 相关配置 -->
|
||
<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">
|
||
<div class="flex justify-between items-center mb-2">
|
||
<!-- 左侧标题 -->
|
||
<label class="block font-semibold text-gray-800">
|
||
令牌列表
|
||
</label>
|
||
<!-- [核心新增] 右侧筛选器 -->
|
||
<div class="flex items-center gap-2">
|
||
<select id="tokenTagFilter" class="form-select-themed text-sm py-1 px-2">
|
||
<option value="all">所有标签</option>
|
||
<!-- 标签将动态填充 -->
|
||
</select>
|
||
<select id="tokenGroupFilter" class="form-select-themed text-sm py-1 px-2">
|
||
<option value="all">所有分组</option>
|
||
<!-- 分组将动态填充 -->
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<!-- 令牌列表容器 -->
|
||
<div class="array-container rounded-lg border border-gray-200 bg-gray-50" id="ALLOWED_TOKENS_container">
|
||
<div class="text-gray-400 text-sm italic p-4 text-center">正在加载令牌列表...</div>
|
||
</div>
|
||
<!-- “添加令牌”按钮 -->
|
||
<div class="flex justify-end mt-2">
|
||
<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>
|
||
<small class="text-gray-500 mt-1 block">
|
||
在此处管理所有API认证令牌。点击“齿轮”图标<i class="fas fa-cog mx-1"></i>进行详细配置。
|
||
</small>
|
||
</div>
|
||
|
||
<!-- 认证令牌 -->
|
||
<div class="mb-6">
|
||
<label for="AUTH_TOKEN" class="block font-semibold mb-2 text-gray-800"
|
||
>认证令牌</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>
|
||
<small class="text-gray-500 mt-1 block">用于API认证的令牌</small>
|
||
</div>
|
||
|
||
<!-- =================================================================== -->
|
||
<!-- [核心新增] IP 封禁配置区域 -->
|
||
<!-- =================================================================== -->
|
||
<div class="mb-6">
|
||
<div class="flex items-center justify-between">
|
||
<!-- 左侧:标题与齿轮图标 -->
|
||
<div class="flex items-center">
|
||
<label for="ENABLE_IP_BANNING" class="font-semibold text-gray-700">启用IP封禁功能</label>
|
||
<!-- [核心] 触发配置模态框的齿轮按钮 -->
|
||
<button type="button" id="ipBanSettingsBtn" class="settings-btn ml-3 px-2 py-2 text-gray-400 hover:text-blue-500 focus:outline-none rounded-md hover:bg-gray-100 transition-colors" title="配置IP封禁规则">
|
||
<i class="fas fa-cog"></i>
|
||
</button>
|
||
</div>
|
||
<!-- 右侧:主开关 -->
|
||
<div class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
|
||
<input type="checkbox" name="ENABLE_IP_BANNING" id="ENABLE_IP_BANNING" class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" />
|
||
<label for="ENABLE_IP_BANNING" class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer"></label>
|
||
</div>
|
||
</div>
|
||
<small class="text-gray-500 mt-1 block">
|
||
当一个IP连续多次登录失败后,是否自动将其封禁一段时间。
|
||
</small>
|
||
<!-- [核心新增] 隐藏字段,用于存储IP封禁配置的细节 -->
|
||
<input type="hidden" id="MAX_LOGIN_ATTEMPTS" name="MAX_LOGIN_ATTEMPTS" data-type="number">
|
||
<input type="hidden" id="IP_BAN_DURATION_MINUTES" name="IP_BAN_DURATION_MINUTES" data-type="number">
|
||
</div>
|
||
|
||
<!-- API基础URL -->
|
||
<div class="mb-6">
|
||
<label for="BASE_URL" class="block font-semibold mb-2 text-gray-700"
|
||
>API基础URL</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block">Gemini API的基础URL</small>
|
||
</div>
|
||
|
||
<!-- 自定义Headers -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="CUSTOM_HEADERS"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>自定义Headers</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>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>在这里添加的键值对将被添加到所有出站API请求的Header中。</small
|
||
>
|
||
</div>
|
||
|
||
<!-- 智能路由配置 -->
|
||
<div class="mb-6">
|
||
<div class="flex items-center justify-between">
|
||
<label
|
||
for="URL_NORMALIZATION_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_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>
|
||
<small class="text-gray-500 mt-1 block">
|
||
自动客户端请求的url拼接为正确格式(仅保证正常聊天,出现问题请关闭)
|
||
</small>
|
||
</div>
|
||
<!-- 最大失败次数 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="MAX_FAILURES"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>最大失败次数</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>API密钥失败后标记为无效的次数</small
|
||
>
|
||
</div>
|
||
|
||
<!-- 请求超时时间 -->
|
||
<div class="mb-6">
|
||
<label for="TIME_OUT" class="block font-semibold mb-2 text-gray-700"
|
||
>请求超时时间(秒)</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block">API请求的超时时间</small>
|
||
</div>
|
||
|
||
<!-- 最大重试次数 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="MAX_RETRIES"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>最大重试次数</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>API请求失败后的最大重试次数</small
|
||
>
|
||
</div>
|
||
<!-- 代理服务器列表 -->
|
||
<div class="mb-6">
|
||
<div class="flex items-center justify-between mb-2"> <!-- [改造] 使用 flex 布局包裹 -->
|
||
<!-- 左侧:标题与新齿轮图标 -->
|
||
<div class="flex items-center">
|
||
<label for="PROXIES" class="block font-semibold text-gray-700">代理服务器列表</label>
|
||
<!-- =================================================================== -->
|
||
<!-- [核心新增] 代理高级配置按钮 -->
|
||
<!-- =================================================================== -->
|
||
<button type="button" id="proxySettingsBtn" class="settings-btn ml-3 px-2 py-2 text-gray-400 hover:text-blue-500 focus:outline-none rounded-md hover:bg-gray-100 transition-colors" title="代理高级配置">
|
||
<i class="fas fa-cog"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>代理服务器列表,支持 http 和 socks5 格式,例如:
|
||
http://user:pass@host:port 或
|
||
socks5://host:port。点击按钮可批量添加或删除。</small
|
||
>
|
||
<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>
|
||
<!-- ================================================================ -->
|
||
<!-- [核心新增] 用于暂存代理高级配置的隐藏“数据仓库” -->
|
||
<!-- ================================================================ -->
|
||
<input type="hidden" id="ENABLE_PROXY_CHECK" name="ENABLE_PROXY_CHECK" data-type="boolean">
|
||
<input type="hidden" id="USE_PROXY_HASH" name="USE_PROXY_HASH" data-type="boolean">
|
||
<input type="hidden" id="PROXY_CHECK_TIMEOUT_SECONDS" name="PROXY_CHECK_TIMEOUT_SECONDS" data-type="number">
|
||
<input type="hidden" id="PROXY_CHECK_CONCURRENCY" name="PROXY_CHECK_CONCURRENCY" data-type="number">
|
||
</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"
|
||
>是否开启固定代理策略</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>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>开启后,对于每一个API_KEY将根据算法从代理列表中选取同一个代理IP,防止一个API_KEY同时被多个IP访问,也同时防止了一个IP访问了过多的API_KEY。</small
|
||
>
|
||
</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"
|
||
>测试模型</label
|
||
>
|
||
<div class="flex items-center gap-2">
|
||
<input
|
||
type="text"
|
||
id="TEST_MODEL"
|
||
name="TEST_MODEL"
|
||
placeholder="gemini-2.0-flash-lite"
|
||
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>
|
||
<small class="text-gray-500 mt-1 block">用于测试API密钥的模型</small>
|
||
</div>
|
||
|
||
<!-- 图像模型列表 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="IMAGE_MODELS"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>图像模型列表</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>
|
||
<small class="text-gray-500 mt-1 block">支持图像处理的模型列表</small>
|
||
</div>
|
||
|
||
<!-- 搜索模型列表 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="SEARCH_MODELS"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>搜索模型列表</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>
|
||
<small class="text-gray-500 mt-1 block">支持搜索功能的模型列表</small>
|
||
</div>
|
||
|
||
<!-- 过滤模型列表 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="FILTERED_MODELS"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>过滤模型列表</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>
|
||
<small class="text-gray-500 mt-1 block">需要过滤的模型列表</small>
|
||
</div>
|
||
|
||
<!-- 启用代码执行工具 -->
|
||
<div class="mb-6 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="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"
|
||
>网址上下文模型列表</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>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>支持网址上下文功能的模型列表</small
|
||
>
|
||
</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"
|
||
>思考模型列表</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>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>用于"思考过程"的模型列表</small
|
||
>
|
||
</div>
|
||
|
||
<!-- 思考模型预算映射 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="THINKING_BUDGET_MAP"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>思考模型预算映射</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 class="flex justify-end">
|
||
<button type="button" class="bg-primary-600 hover:bg-primary-700 text-white px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2" id="addBudgetMapItemBtn">
|
||
<i class="fas fa-plus"></i> 添加预算映射
|
||
</button>
|
||
</div> -->
|
||
<small class="text-gray-500 mt-1 block"
|
||
>为每个思考模型设置预算(-1为auto,最大值
|
||
32767),此项与上方模型列表自动关联。</small
|
||
>
|
||
</div>
|
||
<!-- 安全设置 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="SAFETY_SETTINGS"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>安全设置 (Safety Settings)</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>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>配置模型的安全过滤级别,例如 HARM_CATEGORY_HARASSMENT:
|
||
BLOCK_NONE。</small
|
||
>
|
||
<div class="warning-text">
|
||
<i class="fas fa-exclamation-triangle"></i>
|
||
<span
|
||
>建议设置成OFF,其他值会影响输出速度,非必要不要随便改动。</span
|
||
>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- TTS配置 -->
|
||
<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>
|
||
|
||
<!-- TTS 模型 -->
|
||
<div class="mb-6">
|
||
<label for="TTS_MODEL" class="block font-semibold mb-2 text-gray-700"
|
||
>TTS 模型</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>
|
||
<small class="text-gray-500 mt-1 block">用于TTS的模型</small>
|
||
</div>
|
||
|
||
<!-- TTS 语音名称 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="TTS_VOICE_NAME"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>TTS 语音名称</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>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>TTS 的语音名称,控制风格、语调、口音和节奏</small
|
||
>
|
||
</div>
|
||
|
||
<!-- TTS 语速 -->
|
||
<div class="mb-6">
|
||
<label for="TTS_SPEED" class="block font-semibold mb-2 text-gray-700"
|
||
>TTS 语速</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>
|
||
<small class="text-gray-500 mt-1 block">选择 TTS 的语速</small>
|
||
</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>
|
||
|
||
<!-- 付费API密钥 -->
|
||
<div class="mb-6">
|
||
<label for="PAID_KEY" class="block font-semibold mb-2 text-gray-700"
|
||
>付费API密钥</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>用于图像生成的付费API密钥</small
|
||
>
|
||
</div>
|
||
|
||
<!-- 图像生成模型 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="CREATE_IMAGE_MODEL"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>图像生成模型</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>
|
||
<small class="text-gray-500 mt-1 block">用于图像生成的模型</small>
|
||
</div>
|
||
|
||
<!-- 上传提供商 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="UPLOAD_PROVIDER"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>上传提供商</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>
|
||
</select>
|
||
<small class="text-gray-500 mt-1 block">图片上传服务提供商</small>
|
||
</div>
|
||
|
||
<!-- SM.MS密钥 -->
|
||
<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密钥</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block">SM.MS图床的密钥</small>
|
||
</div>
|
||
|
||
<!-- PicGo API密钥 -->
|
||
<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密钥</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block">PicGo的API密钥</small>
|
||
</div>
|
||
|
||
<!-- Cloudflare图床URL -->
|
||
<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</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block">Cloudflare图床的URL</small>
|
||
</div>
|
||
|
||
<!-- Cloudflare认证码 -->
|
||
<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认证码</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block">Cloudflare图床的认证码</small>
|
||
</div>
|
||
|
||
<!-- Cloudflare上传文件夹 -->
|
||
<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上传文件夹</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>Cloudflare图床的上传文件夹路径(可选)</small
|
||
>
|
||
</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 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="mb-6">
|
||
<label
|
||
for="STREAM_MIN_DELAY"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>最小延迟(秒)</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block">流式输出的最小延迟时间</small>
|
||
</div>
|
||
|
||
<!-- 最大延迟 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="STREAM_MAX_DELAY"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>最大延迟(秒)</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block">流式输出的最大延迟时间</small>
|
||
</div>
|
||
|
||
<!-- 短文本阈值 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="STREAM_SHORT_TEXT_THRESHOLD"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>短文本阈值</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block">短文本的字符阈值</small>
|
||
</div>
|
||
|
||
<!-- 长文本阈值 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="STREAM_LONG_TEXT_THRESHOLD"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>长文本阈值</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block">长文本的字符阈值</small>
|
||
</div>
|
||
|
||
<!-- 分块大小 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="STREAM_CHUNK_SIZE"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>分块大小</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block">流式输出的分块大小</small>
|
||
</div>
|
||
|
||
<!-- Fake Streaming Configuration -->
|
||
<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"
|
||
>启用假流式输出</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>
|
||
<small class="text-gray-500 mt-1 block mb-4"
|
||
>当启用时,将调用非流式接口,并在等待响应期间发送空数据以维持连接。</small
|
||
>
|
||
|
||
<!-- 假流式发送空数据的间隔时间 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="FAKE_STREAM_EMPTY_DATA_INTERVAL_SECONDS"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>假流式空数据发送间隔(秒)</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"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>在启用假流式输出时,向客户端发送空数据以维持连接状态的时间间隔(建议
|
||
3-10 秒)。</small
|
||
>
|
||
</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"
|
||
>检查间隔(小时)</label
|
||
>
|
||
<input
|
||
type="number"
|
||
id="CHECK_INTERVAL_HOURS"
|
||
name="CHECK_INTERVAL_HOURS"
|
||
min="1"
|
||
class="w-full px-4 py-3 rounded-lg form-input-themed"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>定时检查密钥状态的间隔时间(单位:小时)</small
|
||
>
|
||
</div>
|
||
|
||
<!-- 时区 -->
|
||
<div class="mb-6">
|
||
<label for="TIMEZONE" class="block font-semibold mb-2 text-gray-700"
|
||
>时区</label
|
||
>
|
||
<input
|
||
type="text"
|
||
id="TIMEZONE"
|
||
name="TIMEZONE"
|
||
placeholder="例如: Asia/Shanghai"
|
||
class="w-full px-4 py-3 rounded-lg form-input-themed"
|
||
/>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>定时任务使用的时区,格式如 "Asia/Shanghai" 或 "UTC"</small
|
||
>
|
||
</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"
|
||
>日志级别</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>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>设置应用程序的日志记录详细程度</small
|
||
>
|
||
</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"
|
||
>是否开启自动删除错误日志</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>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>开启后,将自动删除指定天数前的错误日志。</small
|
||
>
|
||
</div>
|
||
|
||
<!-- 自动删除日志天数 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="AUTO_DELETE_ERROR_LOGS_DAYS"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>自动删除多少天前的错误日志</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>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>选择自动删除错误日志的天数。</small
|
||
>
|
||
</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"
|
||
>是否开启自动删除请求日志</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>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>开启后,将自动删除指定天数前的请求日志。</small
|
||
>
|
||
</div>
|
||
|
||
<!-- 自动删除请求日志天数 -->
|
||
<div class="mb-6">
|
||
<label
|
||
for="AUTO_DELETE_REQUEST_LOGS_DAYS"
|
||
class="block font-semibold mb-2 text-gray-700"
|
||
>自动删除多少天前的请求日志</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>
|
||
<small class="text-gray-500 mt-1 block"
|
||
>选择自动删除请求日志的天数。</small
|
||
>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Action Buttons -->
|
||
<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>
|
||
|
||
<!-- Scroll buttons are now in base.html -->
|
||
<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>
|
||
|
||
<!-- Notification component is now in base.html -->
|
||
<div id="notification" class="notification"></div>
|
||
<!-- Footer is now in base.html -->
|
||
|
||
<!-- [核心新增] 认证令牌配置模态框 (Token Settings Modal) -->
|
||
<div id="tokenSettingsModal" class="modal">
|
||
<div class="w-full max-w-2xl 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-6 pb-3 border-b border-gray-200">
|
||
<h2 class="text-xl font-bold text-gray-800">配置认证令牌</h2>
|
||
<button id="closeTokenSettingsModalBtn" class="text-gray-400 hover:text-gray-800 text-2xl">×</button>
|
||
</div>
|
||
<!-- 表单内容 -->
|
||
<div class="space-y-5">
|
||
|
||
<!-- 令牌字段 -->
|
||
<div>
|
||
<label for="tokenSettingsTokenInput" class="block text-sm font-medium text-gray-700 mb-1">令牌 (Token)</label>
|
||
<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="tokenSettingsTokenInput" placeholder="点击右侧按钮生成"
|
||
class="array-input flex-grow px-3 py-2 rounded-l-md form-input-themed sensitive-input">
|
||
<button type="button" id="tokenSettingsGenerateBtn"
|
||
class="generate-btn px-3 py-2 text-gray-500 hover:text-blue-500 focus:outline-none rounded-r-md bg-gray-100 hover:bg-gray-200 transition-colors"
|
||
title="生成随机令牌">
|
||
<i class="fas fa-dice"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<!-- 描述字段 -->
|
||
<div>
|
||
<label for="tokenSettingsDescriptionInput" class="block text-sm font-medium text-gray-700 mb-1">描述 (Description)</label>
|
||
<input type="text" id="tokenSettingsDescriptionInput" placeholder="例如:用于XX项目的用户令牌"
|
||
class="w-full px-3 py-2 rounded-md form-input-themed">
|
||
</div>
|
||
|
||
<!-- 标签字段 -->
|
||
<div>
|
||
<label for="tokenSettingsTagInput" class="block text-sm font-medium text-gray-700 mb-1">分类标签 (Tag)</label>
|
||
<input type="text" id="tokenSettingsTagInput" placeholder="例如:user, test, high-priority"
|
||
class="w-full px-3 py-2 rounded-md form-input-themed">
|
||
</div>
|
||
<!-- 状态开关 -->
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-1">状态 (Status)</label>
|
||
<label for="tokenSettingsStatusToggle" class="flex items-center cursor-pointer">
|
||
<div class="relative">
|
||
<input type="checkbox" id="tokenSettingsStatusToggle" class="sr-only">
|
||
<div class="block bg-gray-300 w-14 h-8 rounded-full"></div>
|
||
<div class="dot absolute left-1 top-1 bg-white w-6 h-6 rounded-full transition"></div>
|
||
</div>
|
||
<div id="tokenSettingsStatusText" class="ml-3 text-gray-700 font-medium">Active</div>
|
||
</label>
|
||
</div>
|
||
<!-- 授权分组 -->
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-2">授权分组 (Allowed Groups)</label>
|
||
<div class="flex items-center gap-2 mb-3">
|
||
<button type="button" id="tokenSettingsSelectAllGroupsBtn" class="text-xs px-3 py-1 bg-gray-200 hover:bg-gray-300 rounded-full">全选</button>
|
||
<button type="button" id="tokenSettingsDeselectAllGroupsBtn" class="text-xs px-3 py-1 bg-gray-200 hover:bg-gray-300 rounded-full">全不选</button>
|
||
</div>
|
||
<div id="tokenSettingsGroupsContainer" class="p-3 border rounded-lg bg-gray-50 max-h-40 overflow-y-auto flex flex-wrap gap-2">
|
||
<!-- 分组复选框将在这里动态生成 -->
|
||
<span class="text-gray-400 text-sm italic">正在加载分组列表...</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- 操作按钮 -->
|
||
<div class="flex justify-end gap-3 mt-8">
|
||
<button type="button" id="confirmTokenSettingsBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg font-medium transition">
|
||
确认
|
||
</button>
|
||
<button type="button" id="cancelTokenSettingsBtn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-6 py-2 rounded-lg font-medium transition">
|
||
取消
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- 为状态开关添加一些基本样式 -->
|
||
<style>
|
||
#tokenSettingsStatusToggle:checked ~ .dot {
|
||
transform: translateX(100%);
|
||
background-color: #4A90E2; /* Blue */
|
||
}
|
||
#tokenSettingsStatusToggle:checked ~ .block {
|
||
background-color: #C7D2FE; /* Light blue */
|
||
}
|
||
</style>
|
||
|
||
|
||
<!-- =================================================================== -->
|
||
<!-- [核心新增] IP 封禁配置模态框 (IP Ban Settings Modal) -->
|
||
<!-- =================================================================== -->
|
||
<div id="ipBanSettingsModal" 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-6 pb-3 border-b border-gray-200">
|
||
<h2 class="text-xl font-bold text-gray-800">配置IP封禁规则</h2>
|
||
<button id="closeIpBanSettingsModalBtn" class="text-gray-400 hover:text-gray-800 text-2xl">×</button>
|
||
</div>
|
||
|
||
<!-- 表单内容 -->
|
||
<div class="space-y-5">
|
||
<!-- 最大登录失败次数 -->
|
||
<div>
|
||
<label for="ipBanMaxAttemptsInput" class="block text-sm font-medium text-gray-700 mb-1">最大登录失败次数</label>
|
||
<input type="number" id="ipBanMaxAttemptsInput" placeholder="5" min="1" class="w-full px-3 py-2 rounded-md form-input-themed">
|
||
<small class="text-gray-500 mt-1 block">在一个IP被封禁前,允许的连续登录失败次数。</small>
|
||
</div>
|
||
|
||
<!-- IP封禁时长 -->
|
||
<div>
|
||
<label for="ipBanDurationInput" class="block text-sm font-medium text-gray-700 mb-1">IP封禁时长 (分钟)</label>
|
||
<input type="number" id="ipBanDurationInput" placeholder="15" min="1" class="w-full px-3 py-2 rounded-md form-input-themed">
|
||
<small class="text-gray-500 mt-1 block">IP被封禁的时长,单位为分钟。</small>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 操作按钮 -->
|
||
<div class="flex justify-end gap-3 mt-8">
|
||
<button type="button" id="confirmIpBanSettingsBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg font-medium transition">
|
||
确认
|
||
</button>
|
||
<button type="button" id="cancelIpBanSettingsBtn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-6 py-2 rounded-lg font-medium transition">
|
||
取消
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<!-- Proxy Add Modal -->
|
||
<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>
|
||
|
||
<!-- Bulk Delete Proxy Modal -->
|
||
<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>
|
||
|
||
<!-- Reset Confirmation Modal -->
|
||
<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>
|
||
|
||
|
||
|
||
<!-- Proxy Check Results Modal -->
|
||
<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>
|
||
|
||
<!-- =================================================================== -->
|
||
<!-- [核心新增] 代理高级配置模态框 (Proxy Settings Modal) -->
|
||
<!-- =================================================================== -->
|
||
<div id="proxySettingsModal" 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-6 pb-3 border-b border-gray-200">
|
||
<h2 class="text-xl font-bold text-gray-800">代理高级配置</h2>
|
||
<button id="closeProxySettingsModalBtn" class="text-gray-400 hover:text-gray-800 text-2xl">×</button>
|
||
</div>
|
||
|
||
<!-- 表单内容 -->
|
||
<div class="space-y-6">
|
||
<!-- 启用代理健康检查 -->
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<label for="enableProxyCheckInput" class="font-medium text-gray-700">启用后台健康检查</label>
|
||
<small class="text-gray-500 mt-1 block text-sm">是否启用后台自动健康检查,提前发现并禁用失效的代理。</small>
|
||
</div>
|
||
<div class="relative inline-block w-10 align-middle select-none transition duration-200 ease-in">
|
||
<input type="checkbox" id="enableProxyCheckInput" class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" />
|
||
<label for="enableProxyCheckInput" class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer"></label>
|
||
</div>
|
||
</div>
|
||
<!-- 启用固定代理策略 -->
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<label for="useProxyHashInput" class="font-medium text-gray-700">启用固定代理策略</label>
|
||
<small class="text-gray-500 mt-1 block text-sm">为每个API Key分配固定的代理,防止多IP访问同一Key。</small>
|
||
</div>
|
||
<div class="relative inline-block w-10 align-middle select-none transition duration-200 ease-in">
|
||
<input type="checkbox" id="useProxyHashInput" class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer" />
|
||
<label for="useProxyHashInput" class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer"></label>
|
||
</div>
|
||
</div>
|
||
<!-- 代理检查超时 -->
|
||
<div>
|
||
<label for="proxyCheckTimeoutInput" class="block text-sm font-medium text-gray-700 mb-1">代理检查超时 (秒)</label>
|
||
<input type="number" id="proxyCheckTimeoutInput" placeholder="例如:20" min="1" class="w-full px-3 py-2 rounded-md form-input-themed">
|
||
<small class="text-gray-500 mt-1 block">对单个代理进行连通性测试时的网络超时时间。</small>
|
||
</div>
|
||
<!-- 代理测试并发数 -->
|
||
<div>
|
||
<label for="proxyCheckConcurrencyInput" class="block text-sm font-medium text-gray-700 mb-1">代理测试并发数</label>
|
||
<input type="number" id="proxyCheckConcurrencyInput" placeholder="例如:5" min="1" class="w-full px-3 py-2 rounded-md form-input-themed">
|
||
<small class="text-gray-500 mt-1 block">手动批量测试代理时的并发请求数量。</small>
|
||
</div>
|
||
</div>
|
||
<!-- 操作按钮 -->
|
||
<div class="flex justify-end gap-3 mt-8">
|
||
<button type="button" id="confirmProxySettingsBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg font-medium transition">
|
||
确认
|
||
</button>
|
||
<button type="button" id="cancelProxySettingsBtn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-6 py-2 rounded-lg font-medium transition">
|
||
取消
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Model Helper Modal -->
|
||
<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"
|
||
>
|
||
<!-- Model items will be populated here -->
|
||
<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/js/settings.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"; // blue-500 主题色
|
||
logLevelSelect.style.color = "#374151"; // gray-700 深灰文字
|
||
break;
|
||
case "INFO":
|
||
logLevelSelect.style.borderColor = "#3b82f6"; // blue-500 主题色
|
||
logLevelSelect.style.color = "#374151"; // gray-700 深灰文字
|
||
break;
|
||
case "WARNING":
|
||
logLevelSelect.style.borderColor = "#6b7280"; // gray-500 中性灰
|
||
logLevelSelect.style.color = "#374151"; // gray-700 深灰文字
|
||
break;
|
||
case "ERROR":
|
||
logLevelSelect.style.borderColor = "#6b7280"; // gray-500 中性灰
|
||
logLevelSelect.style.color = "#374151"; // gray-700 深灰文字
|
||
break;
|
||
case "CRITICAL":
|
||
logLevelSelect.style.borderColor = "#4b5563"; // gray-600 稍深灰
|
||
logLevelSelect.style.color = "#374151"; // gray-700 深灰文字
|
||
break;
|
||
default:
|
||
logLevelSelect.style.borderColor = "rgba(0, 0, 0, 0.12)"; // 默认边框
|
||
logLevelSelect.style.color = "#374151"; // gray-700 深灰文字
|
||
}
|
||
};
|
||
|
||
// 初始化和变更时更新样式
|
||
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)"; /* gray-100 */
|
||
parentItem.style.borderColor =
|
||
"rgba(59, 130, 246, 0.5)"; /* blue-500 */
|
||
}
|
||
});
|
||
|
||
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 %} |