""" 模板生成模块 此模块包含 HTML 页面生成函数,用于管理界面和日志查看器 注意: - 这些函数需要通过 import main 动态获取全局变量 - 避免在模块顶层导入 main,防止循环依赖 """ from fastapi import Request, Header, HTTPException from fastapi.responses import HTMLResponse def generate_admin_html(request: Request, multi_account_mgr, show_hide_tip: bool = False) -> str: """生成管理页面HTML - 端点带Key参数完整版""" # 动态导入 main 模块的变量(避免循环依赖) import main # 获取当前页面的完整URL current_url = main.get_base_url(request) # 获取错误统计 error_count = 0 with main.log_lock: for log in main.log_buffer: if log.get("level") in ["ERROR", "CRITICAL"]: error_count += 1 # --- 1. 构建提示信息 --- hide_tip = "" if show_hide_tip: hide_tip = """
💡
提示:此页面默认在首页显示。如需隐藏,请设置环境变量:
main.HIDE_HOME_PAGE=true
""" api_key_status = "" if main.API_KEY: api_key_status = """
🔒
安全模式已启用
请求 Header 需携带 Authorization 密钥。
""" else: api_key_status = """
⚠️
API Key 未设置
API 当前允许公开访问,建议配置 main.API_KEY。
""" error_alert = "" if error_count > 0: error_alert = f"""
🚨
检测到 {error_count} 条错误日志 查看详情 →
""" # API接口信息提示 api_endpoint = f"{current_url}/{main.PATH_PREFIX}/v1/chat/completions" api_key_display = main.API_KEY if main.API_KEY else '未设置(公开访问)' api_info_tip = f"""
🔗
API 接口信息
聊天接口
{api_endpoint}
API 密钥
{api_key_display}
支持的模型
gemini-auto gemini-2.5-flash gemini-2.5-pro gemini-3-flash-preview gemini-3-pro-preview
📸 图片生成说明
• 仅 gemini-3-pro-preview 支持绘图
• 存储路径:./images
• 存储类型:临时(服务重启后丢失)
""" # --- 2. 构建账户卡片 --- accounts_html = "" for account_id, account_manager in multi_account_mgr.accounts.items(): config = account_manager.config remaining_hours = config.get_remaining_hours() expire_status_text, _, expire_display = main.format_account_expiration(remaining_hours) # 检查账户是否过期或被手动禁用 is_expired = config.is_expired() is_disabled = config.disabled # 使用AccountManager的方法获取冷却信息 cooldown_seconds, cooldown_reason = account_manager.get_cooldown_info() # 确定账户状态和颜色 if is_expired: status_text = "过期禁用" status_color = "#9e9e9e" dot_color = "#9e9e9e" card_opacity = "0.5" action_buttons = f'' elif is_disabled: status_text = "手动禁用" status_color = "#9e9e9e" dot_color = "#9e9e9e" card_opacity = "0.5" action_buttons = f''' ''' elif cooldown_seconds == -1: # 错误永久禁用 status_text = cooldown_reason # "错误禁用" status_color = "#f44336" dot_color = "#f44336" card_opacity = "0.5" action_buttons = f''' ''' elif cooldown_seconds > 0: # 429限流(冷却中) status_text = cooldown_reason # "429限流" status_color = "#ff9800" dot_color = "#ff9800" card_opacity = "1" action_buttons = f''' ''' else: # 正常状态 is_avail = account_manager.is_available if is_avail: status_text = expire_status_text # "正常", "即将过期", "紧急" if expire_status_text == "正常": status_color = "#4caf50" dot_color = "#34c759" elif expire_status_text == "即将过期": status_color = "#ff9800" dot_color = "#ff9800" else: # 紧急 status_color = "#f44336" dot_color = "#f44336" else: status_text = "不可用" status_color = "#f44336" dot_color = "#ff3b30" card_opacity = "1" action_buttons = f''' ''' # 构建卡片内容 accounts_html += f"""
{config.account_id}
{status_text}
{action_buttons}
过期时间 {config.expires_at or '未设置'}
剩余时长 {expire_display}
累计对话 {account_manager.conversation_count} 次
{'
冷却倒计时' + str(cooldown_seconds) + '秒 (' + cooldown_reason + ')
' if cooldown_seconds > 0 else ''}
""" # --- 3. 构建 HTML --- html_content = f""" 系统管理 - Gemini Business API

Gemini-Business2api

多账户代理面板
📄 公开日志 🔧 管理日志
{hide_tip} {api_key_status} {error_alert} {api_info_tip}
账户状态 ({len(multi_account_mgr.accounts)} 个)
过期时间为12小时,可以自行修改时间,脚本可能有误差。
环境变量配置

必需变量 REQUIRED

ACCOUNTS_CONFIG
JSON格式账户列表
PATH_PREFIX
API路径前缀
当前: {main.PATH_PREFIX}
ADMIN_KEY
管理员密钥
已设置

重试配置 OPTIONAL

MAX_NEW_SESSION_TRIES
新会话尝试账户数
{main.MAX_NEW_SESSION_TRIES}
MAX_REQUEST_RETRIES
请求失败重试次数
{main.MAX_REQUEST_RETRIES}
MAX_ACCOUNT_SWITCH_TRIES
每次重试查找账户次数
{main.MAX_ACCOUNT_SWITCH_TRIES}
ACCOUNT_FAILURE_THRESHOLD
账户失败阈值
{main.ACCOUNT_FAILURE_THRESHOLD} 次
RATE_LIMIT_COOLDOWN_SECONDS
429限流冷却时间
{main.RATE_LIMIT_COOLDOWN_SECONDS} 秒

可选变量 OPTIONAL

API_KEY
API访问密钥
{'已设置' if main.API_KEY else '未设置'}
BASE_URL
图片URL生成(推荐设置)
{'已设置' if main.BASE_URL else '未设置(自动检测)'}
PROXY
代理地址
{'已设置' if main.PROXY else '未设置'}
SESSION_CACHE_TTL_SECONDS
会话缓存过期时间
{main.SESSION_CACHE_TTL_SECONDS} 秒
LOGO_URL
Logo URL(公开,为空则不显示)
{'已设置' if main.LOGO_URL else '未设置'}
CHAT_URL
开始对话链接(公开,为空则不显示)
{'已设置' if main.CHAT_URL else '未设置'}
MODEL_NAME
模型名称(公开)
{main.MODEL_NAME}
HIDE_HOME_PAGE
隐藏首页管理面板
{'已隐藏' if main.HIDE_HOME_PAGE else '未隐藏'}
服务信息

支持的模型

gemini-auto gemini-2.5-flash gemini-2.5-pro gemini-3-flash-preview gemini-3-pro-preview
📸 图片生成说明
gemini-3-pro-preview 支持绘图。
路径: {main.IMAGE_DIR}
类型: {'持久化(重启保留)' if main.IMAGE_DIR == '/data/images' else '临时(重启丢失)'}

API 端点

当前页面: {current_url}
POST /{main.PATH_PREFIX}/v1/chat/completions OpenAI 兼容对话接口
GET /{main.PATH_PREFIX}/v1/models 获取模型列表
GET /{main.PATH_PREFIX}/admin 管理首页
GET /{main.PATH_PREFIX}/admin/health?key={{main.ADMIN_KEY}} 健康检查 (需 Key)
GET /{main.PATH_PREFIX}/admin/accounts?key={{main.ADMIN_KEY}} 账户状态 JSON (需 Key)
GET /{main.PATH_PREFIX}/admin/log?key={{main.ADMIN_KEY}} 获取日志 JSON (需 Key)
GET /{main.PATH_PREFIX}/admin/log/html?key={{main.ADMIN_KEY}} 日志查看器 HTML (需 Key)
DEL /{main.PATH_PREFIX}/admin/log?confirm=yes&key={{main.ADMIN_KEY}} 清空系统日志 (需 Key)
GET /public/stats 公开统计数据
GET /public/log 公开日志 (JSON, 脱敏)
GET /public/log/html 公开日志查看器 (HTML)
GET /docs Swagger API 文档
GET /redoc ReDoc API 文档
""" return html_content async def admin_logs_html(path_prefix: str, key: str = None, authorization: str = Header(None)): """返回美化的 HTML 日志查看界面""" # 动态导入 main 模块的变量(避免循环依赖) import main # 验证路径前缀 if path_prefix != main.PATH_PREFIX: raise HTTPException(404, "Not Found") # 验证管理员密钥 admin_key = key or (authorization.replace("Bearer ", "") if authorization and authorization.startswith("Bearer ") else authorization) if admin_key != main.ADMIN_KEY: raise HTTPException(404, "Not Found") html_content = r""" 日志查看器

Gemini API 日志查看器

总数
-
对话
-
INFO
-
WARNING
-
ERROR
-
更新
-
正在加载...
""" return HTMLResponse(content=html_content) async def get_public_logs_html(): """公开的脱敏日志查看器""" # 动态导入 main 模块的变量(避免循环依赖) import main html_content = r""" 服务状态

""" + (f'Logo' if main.LOGO_URL else '') + r""" Gemini服务状态

展示最近1000条对话日志 · 每5秒自动更新 """ + (f'开始对话' if main.CHAT_URL else '开始对话') + r"""
总访问
0
每分钟请求
0
平均响应
-
成功率
-
对话次数
0
成功
0
失败
0
更新时间
--:--
加载中...
""" return HTMLResponse(content=html_content)