257 lines
9.4 KiB
Python
257 lines
9.4 KiB
Python
"""
|
||
AI Assistant 可执行操作注册表
|
||
"""
|
||
import json
|
||
from datetime import datetime, timezone, timedelta
|
||
from typing import Dict, Any, List, Optional
|
||
|
||
from ..database import SessionLocal
|
||
from ..models import Topic, ContentTask, TaskLog, SystemConfig, TopicField, Case
|
||
from ..core.scheduler import scheduler as bg_scheduler
|
||
|
||
# -------------------- 工具函数 --------------------
|
||
|
||
def list_topics(
|
||
page: int = 1,
|
||
page_size: int = 20,
|
||
status: Optional[str] = None,
|
||
field: Optional[str] = None,
|
||
org_id: Optional[str] = None,
|
||
) -> Dict[str, Any]:
|
||
"""获取选题列表,支持分页和筛选"""
|
||
db = SessionLocal()
|
||
try:
|
||
query = db.query(Topic)
|
||
if org_id:
|
||
query = query.filter(Topic.org_id == org_id)
|
||
if status:
|
||
query = query.filter(Topic.status == status)
|
||
if field:
|
||
query = query.filter(Topic.field_name == field)
|
||
total = query.count()
|
||
items = query.order_by(Topic.priority.desc(), Topic.created_at.desc()) \
|
||
.offset((page - 1) * page_size) \
|
||
.limit(page_size) \
|
||
.all()
|
||
result_items = []
|
||
for t in items:
|
||
result_items.append({
|
||
"id": t.id,
|
||
"title": t.title,
|
||
"field": t.field_name,
|
||
"status": t.status,
|
||
"priority": t.priority,
|
||
"priority_score": t.priority_score,
|
||
"created_at": t.created_at.isoformat() if t.created_at else None
|
||
})
|
||
return {
|
||
"total": total,
|
||
"page": page,
|
||
"page_size": page_size,
|
||
"items": result_items
|
||
}
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
def get_topic(topic_id: str, org_id: Optional[str] = None) -> Dict[str, Any]:
|
||
"""获取单个选题详情"""
|
||
db = SessionLocal()
|
||
try:
|
||
query = db.query(Topic).filter(Topic.id == topic_id)
|
||
if org_id:
|
||
query = query.filter(Topic.org_id == org_id)
|
||
t = query.first()
|
||
if not t:
|
||
return {"error": f"选题 {topic_id} 不存在"}
|
||
return {
|
||
"id": t.id,
|
||
"title": t.title,
|
||
"field": t.field_name,
|
||
"status": t.status,
|
||
"priority": t.priority,
|
||
"priority_score": t.priority_score,
|
||
"core_concept": t.core_concept,
|
||
"audience_pain": t.audience_pain,
|
||
"unique_angle": t.unique_angle,
|
||
"cases": t.cases or [],
|
||
"tags": t.tags or [],
|
||
"platform_urls": t.platform_urls or {},
|
||
"created_at": t.created_at.isoformat() if t.created_at else None
|
||
}
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
def get_recent_task_logs(limit: int = 10) -> List[Dict[str, Any]]:
|
||
"""获取最近的任务执行日志"""
|
||
db = SessionLocal()
|
||
try:
|
||
logs = db.query(TaskLog).order_by(TaskLog.started_at.desc()).limit(limit).all()
|
||
return [{
|
||
"id": l.id,
|
||
"module_id": l.module_id,
|
||
"status": l.status,
|
||
"message": l.message,
|
||
"started_at": l.started_at.isoformat() if l.started_at else None,
|
||
"finished_at": l.finished_at.isoformat() if l.finished_at else None,
|
||
"triggered_by": l.triggered_by
|
||
} for l in logs]
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
def get_system_stats() -> Dict[str, Any]:
|
||
"""获取系统概览统计数据"""
|
||
db = SessionLocal()
|
||
try:
|
||
total_topics = db.query(Topic).count()
|
||
pending = db.query(Topic).filter(Topic.status == "pending").count()
|
||
review = db.query(Topic).filter(Topic.status == "review").count()
|
||
draft = db.query(Topic).filter(Topic.status == "draft").count()
|
||
ready = db.query(Topic).filter(Topic.status == "ready").count()
|
||
published = db.query(Topic).filter(Topic.status == "published").count()
|
||
total_cases = db.query(Case).count()
|
||
week_ago = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=7)
|
||
new_this_week = db.query(Topic).filter(Topic.created_at >= week_ago).count()
|
||
return {
|
||
"topics": {
|
||
"total": total_topics,
|
||
"pending": pending,
|
||
"review": review,
|
||
"draft": draft,
|
||
"ready": ready,
|
||
"published": published,
|
||
"new_this_week": new_this_week
|
||
},
|
||
"cases": total_cases,
|
||
"date": datetime.now(timezone.utc).isoformat()
|
||
}
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
def get_task_status(module_id: Optional[str] = None) -> List[Dict[str, Any]]:
|
||
"""查询任务日志(如 collector、generator、optimizer 等)"""
|
||
db = SessionLocal()
|
||
try:
|
||
query = db.query(TaskLog)
|
||
if module_id:
|
||
query = query.filter(TaskLog.module_id == module_id)
|
||
logs = query.order_by(TaskLog.started_at.desc()).limit(10).all()
|
||
return [{
|
||
"id": l.id,
|
||
"module_id": l.module_id,
|
||
"status": l.status,
|
||
"message": l.message,
|
||
"started_at": l.started_at.isoformat() if l.started_at else None,
|
||
"finished_at": l.finished_at.isoformat() if l.finished_at else None,
|
||
"triggered_by": l.triggered_by
|
||
} for l in logs]
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
def trigger_task(module_id: str) -> Dict[str, Any]:
|
||
"""手动触发定时任务(如 collector、generator、optimizer、metrics_sync 等)"""
|
||
# 只允许触发特定任务
|
||
allowed = ["scheduled_collect", "scheduled_generate", "scheduled_optimize",
|
||
"scheduled_optimize_sources", "scheduled_metrics_sync", "scheduled_trends"]
|
||
if module_id not in allowed:
|
||
return {"error": f"不允许手动触发该任务: {module_id}"}
|
||
job_id = module_id if module_id.startswith("scheduled_") else f"scheduled_{module_id}"
|
||
# 检查任务是否存在
|
||
job = bg_scheduler.get_job(job_id)
|
||
if not job:
|
||
return {"error": f"任务不存在: {job_id}"}
|
||
try:
|
||
# 如果任务正在运行,返回提示
|
||
# APScheduler 的 run_job 会立即执行
|
||
bg_scheduler.run_job(job_id)
|
||
return {"success": True, "message": f"任务 {job_id} 已触发执行"}
|
||
except Exception as e:
|
||
return {"error": str(e)}
|
||
|
||
|
||
def search_web(query: str, max_results: int = 5) -> List[Dict[str, Any]]:
|
||
"""联网搜索(通过本项目的 search_utils)"""
|
||
try:
|
||
from ...scripts.search_utils import search as web_search
|
||
results = web_search(query, max_results)
|
||
return {"success": True, "results": results, "count": len(results)}
|
||
except Exception as e:
|
||
return {"error": str(e)}
|
||
|
||
|
||
def list_system_configs() -> List[Dict[str, Any]]:
|
||
"""列出系统配置项"""
|
||
db = SessionLocal()
|
||
try:
|
||
configs = db.query(SystemConfig).all()
|
||
return [{"key": c.key, "value": c.value, "description": c.description} for c in configs]
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
# Action registry
|
||
ACTION_REGISTRY = {
|
||
"list_topics": {
|
||
"func": list_topics,
|
||
"description": "获取选题列表,支持分页(page, page_size)和筛选(status, field, org_id)",
|
||
"params_schema": {
|
||
"page": {"type": "integer", "default": 1, "desc": "页码"},
|
||
"page_size": {"type": "integer", "default": 20, "desc": "每页条数"},
|
||
"status": {"type": "string", "enum": ["pending", "review", "draft", "ready", "published"], "desc": "按状态筛选"},
|
||
"field": {"type": "string", "desc": "按领域筛选"},
|
||
"org_id": {"type": "string", "desc": "按组织筛选"}
|
||
}
|
||
},
|
||
"get_topic": {
|
||
"func": get_topic,
|
||
"description": "获取单个选题详情",
|
||
"params_schema": {
|
||
"topic_id": {"type": "string", "desc": "选题ID,如 A01 或 LIVING-001-26"},
|
||
"org_id": {"type": "string", "desc": "按组织筛选(可选)"}
|
||
}
|
||
},
|
||
"get_recent_task_logs": {
|
||
"func": get_recent_task_logs,
|
||
"description": "获取最近的任务执行日志",
|
||
"params_schema": {
|
||
"limit": {"type": "integer", "default": 10, "desc": "返回条数"}
|
||
}
|
||
},
|
||
"get_system_stats": {
|
||
"func": get_system_stats,
|
||
"description": "获取系统概览统计(选题总数、各状态数量、案例数等)",
|
||
"params_schema": {}
|
||
},
|
||
"get_task_status": {
|
||
"func": get_task_status,
|
||
"description": "查询任务日志,可按模块ID筛选",
|
||
"params_schema": {
|
||
"module_id": {"type": "string", "desc": "可选:筛选特定模块ID(如 scheduled_collect)"}
|
||
}
|
||
},
|
||
"trigger_task": {
|
||
"func": trigger_task,
|
||
"description": "手动触发定时任务(采集、生成、优化、指标同步等)",
|
||
"params_schema": {
|
||
"module_id": {"type": "string", "desc": "任务模块ID:scheduled_collect/scheduled_generate/scheduled_optimize/scheduled_optimize_sources/scheduled_metrics_sync/scheduled_trends"}
|
||
}
|
||
},
|
||
"search_web": {
|
||
"func": search_web,
|
||
"description": "执行网络搜索,返回结构化结果",
|
||
"params_schema": {
|
||
"query": {"type": "string", "desc": "搜索关键词"},
|
||
"max_results": {"type": "integer", "default": 5, "desc": "返回结果数量"}
|
||
}
|
||
},
|
||
"list_system_configs": {
|
||
"func": list_system_configs,
|
||
"description": "列出所有系统配置项(key/value)",
|
||
"params_schema": {}
|
||
}
|
||
}
|