"""Insurance Blueprint 路由注册 在基础平台的 main.py 中添加以下代码即可挂载所有自研路由: from insurance.routes import register_insurance_routes register_insurance_routes(app) """ import os from flask import Flask def register_insurance_routes(app: Flask): """注册所有 insurance 模块的 Blueprint 到基础平台主应用。""" from insurance.auth.routes import auth_bp from insurance.chat.routes import chat_bp from insurance.chat.agent_routes import agent_bp from insurance.recommend.routes import recommend_bp from insurance.kb.routes import kb_bp from insurance.kb.retrieval_routes import retrieval_bp from insurance.admin.routes import admin_bp from insurance.stats.routes import stats_bp from insurance.wecom.routes import wecom_bp from insurance.ppt.routes import ppt_bp from insurance.admin.ppt_admin_routes import ppt_admin_bp from insurance.poster.routes import poster_bp from insurance.generation.routes import workspace_bp # 使用 /insurance/ 前缀避免与 Dify 的 /api/ 路由冲突 app.register_blueprint(auth_bp, url_prefix="/insurance/auth") app.register_blueprint(chat_bp, url_prefix="/insurance/chat") app.register_blueprint(agent_bp, url_prefix="/insurance/agents") app.register_blueprint(recommend_bp, url_prefix="/insurance/recommend") app.register_blueprint(kb_bp, url_prefix="/insurance/kb") app.register_blueprint(retrieval_bp, url_prefix="/insurance/retrieval") app.register_blueprint(admin_bp, url_prefix="/insurance/admin") app.register_blueprint(stats_bp, url_prefix="/insurance/stats") app.register_blueprint(wecom_bp, url_prefix="/insurance/wecom") app.register_blueprint(ppt_bp, url_prefix="/insurance/ppt") app.register_blueprint(ppt_admin_bp, url_prefix="/insurance/admin/ppt") app.register_blueprint(poster_bp, url_prefix="/insurance/poster") app.register_blueprint(workspace_bp, url_prefix="/insurance/workspace") # 注册 Celery 自研任务(不修改 BaoDan Celery 基座) _register_celery_tasks(app) # 恢复过期任务(启动时清理无心跳的 running/queued 任务) _recover_stale_tasks(app) # 注册全局异常处理器 from insurance.utils.error_handler import register_error_handlers register_error_handlers(app) # 注册增强健康检查端点 _register_health_checks(app) def _register_celery_tasks(app: Flask): """将自研 Celery 任务注册到 BaoDan 的 Celery 实例。 不修改 BaoDan 的 ext_celery.py,通过动态添加 imports 实现。 """ try: celery_app = app.extensions.get("celery") if celery_app: # 将自研任务模块添加到 Celery imports insurance_tasks = [ "insurance.generation.celery_tasks", ] current_imports = list(celery_app.conf.get("imports", []) or []) for task_module in insurance_tasks: if task_module not in current_imports: current_imports.append(task_module) celery_app.conf.update(imports=current_imports) app.logger.info(f"已注册自研 Celery 任务: {insurance_tasks}") else: app.logger.debug("Celery 未初始化,跳过自研任务注册") except Exception as e: app.logger.warning(f"注册自研 Celery 任务失败: {e}") def _recover_stale_tasks(app: Flask): """启动时恢复过期任务。""" try: with app.app_context(): from insurance.generation.task_service import recover_stale_tasks recover_stale_tasks() except Exception as e: app.logger.warning(f"恢复过期任务失败: {e}") def _register_health_checks(app: Flask): """注册增强健康检查端点。""" from flask import jsonify @app.route("/insurance/health/ready", methods=["GET"]) def health_ready(): """就绪检查:DB、Redis、storage 可写、必要表字段。""" checks = {} # DB 检查 try: from insurance.db.compat import db from sqlalchemy import text db.session.execute(text("SELECT 1")) checks["database"] = "ok" except Exception as e: checks["database"] = f"error: {e}" # Redis 检查 try: from insurance.db.compat import redis_client if redis_client: redis_client.ping() checks["redis"] = "ok" else: checks["redis"] = "not_configured" except Exception as e: checks["redis"] = f"error: {e}" # Storage 可写检查 try: from flask import current_app upload_dir = current_app.config.get("UPLOAD_FOLDER", "uploads") os.makedirs(upload_dir, exist_ok=True) test_file = os.path.join(upload_dir, ".health_check") with open(test_file, "w") as f: f.write("ok") os.remove(test_file) checks["storage"] = "ok" except Exception as e: checks["storage"] = f"error: {e}" # 关键表检查 try: from insurance.db.compat import db from sqlalchemy import text tables = ["insurance_ppt_templates", "poster_records", "system_settings"] missing = [] for t in tables: try: db.session.execute(text(f"SELECT 1 FROM {t} LIMIT 0")) except Exception: missing.append(t) if missing: checks["tables"] = f"missing: {', '.join(missing)}" else: checks["tables"] = "ok" except Exception as e: checks["tables"] = f"error: {e}" all_ok = all(v == "ok" or v == "not_configured" for v in checks.values()) status_code = 200 if all_ok else 503 return jsonify({"status": "ready" if all_ok else "degraded", "checks": checks}), status_code