150 lines
7.3 KiB
Python
150 lines
7.3 KiB
Python
|
|
from datetime import datetime
|
||
|
|
|
||
|
|
from flask import jsonify, request, send_from_directory
|
||
|
|
|
||
|
|
from app.application.bot_controller import bot_controller
|
||
|
|
from app.infrastructure.service.backend.config import ASSETS_DIR, STATIC_DIR
|
||
|
|
from app.infrastructure.service.backend.db import SQLITE_DB_PATH, get_conn, get_setting, set_setting
|
||
|
|
from app.infrastructure.service.logging.log_service import log_event, new_trace_id
|
||
|
|
|
||
|
|
LOCAL_SETTING_DEFAULTS = {
|
||
|
|
"auto_reply_enabled": "1",
|
||
|
|
"listener_enabled": "0",
|
||
|
|
"listener_runtime_status": "stopped",
|
||
|
|
"full_auto_reply_enabled": "0",
|
||
|
|
"reply_fallback_mode": "ai",
|
||
|
|
}
|
||
|
|
LOCAL_SETTING_CACHE = {}
|
||
|
|
|
||
|
|
|
||
|
|
def _load_local_settings(force=False):
|
||
|
|
if LOCAL_SETTING_CACHE and not force:
|
||
|
|
return
|
||
|
|
for key, default in LOCAL_SETTING_DEFAULTS.items():
|
||
|
|
LOCAL_SETTING_CACHE[key] = str(get_setting(key, default))
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
def _get_local_setting(key, default=None):
|
||
|
|
_load_local_settings(force=True)
|
||
|
|
return LOCAL_SETTING_CACHE.get(key, default)
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
def _set_local_setting(key, value):
|
||
|
|
v = str(value)
|
||
|
|
LOCAL_SETTING_CACHE[key] = v
|
||
|
|
set_setting(key, v)
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
def _frontend_index_available():
|
||
|
|
return STATIC_DIR != ASSETS_DIR and (STATIC_DIR / "index.html").exists()
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
def register_rule_routes(app):
|
||
|
|
@app.route("/")
|
||
|
|
@app.route("/index.html")
|
||
|
|
def frontend_page():
|
||
|
|
if _frontend_index_available():
|
||
|
|
return send_from_directory(STATIC_DIR, "index.html")
|
||
|
|
return send_from_directory(ASSETS_DIR, "admin.html")
|
||
|
|
|
||
|
|
@app.route("/admin.html")
|
||
|
|
def admin_page():
|
||
|
|
return send_from_directory(ASSETS_DIR, "admin.html")
|
||
|
|
|
||
|
|
@app.route("/api/rules", methods=["GET", "POST"])
|
||
|
|
def api_rules():
|
||
|
|
action = request.values.get("action", "list")
|
||
|
|
conn = get_conn()
|
||
|
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||
|
|
try:
|
||
|
|
with conn.cursor() as cur:
|
||
|
|
if action == "list":
|
||
|
|
cur.execute("SELECT * FROM auto_reply_rules ORDER BY id DESC")
|
||
|
|
rows = cur.fetchall()
|
||
|
|
log_event("INFO", "api", "api.rules.list", new_trace_id("rules"), "query", "ok", "查询回复匹配配置", extra={"db_path": str(SQLITE_DB_PATH), "count": len(rows)})
|
||
|
|
return jsonify({"success": True, "data": rows, "db_path": str(SQLITE_DB_PATH)})
|
||
|
|
|
||
|
|
if action == "create":
|
||
|
|
keyword = (request.values.get("keyword") or "").strip()
|
||
|
|
match_type = request.values.get("match_type", "contain")
|
||
|
|
reply_text = (request.values.get("reply_text") or "").strip()
|
||
|
|
is_active = int(request.values.get("is_active", 1))
|
||
|
|
if not keyword or not reply_text:
|
||
|
|
return jsonify({"success": False, "message": "关键词和回复内容不能为空"})
|
||
|
|
if match_type not in ["contain", "equal"]:
|
||
|
|
match_type = "contain"
|
||
|
|
cur.execute("INSERT INTO auto_reply_rules(keyword, match_type, reply_text, is_active, created_at, updated_at) VALUES (%s, %s, %s, %s, %s, %s)", (keyword, match_type, reply_text, is_active, now, now))
|
||
|
|
conn.commit()
|
||
|
|
return jsonify({"success": True})
|
||
|
|
|
||
|
|
if action == "toggle":
|
||
|
|
rule_id = int(request.values.get("id", 0))
|
||
|
|
is_active = int(request.values.get("is_active", 0))
|
||
|
|
if rule_id <= 0:
|
||
|
|
return jsonify({"success": False, "message": "参数错误"})
|
||
|
|
cur.execute("UPDATE auto_reply_rules SET is_active = %s, updated_at = %s WHERE id = %s", (is_active, now, rule_id))
|
||
|
|
conn.commit()
|
||
|
|
return jsonify({"success": True})
|
||
|
|
|
||
|
|
if action == "delete":
|
||
|
|
rule_id = int(request.values.get("id", 0))
|
||
|
|
if rule_id <= 0:
|
||
|
|
return jsonify({"success": False, "message": "参数错误"})
|
||
|
|
cur.execute("DELETE FROM auto_reply_rules WHERE id = %s", (rule_id,))
|
||
|
|
conn.commit()
|
||
|
|
return jsonify({"success": True})
|
||
|
|
|
||
|
|
if action == "settings_get":
|
||
|
|
auto_on = _get_local_setting("auto_reply_enabled", "1") == "1"
|
||
|
|
full_auto_on = _get_local_setting("full_auto_reply_enabled", "0") == "1"
|
||
|
|
reply_fallback_mode = (_get_local_setting("reply_fallback_mode", "ai") or "ai").strip() or "ai"
|
||
|
|
bot_status = bot_controller.status()
|
||
|
|
runtime_status = (bot_status.get("status") or "stopped").strip().lower()
|
||
|
|
if runtime_status not in ["running", "starting", "stopping", "stopped", "error"]:
|
||
|
|
runtime_status = "stopped"
|
||
|
|
listener_on = runtime_status in ["running", "starting"]
|
||
|
|
return jsonify({
|
||
|
|
"success": True,
|
||
|
|
"auto_reply_enabled": auto_on,
|
||
|
|
"listener_enabled": listener_on,
|
||
|
|
"listener_runtime_status": runtime_status,
|
||
|
|
"listener_intent_enabled": _get_local_setting("listener_enabled", "0") == "1",
|
||
|
|
"full_auto_reply_enabled": full_auto_on,
|
||
|
|
"reply_fallback_mode": reply_fallback_mode,
|
||
|
|
})
|
||
|
|
|
||
|
|
if action == "settings_set":
|
||
|
|
if "auto_reply_enabled" in request.values:
|
||
|
|
auto_on = "1" if request.values.get("auto_reply_enabled", "1") == "1" else "0"
|
||
|
|
_set_local_setting("auto_reply_enabled", auto_on)
|
||
|
|
if "listener_enabled" in request.values:
|
||
|
|
listener_on = "1" if request.values.get("listener_enabled", "0") == "1" else "0"
|
||
|
|
_set_local_setting("listener_enabled", listener_on)
|
||
|
|
if "listener_runtime_status" in request.values:
|
||
|
|
runtime_status = (request.values.get("listener_runtime_status") or "stopped").strip().lower()
|
||
|
|
if runtime_status not in ["running", "starting", "stopping", "stopped", "error"]:
|
||
|
|
runtime_status = "stopped"
|
||
|
|
_set_local_setting("listener_runtime_status", runtime_status)
|
||
|
|
if "full_auto_reply_enabled" in request.values:
|
||
|
|
full_auto_on = "1" if request.values.get("full_auto_reply_enabled", "0") == "1" else "0"
|
||
|
|
_set_local_setting("full_auto_reply_enabled", full_auto_on)
|
||
|
|
if "reply_fallback_mode" in request.values:
|
||
|
|
reply_fallback_mode = (request.values.get("reply_fallback_mode") or "ai").strip() or "ai"
|
||
|
|
_set_local_setting("reply_fallback_mode", reply_fallback_mode)
|
||
|
|
return jsonify({"success": True})
|
||
|
|
|
||
|
|
if action == "messages_recent":
|
||
|
|
limit = int(request.values.get("limit", 50))
|
||
|
|
limit = max(1, min(100, limit))
|
||
|
|
cur.execute("SELECT * FROM messages ORDER BY id DESC LIMIT %s", (limit,))
|
||
|
|
rows = cur.fetchall()
|
||
|
|
return jsonify({"success": True, "data": rows})
|
||
|
|
|
||
|
|
return jsonify({"success": False, "message": "未知操作"})
|
||
|
|
finally:
|
||
|
|
conn.close()
|