在数字化营销场景下,高质量的营销文案与视觉化的广告海报结合,是提升商品转化效率的核心抓手。我们基于既有营销文案生成链路,深度集成新一代图形识别与生成大模型,完成了从 “文案创作” 到 “海报生成” 的全链路闭环,实现了营销内容创作的智能化、自动化升级。本文将详细拆解这一过程中的技术选型、核心实现与工程化思考。

一、背景与挑战:从文案到海报的链路补全

1. 既有链路的局限性

我们已落地的营销文案生成系统基于双层 RAG(检索增强生成)架构,能依托商品评论数据、PDF 知识库等多源信息,生成贴合商品卖点的营销文案。但在实际落地中发现:

  • 文案与视觉素材脱节:生成的优质文案缺乏配套的广告海报,无法直接应用于电商投放、社交媒体传播等场景;
  • 海报制作效率低:传统海报制作依赖设计人员手动结合文案与商品图,耗时且难以批量适配不同商品风格;
  • 数据闭环缺失:海报生成结果未与既有数据模型联动,无法沉淀、管理、复用生成的广告素材。

2. 核心目标

补全 “文案生成→海报生成→素材管理” 的全链路,实现:

  • 输入商品实物图 + 既有营销文案,自动生成风格化广告海报;
  • 支持多风格海报生成,适配不同营销场景(如 premium、简约、国潮等);
  • 实现海报的存储、查询、封面设置、删除等全生命周期管理;
  • 兼容异步生成模式,应对大模型图片生成的耗时特性。

二、技术方案设计:从模型层到工程层的全维度考量

1. 核心技术选型思考

在海报生成链路中,我们面临两个核心技术决策:

(1)图形识别:为何选择视觉大模型而非传统 CV?

传统 CV 算法(如目标检测、OCR)仅能提取商品基础特征,无法理解商品卖点与营销文案的关联;而基于 GPT-4V 等视觉大模型的方案,可实现:

  • 多模态理解:同时分析商品图片的视觉特征(材质、颜色、形态)与营销文案的语义特征(卖点、slogan);
  • 场景化洞察:结合文案中的核心卖点(如 “防水”“轻便”),从图片中定位对应视觉特征,为海报生成提供精准的视觉锚点;
  • 自然语言输出:将视觉分析结果转化为结构化的文案描述,直接用于海报生成的 prompt 构建。
(2)图片生成:异步任务 + 兜底方案的工程化设计

考虑到大模型图片生成存在耗时久、成功率波动的问题,我们设计了 “SVG 兜底 + AI 生成异步回调” 的双层方案:

  • 兜底层:基于 Canvas/SVG 即时生成基础版海报,确保接口快速返回可用素材;
  • 优化层:调用 SophnetImageGenerator 异步生成高质量风格化海报,通过任务 ID 轮询获取结果,生成成功后更新海报链接;
  • 容错设计:若 AI 生成失败,直接返回兜底海报,避免链路中断。

2. 数据模型设计:营销海报的结构化存储

为实现海报的全生命周期管理,我们基于 SQLAlchemy 设计了MarketingPoster模型,核心字段设计的思考如下:

python

运行

class MarketingPoster(Base):
    __tablename__ = "marketing_posters"

    id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    dataset_id = Column(String(36), ForeignKey("datasets.id"), nullable=False, index=True)  # 关联商品数据集,实现素材归属
    poster_url = Column(String(1000), nullable=False)  # 最终海报存储地址
    source_url = Column(String(1000))  # AI生成原始地址,便于溯源
    style = Column(String(50))  # 海报风格标识,支持多风格管理
    style_name = Column(String(100))  # 风格友好名称,前端展示
    slogan = Column(String(200))  # 海报使用的营销slogan,关联文案链路
    task_id = Column(String(100), index=True)  # 关联AI生成任务ID,异步状态追踪
    status = Column(String(30), default="SUCCEEDED")  # 生成状态,便于问题排查
    is_cover = Column(Integer, default=0)  # 封面标识,支持商品封面设置
    created_at = Column(DateTime, default=datetime.utcnow)  # 生成时间,便于排序查询

核心设计思路:

  • 关联粒度:通过dataset_id关联商品数据集,确保海报素材与商品一一对应;
  • 可追溯性:task_id关联 AI 生成任务,source_url记录原始生成地址,便于问题定位;
  • 业务适配:is_cover字段支持设置商品封面,贴合电商场景的素材使用需求;
  • 扩展性:stylestyle_name分离,便于后续新增风格体系(如新增 “国潮”“极简” 风格)。

3. 核心业务逻辑实现:从接口到异步任务的全链路

(1)海报生成接口:多模态输入的处理与校验

