feat: 前后台静态资源路径冲突修复 + 用户管理功能

- 修改 admin/vite.config.js 添加 base: '/admin/' 解决静态资源路径问题
- 修复后台 index.html 资源引用从 /assets/ → /admin/assets/
- 更新优化器默认 API 地址为服务器地址
- 添加友链管理相关代码
- 修复多处分类管理页面
This commit is contained in:
bwstudio
2026-06-10 07:30:49 +08:00
parent aecf1f1f15
commit 595394fcb7
22 changed files with 740 additions and 100 deletions
+2 -2
View File
@@ -25,8 +25,8 @@ def parse_args():
parser.add_argument(
"--api-url",
type=str,
default=os.getenv("API_URL", "http://localhost:8001"),
help="API 地址(默认: http://localhost:8001",
default=os.getenv("API_URL", "http://39.104.58.51"),
help="API 地址(默认: http://39.104.58.51",
)
parser.add_argument(
"--username",
+77 -33
View File
@@ -120,30 +120,34 @@ class Optimizer:
# === Stage 1: 质量检测 ===
def quality_check(self, content: str) -> dict:
"""判断笑话是否有笑点,返回 {"has_punchline": bool, "reason": str}"""
resp = self.ai_client.chat.completions.create(
model=self.model_name,
messages=[
{"role": "system", "content": QUALITY_CHECK_SYSTEM_PROMPT},
{"role": "user", "content": QUALITY_CHECK_USER_PROMPT.format(content=content[:2000])},
],
temperature=0.3,
max_tokens=200,
)
def _call():
return self.ai_client.chat.completions.create(
model=self.model_name,
messages=[
{"role": "system", "content": QUALITY_CHECK_SYSTEM_PROMPT},
{"role": "user", "content": QUALITY_CHECK_USER_PROMPT.format(content=content[:2000])},
],
temperature=0.3,
max_tokens=200,
)
resp = self._safe_api_call(_call)
raw = resp.choices[0].message.content.strip()
return self._parse_json(raw, {"has_punchline": True, "reason": ""})
# === Stage 2: AI 润色 ===
def polish(self, content: str) -> str:
"""润色笑话内容"""
resp = self.ai_client.chat.completions.create(
model=self.model_name,
messages=[
{"role": "system", "content": POLISH_SYSTEM_PROMPT},
{"role": "user", "content": POLISH_USER_PROMPT.format(content=content)},
],
temperature=0.8,
max_tokens=1024,
)
def _call():
return self.ai_client.chat.completions.create(
model=self.model_name,
messages=[
{"role": "system", "content": POLISH_SYSTEM_PROMPT},
{"role": "user", "content": POLISH_USER_PROMPT.format(content=content)},
],
temperature=0.8,
max_tokens=1024,
)
resp = self._safe_api_call(_call)
return resp.choices[0].message.content.strip()
# === Stage 3: 评价分类 ===
@@ -152,19 +156,21 @@ class Optimizer:
type_names = [t.get("name", "") for t in self.types]
crowd_names = [c.get("name", "") for c in self.crowds]
resp = self.ai_client.chat.completions.create(
model=self.model_name,
messages=[
{"role": "system", "content": EVALUATE_SYSTEM_PROMPT},
{"role": "user", "content": EVALUATE_USER_PROMPT.format(
content=content[:2000],
known_types=", ".join(type_names),
known_crowds=", ".join(crowd_names),
)},
],
temperature=0.3,
max_tokens=300,
)
def _call():
return self.ai_client.chat.completions.create(
model=self.model_name,
messages=[
{"role": "system", "content": EVALUATE_SYSTEM_PROMPT},
{"role": "user", "content": EVALUATE_USER_PROMPT.format(
content=content[:2000],
known_types=", ".join(type_names),
known_crowds=", ".join(crowd_names),
)},
],
temperature=0.3,
max_tokens=300,
)
resp = self._safe_api_call(_call)
raw = resp.choices[0].message.content.strip()
result = self._parse_json(raw, {"types": [], "crowds": [], "score": 5, "comment": ""})
# Backward compatibility: if LLM returns old single format, convert to array
@@ -175,6 +181,27 @@ class Optimizer:
return result
# === 辅助方法 ===
def _safe_api_call(self, func, *args, max_retries: int = 3, **kwargs):
"""带重试的 API 调用,自动处理限流"""
import time as time_module
last_error = None
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
last_error = e
error_str = str(e)
# 检查是否是限流错误
if "429" in error_str or "rate" in error_str.lower():
wait_time = (attempt + 1) * 30 # 30, 60, 90 秒
print(f" [!] API 限流,等待 {wait_time} 秒后重试 ({attempt+1}/{max_retries})...")
time_module.sleep(wait_time)
else:
# 其他错误,直接重试一次
if attempt < max_retries - 1:
time_module.sleep(5)
raise last_error
def _parse_json(self, raw: str, default: dict) -> dict:
"""安全解析 LLM 返回的 JSON"""
try:
@@ -266,12 +293,28 @@ class Optimizer:
crowd_names = []
score = None
# 根据评分计算 AI 等级
ai_level = None
if score is not None:
if score >= 8:
ai_level = "excellent"
elif score >= 6:
ai_level = "good"
elif score >= 4:
ai_level = "ordinary"
else:
ai_level = "poor"
# 保存更新
try:
update = {
"polished_content": polished,
"status": "approved" if (score or 5) >= 4 else "pending",
}
if score is not None:
update["ai_score"] = float(score)
if ai_level:
update["ai_level"] = ai_level
if type_names:
update["type_ids"] = []
for n in type_names:
@@ -325,9 +368,10 @@ class Optimizer:
print(f" [!] 处理异常: {e}")
self.stats["skipped"] += 1
# 每条间稍等,避免 API 限流
# 每条间稍等,避免 API 限流(每次请求间隔 2-3 秒)
if idx < len(jokes) - 1:
time.sleep(1)
import time
time.sleep(2)
# 输出统计
print(f"\n{'='*40}")