zai / app /templates /config.html
sanbo110's picture
update sth at 2026-01-15 15:33:59
f78578c
{% extends "base.html" %}
{% block title %}配置管理{% endblock %}
{% block content %}
<div class="space-y-6" x-data="{
showAdvanced: false,
tokenCount: 1,
saveStatus: ''
}">
<!-- 页面标题 -->
<div class="flex items-center justify-between">
<h2 class="text-3xl font-bold text-gray-900">配置管理</h2>
<button
@click="showAdvanced = !showAdvanced"
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md text-sm font-medium">
<span x-text="showAdvanced ? '隐藏高级选项' : '显示高级选项'"></span>
</button>
</div>
<!-- 基础配置 -->
<div class="bg-white shadow rounded-lg">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-medium text-gray-900">基础配置</h3>
</div>
<form hx-post="/admin/api/config/save"
hx-target="#save-notification"
hx-swap="innerHTML"
class="p-6 space-y-6">
<!-- 服务名称 -->
<div>
<label class="block text-sm font-medium text-gray-700">服务名称</label>
<input type="text"
name="service_name"
value="{{ config.SERVICE_NAME or 'Z.AI2API' }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
<p class="mt-1 text-sm text-gray-500">显示在进程列表中的服务名称</p>
</div>
<!-- 监听端口 -->
<div>
<label class="block text-sm font-medium text-gray-700">监听端口</label>
<input type="number"
name="listen_port"
value="{{ config.LISTEN_PORT or 7860 }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
<p class="mt-1 text-sm text-gray-500">服务监听的端口号</p>
</div>
<!-- 调试模式 -->
<div class="flex items-center">
<input type="checkbox"
name="debug_logging"
{{ 'checked' if config.DEBUG_LOGGING else '' }}
class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500">
<label class="ml-2 block text-sm text-gray-900">启用调试日志</label>
</div>
<!-- 匿名模式 -->
<div class="flex items-center">
<input type="checkbox"
name="anonymous_mode"
{{ 'checked' if config.ANONYMOUS_MODE else '' }}
class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500">
<label class="ml-2 block text-sm text-gray-900">启用匿名模式(自动获取临时 Token)</label>
</div>
<!-- 认证配置 -->
<div>
<label class="block text-sm font-medium text-gray-700">客户端认证密钥</label>
<input type="text"
name="auth_token"
value="{{ config.AUTH_TOKEN or 'sk-your-api-key' }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
<p class="mt-1 text-sm text-gray-500">客户端访问本服务时使用的 API 密钥</p>
</div>
<!-- 跳过认证 -->
<div class="flex items-center">
<input type="checkbox"
name="skip_auth_token"
{{ 'checked' if config.SKIP_AUTH_TOKEN else '' }}
class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500">
<label class="ml-2 block text-sm text-gray-900">跳过客户端认证(仅开发环境)</label>
</div>
<!-- 工具调用支持 -->
<div class="flex items-center">
<input type="checkbox"
name="tool_support"
{{ 'checked' if config.TOOL_SUPPORT else '' }}
class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500">
<label class="ml-2 block text-sm text-gray-900">启用 Function Call(工具调用)功能</label>
</div>
<!-- 高级选项 -->
<div x-show="showAdvanced" x-transition class="border-t pt-6 space-y-6">
<h4 class="text-md font-medium text-gray-900">高级选项</h4>
<!-- Token 失败阈值 -->
<div>
<label class="block text-sm font-medium text-gray-700">Token 失败阈值</label>
<input type="number"
name="token_failure_threshold"
value="{{ config.TOKEN_FAILURE_THRESHOLD or 3 }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
<p class="mt-1 text-sm text-gray-500">连续失败多少次后标记 Token 为失败状态</p>
</div>
<!-- Token 恢复超时 -->
<div>
<label class="block text-sm font-medium text-gray-700">Token 恢复超时(秒)</label>
<input type="number"
name="token_recovery_timeout"
value="{{ config.TOKEN_RECOVERY_TIMEOUT or 1800 }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
<p class="mt-1 text-sm text-gray-500">Token 失败后多久自动恢复(默认 1800 秒 / 30 分钟)</p>
</div>
<!-- 工具调用扫描限制 -->
<div>
<label class="block text-sm font-medium text-gray-700">工具调用扫描限制(字符数)</label>
<input type="number"
name="scan_limit"
value="{{ config.SCAN_LIMIT or 200000 }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
<p class="mt-1 text-sm text-gray-500">Function Call 功能扫描的最大字符数</p>
</div>
<!-- LongCat Token -->
<div>
<label class="block text-sm font-medium text-gray-700">LongCat Passport Token</label>
<input type="text"
name="longcat_token"
value="{{ config.LONGCAT_TOKEN or '' }}"
placeholder="可选,用于 LongCat 提供商"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
<p class="mt-1 text-sm text-gray-500">LongCat 提供商的 passport token(可选)</p>
</div>
<!-- 默认提供商 -->
<div>
<label class="block text-sm font-medium text-gray-700">默认提供商</label>
<select name="default_provider"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
<option value="zai" {{ 'selected' if config.DEFAULT_PROVIDER == 'zai' else '' }}>Z.AI</option>
<option value="k2think" {{ 'selected' if config.DEFAULT_PROVIDER == 'k2think' else '' }}>K2Think</option>
<option value="longcat" {{ 'selected' if config.DEFAULT_PROVIDER == 'longcat' else '' }}>LongCat</option>
</select>
</div>
</div>
<!-- 保存按钮 -->
<div class="flex items-center justify-between pt-6 border-t">
<div id="save-notification" class="flex-1"></div>
<div class="flex space-x-3">
<button type="button"
hx-get="/admin/config/reset"
hx-confirm="确定要重置所有配置吗?"
class="px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50">
重置
</button>
<button type="submit"
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
💾 保存并重载
</button>
</div>
</div>
<!-- 配置说明 -->
<div class="mt-4 bg-blue-50 border-l-4 border-blue-400 p-4">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd" />
</svg>
</div>
<div class="ml-3">
<p class="text-sm text-blue-700">
<strong>提示:</strong>配置保存后会自动热重载,大部分配置无需重启服务即可生效。<br>
<code class="bg-blue-100 px-1 py-0.5 rounded">监听端口</code><code class="bg-blue-100 px-1 py-0.5 rounded">服务名称</code> 需要手动重启服务。
</p>
</div>
</div>
</div>
</form>
</div>
<!-- 配置文件预览 -->
<div class="bg-white shadow rounded-lg">
<div class="px-6 py-4 border-b border-gray-200 flex items-center justify-between">
<h3 class="text-lg font-medium text-gray-900">.env 文件预览</h3>
<button
hx-get="/admin/api/env-preview"
hx-target="#env-preview"
class="text-sm text-indigo-600 hover:text-indigo-700">
刷新
</button>
</div>
<div class="p-6">
<div id="env-preview" class="bg-gray-50 rounded-md p-4 font-mono text-sm overflow-x-auto">
<pre>{{ env_content or '加载中...' }}</pre>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_scripts %}
<script>
// 配置保存成功后的处理
document.body.addEventListener('htmx:afterSwap', function(evt) {
if (evt.detail.target.id === 'save-notification') {
// 3秒后自动隐藏通知
setTimeout(() => {
evt.detail.target.innerHTML = '';
}, 3000);
}
});
</script>
{% endblock %}