海报生成的核心入口接口需兼顾 “图片上传 + 文案关联 + 风格配置”,核心逻辑如下:

python

运行

@router.post("/poster/{dataset_id}")
async def generate_marketing_poster(
    dataset_id: str,
    image: UploadFile = File(...),
    style: str = Form("premium"),
    db: AsyncSession = Depends(get_db),
):
    # 1. 图片类型校验:确保上传的是有效图片文件
    if not image.content_type or not image.content_type.startswith("image/"):
        raise HTTPException(400, "请上传商品图片文件")
    
    # 2. 文案前置校验:确保已生成营销文案,避免海报无内容支撑
    result = await db.execute(
        select(AnalysisTask)
        .where(
            AnalysisTask.dataset_id == dataset_id,
            AnalysisTask.task_type == "marketing",
            AnalysisTask.status == "done",
        )
        .order_by(AnalysisTask.created_at.desc())
    )
    task = result.scalars().first()
    if not task or not task.result_json:
        raise HTTPException(400, "请先生成营销文案,再生成商品海报")
    
    # 3. 多模态分析:视觉大模型分析商品图+营销文案,提取核心卖点
    image_bytes = await image.read()
    copy_data = json.loads(task.result_json)
    poster_service = PosterService()
    vision_llm = LLMClient(model=settings.LLM_VISION_MODEL)
    vision_insight = await poster_service.analyze_product_image(
        image_bytes=image_bytes,
        filename=image.filename or "product.png",
        copy_data=copy_data,
        llm_client=vision_llm,
    )
    
    # 4. 兜底海报生成:即时返回基础版海报,保障接口响应速度
    poster = poster_service.generate_poster(
        image_bytes=image_bytes,
        filename=image.filename or "product.png",
        copy_data=copy_data,
        dataset_id=dataset_id,
        style=style,
        vision_insight=vision_insight,
    )
    poster["fallback_poster_url"] = poster.get("poster_url")
    
    # 5. 异步AI生成:调用图片生成大模型,优化海报效果
    image_generator = SophnetImageGenerator()
    if image_generator.enabled:
        try:
            image_task = await image_generator.create_task(
                prompt=poster_service.build_image_generation_prompt(copy_data, vision_insight),
                images=[poster_service.image_data_uri(image_bytes, image.filename or "product.png")],
                negative_prompt=(
                    "低清晰度,文字乱码,错别字,商品变形,商品颜色改变,商品材质改变,商品结构改变,"
                    "新增不存在的配件,虚构品牌logo,虚构功能参数,杂乱背景,水印,多余logo,文字遮挡商品主体"
                ),
                watermark=False,
                save_to_jpeg=False,
            )
            poster["image_task_id"] = image_task.get("taskId")
            poster["image_task_status"] = image_task.get("taskStatus")
            poster["poster_url"] = None  # 异步生成中,暂不返回AI生成地址
        except Exception as e:
            logger.warning(f"图片生成任务创建失败,返回SVG兜底海报: {e}")
    
    # 6. 数据持久化:兜底海报生成成功则存储记录
    if poster.get("poster_url"):
        poster_record = await _save_poster_record(
            db,
            dataset_id=dataset_id,
            poster_url=poster["poster_url"],
            style=style,
            style_name=poster.get("style_name"),
            slogan=poster.get("slogan"),
            status="SUCCEEDED",
        )
        poster["poster_record_id"] = poster_record.id
    
    return ok(poster)

核心思考点:

  • 前置校验:先校验文案是否生成,避免 “无文案的空海报”,保证内容完整性;
  • 分层生成:兜底方案 + 异步优化,兼顾接口响应速度与海报质量;
  • 负向提示词设计:通过精准的 negative prompt 规避 AI 生成的常见问题(如商品变形、文字乱码),提升生成效果;
  • 异常容错:AI 生成任务创建失败时,自动降级为兜底海报,确保接口不报错。
(2)异步任务状态查询:AI 生成结果的闭环管理

为追踪 AI 生成任务的状态,设计了专用的查询接口,并在生成成功后自动更新海报记录:

python

运行

