196 lines
7.6 KiB
Python
196 lines
7.6 KiB
Python
"""海报功能路由。"""
|
||
import os
|
||
from flask import Blueprint, request, jsonify, send_file
|
||
from insurance.middleware.auth_middleware import jwt_required
|
||
from insurance.utils.response import success, error, ErrorCode
|
||
|
||
poster_bp = Blueprint("poster", __name__)
|
||
poster_service = None
|
||
|
||
|
||
def _get_service():
|
||
global poster_service
|
||
if poster_service is None:
|
||
from insurance.poster.service import PosterService
|
||
poster_service = PosterService()
|
||
return poster_service
|
||
|
||
|
||
# ─── 健康检查 ─────────────────────────────────────────────
|
||
|
||
@poster_bp.route("/health", methods=["GET"])
|
||
def health():
|
||
"""海报模块健康检查:reviewed 产品、模板、文案模板、模型配置。"""
|
||
from flask import jsonify
|
||
checks = {}
|
||
critical_missing = []
|
||
|
||
try:
|
||
from insurance.models.ppt_config import PptProduct
|
||
count = PptProduct.query.filter(
|
||
PptProduct.manual_parse_status == "reviewed",
|
||
PptProduct.status == 1,
|
||
).count()
|
||
checks["reviewed_products"] = count
|
||
if count == 0:
|
||
critical_missing.append("reviewed_products")
|
||
except Exception as e:
|
||
checks["reviewed_products"] = f"error: {e}"
|
||
critical_missing.append("reviewed_products")
|
||
|
||
try:
|
||
from insurance.models.poster_template_model import PosterTemplate
|
||
count = PosterTemplate.query.filter_by(status=1).count()
|
||
checks["poster_templates"] = count
|
||
if count == 0:
|
||
critical_missing.append("poster_templates")
|
||
except Exception as e:
|
||
checks["poster_templates"] = f"error: {e}"
|
||
critical_missing.append("poster_templates")
|
||
|
||
try:
|
||
from insurance.models.poster_copy_template import PosterCopyTemplate
|
||
count = PosterCopyTemplate.query.filter_by(status=1).count()
|
||
checks["copy_templates"] = count
|
||
if count == 0:
|
||
critical_missing.append("copy_templates")
|
||
except Exception as e:
|
||
checks["copy_templates"] = f"error: {e}"
|
||
critical_missing.append("copy_templates")
|
||
|
||
try:
|
||
from insurance.models.system_setting import SystemSetting
|
||
keys = ["poster_image_provider", "poster_image_api_key"]
|
||
settings = {s.key: s.value for s in SystemSetting.query.filter(SystemSetting.key.in_(keys)).all()}
|
||
checks["image_model_configured"] = bool(settings.get("poster_image_api_key"))
|
||
except Exception as e:
|
||
checks["image_model_configured"] = f"error: {e}"
|
||
|
||
if critical_missing:
|
||
checks["status"] = "degraded"
|
||
checks["missing"] = critical_missing
|
||
return jsonify(checks), 503
|
||
|
||
checks["status"] = "ok"
|
||
return success(checks)
|
||
|
||
|
||
# ─── 产品列表 ─────────────────────────────────────────────
|
||
|
||
@poster_bp.route("/products", methods=["GET"])
|
||
@jwt_required
|
||
def list_products():
|
||
"""获取已 reviewed 的产品列表。"""
|
||
return jsonify(_get_service().get_reviewed_products())
|
||
|
||
|
||
# ─── 计划书上传 ───────────────────────────────────────────
|
||
|
||
@poster_bp.route("/case-upload", methods=["POST"])
|
||
@jwt_required
|
||
def upload_case():
|
||
"""上传计划书 PDF + 触发解析。"""
|
||
user_id = str(getattr(request, "user_id", "guest"))
|
||
product_id = request.form.get("productId", "")
|
||
password = request.form.get("password", "")
|
||
file = request.files.get("file")
|
||
if not file:
|
||
return error(ErrorCode.PARAM_ERROR, "请上传文件")
|
||
return jsonify(_get_service().upload_case(user_id, product_id, file, password))
|
||
|
||
|
||
@poster_bp.route("/case-upload/<int:record_id>", methods=["GET"])
|
||
@jwt_required
|
||
def get_case_upload(record_id):
|
||
"""获取解析结果。"""
|
||
user_id = str(getattr(request, "user_id", "guest"))
|
||
return jsonify(_get_service().get_case_upload(record_id, user_id))
|
||
|
||
|
||
@poster_bp.route("/case-upload/<int:record_id>/confirm", methods=["PUT"])
|
||
@jwt_required
|
||
def confirm_case_upload(record_id):
|
||
"""核对/修正解析数据。"""
|
||
user_id = str(getattr(request, "user_id", "guest"))
|
||
return jsonify(_get_service().confirm_case_upload(record_id, user_id, request.get_json(silent=True) or {}))
|
||
|
||
|
||
# ─── 模板列表 ─────────────────────────────────────────────
|
||
|
||
@poster_bp.route("/templates", methods=["GET"])
|
||
@jwt_required
|
||
def list_templates():
|
||
"""获取可用海报模板列表。"""
|
||
return jsonify(_get_service().get_templates())
|
||
|
||
|
||
@poster_bp.route("/copy-templates", methods=["GET"])
|
||
@jwt_required
|
||
def list_copy_templates():
|
||
"""获取可用文案模板列表。"""
|
||
return jsonify(_get_service().get_copy_templates())
|
||
|
||
|
||
# ─── 文案生成 ─────────────────────────────────────────────
|
||
|
||
@poster_bp.route("/generate-copy", methods=["POST"])
|
||
@jwt_required
|
||
def generate_copy():
|
||
"""生成文案(template/ai 模式)。"""
|
||
user_id = str(getattr(request, "user_id", "guest"))
|
||
return jsonify(_get_service().generate_copy(user_id, request.get_json(silent=True) or {}))
|
||
|
||
|
||
# ─── 海报生成 ─────────────────────────────────────────────
|
||
|
||
@poster_bp.route("/generate", methods=["POST"])
|
||
@jwt_required
|
||
def generate_poster():
|
||
"""生成海报图片。"""
|
||
user_id = str(getattr(request, "user_id", "guest"))
|
||
return jsonify(_get_service().generate_poster(user_id, request.get_json(silent=True) or {}))
|
||
|
||
|
||
# ─── 下载海报 ─────────────────────────────────────────────
|
||
|
||
@poster_bp.route("/download/<int:record_id>", methods=["GET"])
|
||
@jwt_required
|
||
def download_poster(record_id):
|
||
"""下载海报文件。"""
|
||
from insurance.models.poster_record import PosterRecord
|
||
user_id = str(getattr(request, "user_id", "guest"))
|
||
record = PosterRecord.query.get(record_id)
|
||
if not record or record.user_id != user_id:
|
||
return error(ErrorCode.NOT_FOUND, "记录不存在")
|
||
if not record.export_url:
|
||
return error(ErrorCode.NOT_FOUND, "文件不存在")
|
||
# 路径安全校验:仅允许 uploads/posters 目录
|
||
file_abs = os.path.abspath(record.export_url)
|
||
posters_dir = os.path.abspath(os.path.join("uploads", "posters"))
|
||
if not file_abs.startswith(posters_dir) or not os.path.exists(file_abs):
|
||
return error(ErrorCode.NOT_FOUND, "文件不存在")
|
||
return send_file(file_abs, as_attachment=True,
|
||
download_name=f"poster_{record_id}.png", mimetype="image/png")
|
||
|
||
|
||
# ─── 记录列表 ─────────────────────────────────────────────
|
||
|
||
@poster_bp.route("/records", methods=["GET"])
|
||
@jwt_required
|
||
def list_records():
|
||
"""当前用户的海报生成记录。"""
|
||
user_id = str(getattr(request, "user_id", "guest"))
|
||
params = {
|
||
"page": request.args.get("page", 1, type=int),
|
||
"page_size": request.args.get("page_size", 20, type=int),
|
||
}
|
||
return jsonify(_get_service().list_records(user_id, params))
|
||
|
||
|
||
@poster_bp.route("/records/<int:record_id>", methods=["GET"])
|
||
@jwt_required
|
||
def get_record(record_id):
|
||
"""记录详情。"""
|
||
user_id = str(getattr(request, "user_id", "guest"))
|
||
return jsonify(_get_service().get_record(record_id, user_id))
|