feat: 管理员页面整合与侧边栏导航优化
- 完成系统管理页面与导航整合 - 在 users.html/topics.html/logs.html 侧边栏与移动导航添加系统管理入口 - 创建 admin.html 管理页面(案例/任务日志/LLM配置/系统配置) - 新增核心模块:collector.py(数据采集器)、scheduler.py(任务调度器) - 新增脚本:collector_db_integration.py(采集器数据库整合) - 更新项目文档并验证路由注册
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
选题收集模块
|
||||
调用 scripts/collector.py 脚本,从外部来源收集/生成新选题并写入 JSON
|
||||
"""
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
import logging
|
||||
import os
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 计算项目根目录
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[4]
|
||||
if os.getenv('PROJECT_ROOT'):
|
||||
PROJECT_ROOT = Path(os.getenv('PROJECT_ROOT'))
|
||||
|
||||
def run_collector():
|
||||
"""运行选题收集脚本"""
|
||||
script_path = PROJECT_ROOT / "scripts" / "collector.py"
|
||||
if not script_path.exists():
|
||||
raise FileNotFoundError(f"Collector script not found: {script_path}")
|
||||
result = subprocess.run(
|
||||
["python", str(script_path)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=PROJECT_ROOT,
|
||||
timeout=300
|
||||
)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"Collector failed: {result.stderr}")
|
||||
return {"ok": True, "output": result.stdout}
|
||||
@@ -0,0 +1,94 @@
|
||||
"""
|
||||
定时任务调度器
|
||||
基于 APScheduler,支持在 FastAPI 生命周期内运行定时任务
|
||||
"""
|
||||
import os
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from .generator import run_creator
|
||||
from .optimizer import run_optimizer
|
||||
from .sync import sync_all_topics
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class TaskScheduler:
|
||||
def __init__(self):
|
||||
self.scheduler = BackgroundScheduler()
|
||||
self._started = False
|
||||
|
||||
def start(self):
|
||||
if self._started:
|
||||
logger.warning("Scheduler already started")
|
||||
return
|
||||
# 使用 CronTrigger 设置每日固定时间点
|
||||
self.scheduler.add_job(
|
||||
self._run_sync,
|
||||
CronTrigger(hour=2, minute=30),
|
||||
id='scheduled_sync',
|
||||
replace_existing=True,
|
||||
max_instances=1,
|
||||
coalesce=True
|
||||
)
|
||||
self.scheduler.add_job(
|
||||
self._run_generate,
|
||||
CronTrigger(hour=3, minute=30),
|
||||
id='scheduled_generate',
|
||||
replace_existing=True,
|
||||
max_instances=1,
|
||||
coalesce=True
|
||||
)
|
||||
self.scheduler.add_job(
|
||||
self._run_optimize,
|
||||
CronTrigger(hour=4, minute=30),
|
||||
id='scheduled_optimize',
|
||||
replace_existing=True,
|
||||
max_instances=1,
|
||||
coalesce=True
|
||||
)
|
||||
self.scheduler.start()
|
||||
self._started = True
|
||||
logger.info("Scheduler started with daily cron triggers (02:30, 03:30, 04:30)")
|
||||
def shutdown(self):
|
||||
if self.scheduler.running:
|
||||
self.scheduler.shutdown()
|
||||
logger.info("Scheduler shut down")
|
||||
|
||||
def _run_generate(self):
|
||||
try:
|
||||
logger.info("[Scheduled] Starting content generation...")
|
||||
result = run_creator()
|
||||
logger.info("[Scheduled] Generation completed: %s", result)
|
||||
except Exception as e:
|
||||
logger.exception("[Scheduled] Generation failed: %s", e)
|
||||
|
||||
def _run_optimize(self):
|
||||
try:
|
||||
logger.info("[Scheduled] Starting compliance optimization...")
|
||||
result = run_optimizer()
|
||||
logger.info("[Scheduled] Optimization completed: %s", result)
|
||||
except Exception as e:
|
||||
logger.exception("[Scheduled] Optimization failed: %s", e)
|
||||
|
||||
def _run_sync(self):
|
||||
try:
|
||||
logger.info("[Scheduled] Starting data sync...")
|
||||
sync_all_topics()
|
||||
logger.info("[Scheduled] Sync completed")
|
||||
except Exception as e:
|
||||
logger.exception("[Scheduled] Sync failed: %s", e)
|
||||
|
||||
def get_jobs(self):
|
||||
"""返回当前所有定时任务的状态"""
|
||||
jobs = []
|
||||
for job in self.scheduler.get_jobs():
|
||||
jobs.append({
|
||||
"id": job.id,
|
||||
"next_run_time": job.next_run_time.isoformat() if job.next_run_time else None,
|
||||
"trigger": str(job.trigger),
|
||||
})
|
||||
return jobs
|
||||
|
||||
# 全局单例
|
||||
scheduler = TaskScheduler()
|
||||
Reference in New Issue
Block a user