@router.get("/poster-image-task/{task_id}")
async def get_poster_image_task(
    task_id: str,
    dataset_id: str | None = Query(None),
    style: str | None = Query(None),
    style_name: str | None = Query(None),
    slogan: str | None = Query(None),
    db: AsyncSession = Depends(get_db),
):
    image_generator = SophnetImageGenerator()
    output = await image_generator.get_task(task_id)
    results = output.get("results") or []
    first_url = results[0].get("url") if results else None
    poster_url = first_url
    
    # AI生成成功则下载图片并更新记录
    if output.get("taskStatus") == "SUCCEEDED" and first_url and dataset_id:
        try:
            # 下载AI生成的图片到本地存储,保证素材可访问性
            poster_url = await image_generator.save_result_image(
                first_url,
                dataset_id=dataset_id,
                task_id=task_id,
            )
            # 更新海报记录,替换为AI生成的地址
            poster_record = await _save_poster_record(
                db,
                dataset_id=dataset_id,
                poster_url=poster_url,
                source_url=first_url,
                style=style,
                style_name=style_name,
                slogan=slogan,
                task_id=task_id,
                status="SUCCEEDED",
            )
        except Exception as e:
            logger.warning(f"AI海报下载到本地失败,返回原始URL: {e}")
    
    return ok({
        "task_id": output.get("taskId") or task_id,
        "task_status": output.get("taskStatus"),
        "poster_url": poster_url,
        "source_poster_url": first_url,
        "poster_record": _poster_payload(poster_record) if "poster_record" in locals() else None,
        "results": results,
        "usage": output.get("usage"),
    })

核心思考点:

  • 素材本地化:将 AI 生成的图片下载到本地存储,避免依赖第三方链接失效,保障素材长期可用;
  • 记录更新:复用_save_poster_record方法,支持 “新增 / 更新” 逻辑(若已有 task_id 对应的记录则更新,否则新增),避免数据冗余;
  • 状态透传:返回 task_status、usage 等信息,便于前端展示进度与成本统计。
(3)海报管理接口:全生命周期的工程化支撑

为适配业务端的素材管理需求,设计了列表查询、封面设置、删除等接口,以设置封面为例:

python

运行

@router.post("/posters/{poster_id}/cover")
async def set_marketing_poster_cover(poster_id: str, db: AsyncSession = Depends(get_db)):
    # 1. 校验海报存在性
    result = await db.execute(select(MarketingPoster).where(MarketingPoster.id == poster_id))
    poster = result.scalar_one_or_none()
    if not poster:
        raise HTTPException(404, "广告图不存在")
    
    # 2. 重置同商品下所有海报的封面标识
    await db.execute(
        update(MarketingPoster)
        .where(MarketingPoster.dataset_id == poster.dataset_id)
        .values(is_cover=0)
    )
    poster.is_cover = 1
    
    # 3. 更新商品数据集的封面地址,联动商品展示
    dataset_result = await db.execute(select(Dataset).where(Dataset.id == poster.dataset_id))
    dataset = dataset_result.scalar_one_or_none()
    if dataset:
        dataset.display_image_url = poster.poster_url
    
    await db.commit()
    await db.refresh(poster)
    return ok(_poster_payload(poster))

核心思考点:

  • 原子性操作:先重置同商品下所有海报的封面标识,再设置目标海报为封面,避免多个封面的逻辑冲突;
  • 联动更新:同步更新 Dataset 的 display_image_url,确保商品列表页的封面展示与海报设置一致;
  • 数据一致性:通过数据库事务(commit)保障操作的原子性,避免部分更新导致的数据不一致。

三、工程化优化:从功能实现到生产可用

1. 异步任务的稳定性保障

  • 异常捕获:在_run_marketing等异步任务中增加全局异常捕获,记录错误日志并更新任务状态,避免任务静默失败;
  • 超时控制:为 AI 生成任务设置超时时间,超时后自动降级为兜底海报;
  • 重试机制:对图片下载、任务查询等关键步骤增加重试逻辑,提升容错性。

2. 性能优化

  • 索引设计:为dataset_idtask_id等高频查询字段添加索引,提升海报列表查询效率;
  • 数据序列化:自定义_poster_payload方法,按需序列化海报字段,避免返回冗余数据;
  • 异步数据库操作:基于 SQLAlchemy AsyncSession 实现全异步数据库交互,提升接口并发能力。

3. 可观测性建设

  • 日志埋点:在 AI 生成、图片下载、海报存储等关键步骤添加日志,记录任务 ID、数据集 ID 等关键信息,便于问题排查;
  • 状态监控:暴露海报生成成功率、AI 任务耗时等指标,支持监控告警;
  • 异常兜底:所有外部依赖(如 AI 模型、存储服务)失败时,均有明确的降级策略,保障核心功能可用。

四、总结

本次升级完成了从 “营销文案生成” 到 “广告海报生成” 的全链路闭环,核心工作量体现在:

  1. 多模态融合层:实现视觉大模型与文本文案的协同分析,完成商品卖点的视觉 + 文本双维度提取;
  2. 工程化落地层:设计异步生成 + 兜底降级的方案,解决 AI 生成耗时、成功率波动的问题;
  3. 数据管理层:构建海报的全生命周期管理体系,支持存储、查询、封面设置、删除等核心操作;
  4. 兼容性保障:兼顾接口响应速度与生成质量,适配电商场景的实际使用需求。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