feat: 隐藏后台面板 + /api/stats 运行统计
- 连点页脚提示 6 次唤出管理面板:本机偏好/播放状态 + 服务器统计 - server.py 新增 GET /api/stats:运行时长、访客 IP(X-Forwarded-For 末位取真实 IP 防伪造)、TTS 请求与缓存命中率、缓存体积、经典数 - 计数为进程内存统计,重启清零 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
||||
@@ -39,6 +40,10 @@ PORT = int(os.environ.get("PORT", "8000"))
|
||||
|
||||
GENERATION_URL = f"{DASHSCOPE_BASE}/services/aigc/multimodal-generation/generation"
|
||||
|
||||
# 运行期统计:进程内存内计数,重启清零
|
||||
STATS = {"start": time.time(), "tts_requests": 0, "cache_hits": 0}
|
||||
VISITORS = set() # 见过的客户端 IP(本次进程生命周期内)
|
||||
|
||||
|
||||
def http_post_json(url: str, payload: dict, headers: dict, timeout: int = 60) -> dict:
|
||||
"""发送 JSON POST 请求并返回解析后的响应。"""
|
||||
@@ -72,8 +77,29 @@ class Handler(SimpleHTTPRequestHandler):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, directory=str(BASE_DIR), **kwargs)
|
||||
|
||||
def _track_visitor(self) -> None:
|
||||
"""记录客户端 IP 到访客集合;nginx 反代后真实来源在 X-Forwarded-For / X-Real-IP。"""
|
||||
# nginx 把真实 IP 追加在 X-Forwarded-For 末尾,取最后一个元素防伪造
|
||||
xff = (self.headers.get("X-Forwarded-For") or "").split(",")[-1].strip()
|
||||
ip = xff or (self.headers.get("X-Real-IP") or "").strip() or self.client_address[0]
|
||||
VISITORS.add(ip)
|
||||
|
||||
def do_GET(self) -> None:
|
||||
"""处理 GET 请求:/api/sutras 返回经典目录清单,其余按静态文件处理。"""
|
||||
"""处理 GET 请求:/api/* 接口,其余按静态文件处理。"""
|
||||
self._track_visitor()
|
||||
if self.path == "/api/stats":
|
||||
cache_files = list(CACHE_DIR.glob("*.wav")) if CACHE_DIR.is_dir() else []
|
||||
self._send_json({
|
||||
"uptime_sec": int(time.time() - STATS["start"]),
|
||||
"tts_requests": STATS["tts_requests"],
|
||||
"cache_hits": STATS["cache_hits"],
|
||||
"cache_files": len(cache_files),
|
||||
"cache_bytes": sum(f.stat().st_size for f in cache_files),
|
||||
"sutra_count": len(list(SUTRA_DIR.glob("*.json"))) if SUTRA_DIR.is_dir() else 0,
|
||||
"visitors": len(VISITORS),
|
||||
"model": TTS_MODEL,
|
||||
})
|
||||
return
|
||||
if self.path == "/api/sutras":
|
||||
try:
|
||||
items = []
|
||||
@@ -95,6 +121,7 @@ class Handler(SimpleHTTPRequestHandler):
|
||||
|
||||
def do_POST(self) -> None:
|
||||
"""处理 POST 请求,目前仅支持 /api/tts。"""
|
||||
self._track_visitor()
|
||||
if self.path != "/api/tts":
|
||||
self._send_json({"error": "not found"}, status=404)
|
||||
return
|
||||
@@ -119,8 +146,10 @@ class Handler(SimpleHTTPRequestHandler):
|
||||
|
||||
cache_key = hashlib.sha256(f"{TTS_MODEL}|{voice}|{text}".encode("utf-8")).hexdigest()[:24]
|
||||
cache_file = CACHE_DIR / f"{cache_key}.wav"
|
||||
STATS["tts_requests"] += 1
|
||||
try:
|
||||
if cache_file.exists():
|
||||
STATS["cache_hits"] += 1
|
||||
audio = cache_file.read_bytes()
|
||||
else:
|
||||
audio = synthesize(text, voice)
|
||||
|
||||
Reference in New Issue
Block a user