234 lines
6.2 KiB
Markdown
234 lines
6.2 KiB
Markdown
|
|
# 海报模块 v2 (poster_v2)
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
基于小红书风格的海报生成模块,支持5种布局、5种主题,可与真实图片结合生成美观的营销海报。
|
|||
|
|
|
|||
|
|
## 目录结构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
poster_v2/
|
|||
|
|
├── __init__.py # 入口: PosterFactory, PosterContent, Theme
|
|||
|
|
├── factory.py # PosterFactory 统一生成入口
|
|||
|
|
├── config.py # 配置管理 (从项目统一配置读取)
|
|||
|
|
├── schemas/
|
|||
|
|
│ ├── content.py # PosterContent 数据模型
|
|||
|
|
│ └── theme.py # Theme 主题配置
|
|||
|
|
├── layouts/
|
|||
|
|
│ ├── base.py # BaseLayout 抽象基类
|
|||
|
|
│ ├── hero_bottom.py # 布局A: 大图底部文字
|
|||
|
|
│ ├── overlay_center.py # 布局B: 居中叠加
|
|||
|
|
│ ├── overlay_bottom.py # 布局C: 底部毛玻璃
|
|||
|
|
│ ├── split_vertical.py # 布局D: 左图右文
|
|||
|
|
│ └── card_float.py # 布局E: 悬浮卡片
|
|||
|
|
├── renderers/
|
|||
|
|
│ ├── text.py # 文字渲染器
|
|||
|
|
│ ├── shape.py # 形状渲染器
|
|||
|
|
│ └── effect.py # 效果渲染器
|
|||
|
|
└── themes/
|
|||
|
|
└── __init__.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 使用方式
|
|||
|
|
|
|||
|
|
### 基础用法
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from poster_v2 import PosterFactory, PosterContent
|
|||
|
|
|
|||
|
|
factory = PosterFactory()
|
|||
|
|
|
|||
|
|
# 直接生成
|
|||
|
|
poster = factory.generate(
|
|||
|
|
layout="hero_bottom",
|
|||
|
|
theme="ocean",
|
|||
|
|
title="景点标题",
|
|||
|
|
subtitle="副标题描述",
|
|||
|
|
price="¥199",
|
|||
|
|
tags=["周末游", "亲子"]
|
|||
|
|
)
|
|||
|
|
poster.save("output.png")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 带真实图片
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from PIL import Image
|
|||
|
|
|
|||
|
|
img = Image.open("photo.jpg")
|
|||
|
|
content = PosterContent(
|
|||
|
|
title="广东小新疆",
|
|||
|
|
subtitle="绝美秘境等你来",
|
|||
|
|
price="¥0",
|
|||
|
|
image=img
|
|||
|
|
)
|
|||
|
|
poster = factory.generate_from_content(content, layout="hero_bottom", theme="sunset")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 智能推荐布局
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 根据内容特征推荐布局
|
|||
|
|
layout = factory.suggest_layout({"emoji": "🍰"}) # → overlay_bottom
|
|||
|
|
layout = factory.suggest_layout({"features": ["A", "B", "C", "D"]}) # → card_float
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 5种布局
|
|||
|
|
|
|||
|
|
| 布局 | 类名 | 适用场景 | 特点 |
|
|||
|
|
|-----|------|---------|------|
|
|||
|
|
| **hero_bottom** | HeroBottomLayout | 景点、美食、通用 | 大图+底部渐变文字区 |
|
|||
|
|
| **overlay_center** | OverlayCenterLayout | 攻略、活动 | 居中大标题+装饰线 |
|
|||
|
|
| **overlay_bottom** | OverlayBottomLayout | 美食探店 | 底部毛玻璃+emoji支持 |
|
|||
|
|
| **split_vertical** | SplitVerticalLayout | 酒店、民宿 | 左图右文50/50分栏 |
|
|||
|
|
| **card_float** | CardFloatLayout | 精品推荐 | 悬浮白色卡片+阴影 |
|
|||
|
|
|
|||
|
|
## 5种主题
|
|||
|
|
|
|||
|
|
| 主题 | 名称 | 主色 | 适用场景 |
|
|||
|
|
|-----|------|------|---------|
|
|||
|
|
| **ocean** | 深青海洋 | #4A8B8B | 海洋、旅游、清新 |
|
|||
|
|
| **sunset** | 日落暖橙 | #D66853 | 美食、活力、温暖 |
|
|||
|
|
| **peach** | 蜜桃粉 | #D4918A | 甜品、少女、浪漫 |
|
|||
|
|
| **mint** | 薄荷绿 | #6A9B88 | 自然、民宿、健康 |
|
|||
|
|
| **latte** | 拿铁咖啡 | #8B7355 | 咖啡、高级、复古 |
|
|||
|
|
|
|||
|
|
## PosterContent 字段
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|-----|------|------|
|
|||
|
|
| `title` | str | 主标题 (必填) |
|
|||
|
|
| `subtitle` | str | 副标题 |
|
|||
|
|
| `price` | str | 价格 (如 "¥199") |
|
|||
|
|
| `price_suffix` | str | 价格后缀 (如 "/人") |
|
|||
|
|
| `tags` | List[str] | 标签列表 |
|
|||
|
|
| `highlights` | List[str] | 亮点标签 (overlay_bottom) |
|
|||
|
|
| `features` | List[str] | 特色列表 (card_float) |
|
|||
|
|
| `details` | List[str] | 详情列表 |
|
|||
|
|
| `label` | str | 角标 (如 "精选推荐") |
|
|||
|
|
| `emoji` | str | emoji符号 |
|
|||
|
|
| `image` | PIL.Image | 背景图片 |
|
|||
|
|
|
|||
|
|
## 配置
|
|||
|
|
|
|||
|
|
配置优先级:
|
|||
|
|
1. 环境变量 `POSTER_FONT_DIR` / `POSTER_EMOJI_FONT`
|
|||
|
|
2. 项目配置 `config/app.yaml` → `paths.resource.font`
|
|||
|
|
3. 默认值 `assets/font`
|
|||
|
|
|
|||
|
|
## 测试脚本
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 基础测试
|
|||
|
|
python scripts/test_poster_v2.py
|
|||
|
|
|
|||
|
|
# 真实图片测试
|
|||
|
|
python scripts/test_poster_v2_real_image.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
输出目录:
|
|||
|
|
- `result/poster_v2_test/` - 基础测试结果
|
|||
|
|
- `result/poster_v2_real/` - 真实图片测试结果
|
|||
|
|
|
|||
|
|
## API 接口
|
|||
|
|
|
|||
|
|
### 方式1: 智能海报生成 (推荐)
|
|||
|
|
|
|||
|
|
AI 自动生成海报文案,适合只有产品基本信息的场景:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
POST /api/aigc/execute
|
|||
|
|
{
|
|||
|
|
"engine": "poster_smart",
|
|||
|
|
"params": {
|
|||
|
|
"category": "景点",
|
|||
|
|
"name": "正佳极地海洋世界",
|
|||
|
|
"description": "位于广州正佳广场的大型海洋馆",
|
|||
|
|
"price": "199元/人",
|
|||
|
|
"location": "广州天河",
|
|||
|
|
"features": "企鹅馆, 海豚表演, 儿童乐园",
|
|||
|
|
"target_audience": "亲子家庭",
|
|||
|
|
"image_url": "https://...",
|
|||
|
|
|
|||
|
|
// 可选: 覆盖AI推荐
|
|||
|
|
"override_layout": "hero_bottom",
|
|||
|
|
"override_theme": "ocean"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
返回:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"success": true,
|
|||
|
|
"data": {
|
|||
|
|
"image_base64": "...",
|
|||
|
|
"layout": "hero_bottom",
|
|||
|
|
"theme": "ocean",
|
|||
|
|
"generated_content": {
|
|||
|
|
"title": "🐧 正佳海洋世界真的绝了",
|
|||
|
|
"subtitle": "周末带娃去的,企鹅太可爱了!",
|
|||
|
|
"highlights": ["适合遛娃", "出片率高"],
|
|||
|
|
"price": "¥199"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 方式2: 直接海报生成
|
|||
|
|
|
|||
|
|
已有完整文案时使用:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
POST /api/aigc/execute
|
|||
|
|
{
|
|||
|
|
"engine": "poster_generate_v3",
|
|||
|
|
"params": {
|
|||
|
|
"layout": "hero_bottom",
|
|||
|
|
"theme": "ocean",
|
|||
|
|
"content": {
|
|||
|
|
"title": "标题",
|
|||
|
|
"subtitle": "副标题",
|
|||
|
|
"price": "¥199",
|
|||
|
|
"tags": ["周末游", "亲子"]
|
|||
|
|
},
|
|||
|
|
"image_url": "https://..."
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 响应
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"success": true,
|
|||
|
|
"data": {
|
|||
|
|
"image_base64": "...",
|
|||
|
|
"layout": "hero_bottom",
|
|||
|
|
"theme": "ocean"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 服务层直接调用
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from poster_v2 import get_poster_service_v2
|
|||
|
|
|
|||
|
|
service = get_poster_service_v2()
|
|||
|
|
|
|||
|
|
result = service.generate(
|
|||
|
|
layout="hero_bottom",
|
|||
|
|
theme="ocean",
|
|||
|
|
content={"title": "标题", "price": "¥199"},
|
|||
|
|
image_base64="..." # 可选
|
|||
|
|
)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 设计原则
|
|||
|
|
|
|||
|
|
1. **布局与渲染分离** - Layout 负责计算位置,Renderer 负责绘制
|
|||
|
|
2. **动态内容适配** - 内容区域根据文案自动计算高度
|
|||
|
|
3. **主题可配置** - 配色/字体可通过主题切换
|
|||
|
|
4. **单一职责** - 每个布局类只负责一种布局
|