搭建 pipeline framework
This commit is contained in:
parent
5eec48a889
commit
90fe8dbd11
@ -4,13 +4,13 @@
|
||||
"color": "#000000"
|
||||
},
|
||||
"layer6_title_content": {
|
||||
"content": "世界读书日",
|
||||
"content": "国庆盛典",
|
||||
"font_name": "FZLanTingHei-ExtraBold-GB",
|
||||
"color": "#000000"
|
||||
},
|
||||
"layer7_subtitle_content": {
|
||||
"content": "阅古今中外,启智慧之门",
|
||||
"font_name": "Adobe Song Std L",
|
||||
"color": "#4F4F4F"
|
||||
"content": "共庆华诞,同绘未来",
|
||||
"font_name": "SimHei",
|
||||
"color": "#555555"
|
||||
}
|
||||
}
|
5
outputs/prompts.yaml
Normal file
5
outputs/prompts.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
description: "Generated prompt based on user input: \u7AEF\u5348\u8282\u6D77\u62A5\
|
||||
\uFF0C\u5305\u542B\u80CC\u666F\u3001\u6D3B\u52A8\u4EAE\u70B9\u548C\u56FE\u6807"
|
||||
generated_at: 03:05 PM HKT on Monday, June 09, 2025
|
||||
user_prompt: "\u7AEF\u5348\u8282\u6D77\u62A5\uFF0C\u5305\u542B\u80CC\u666F\u3001\u6D3B\
|
||||
\u52A8\u4EAE\u70B9\u548C\u56FE\u6807"
|
@ -1,11 +1,9 @@
|
||||
# 基础依赖
|
||||
python-dotenv # 用于加载.env文件中的环境变量
|
||||
pyyaml # 用于解析YAML配置文件
|
||||
|
||||
# API客户端
|
||||
openai == 1.82.1 # 用于调用OpenAI/Moonshot/DeepSeek API
|
||||
|
||||
# 图像处理
|
||||
Pillow # PIL库,用于基础图像处理
|
||||
psd-tools # 用于PSD文件的创建和操作
|
||||
|
||||
fastapi>=0.68.0
|
||||
uvicorn>=0.18.0
|
||||
python-dotenv>=0.21.0
|
||||
pyyaml>=6.0
|
||||
websocket-client>=1.5.0
|
||||
requests>=2.28.0
|
||||
pillow>=9.0.0
|
||||
psd-tools>=1.9.0
|
||||
openai>=1.0.0
|
||||
|
BIN
scripts/__pycache__/generate_layout.cpython-311.pyc
Normal file
BIN
scripts/__pycache__/generate_layout.cpython-311.pyc
Normal file
Binary file not shown.
BIN
scripts/__pycache__/generate_text.cpython-311.pyc
Normal file
BIN
scripts/__pycache__/generate_text.cpython-311.pyc
Normal file
Binary file not shown.
@ -98,6 +98,8 @@ def call_deepseek(
|
||||
raise
|
||||
raise Exception("达到最大重试次数,API 调用失败")
|
||||
|
||||
|
||||
|
||||
def generate_vue_code(prompt=None):
|
||||
prompt = (
|
||||
"生成一个Vue组件代码,用于端午节活动海报,包含以下部分并指定排版位置:"
|
||||
@ -123,6 +125,5 @@ def save_code(code, file_path="../outputs/generated_code.vue"):
|
||||
f.write(code)
|
||||
|
||||
if __name__ == "__main__":
|
||||
vue_code = generate_vue_code()
|
||||
save_code(vue_code)
|
||||
save_code(generate_vue_code())
|
||||
print("Vue组件代码已生成并保存到outputs/generated_code.vue")
|
@ -249,7 +249,7 @@ if __name__ == "__main__":
|
||||
# user_input_example2 = "我要一个端午节的海报,中国风,深色背景。"
|
||||
# user_input_example3 = "世界读书日海报,简约风格,元素包含打开的书和思考的人。"
|
||||
|
||||
load_config_from_file("./configs/font.yaml")
|
||||
load_config_from_file("../configs/font.yaml")
|
||||
|
||||
user_input = input("请输入您的海报需求:")
|
||||
|
||||
@ -260,7 +260,7 @@ if __name__ == "__main__":
|
||||
if suggestions:
|
||||
# print("\n--- 最终输出给调用者的内容 ---")
|
||||
# print(json.dumps(suggestions, indent=2, ensure_ascii=False))
|
||||
output_folder = "outputs"
|
||||
output_folder = "../outputs"
|
||||
output_file = os.path.join(output_folder, "poster_content.json")
|
||||
try:
|
||||
with open(output_file, "w", encoding="utf-8") as file:
|
||||
|
175
scripts/run_pipeline.py
Normal file
175
scripts/run_pipeline.py
Normal file
@ -0,0 +1,175 @@
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
import yaml
|
||||
from generate_layout import call_deepseek, generate_vue_code, save_code
|
||||
from generate_text import load_config_from_file, get_poster_content_suggestions
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.responses import FileResponse
|
||||
from ComfyUI.flux_con import comfyui_img_info # 导入已实现的图像生成函数
|
||||
|
||||
# 配置路径
|
||||
config_paths = {
|
||||
"font": "../configs/font.yaml",
|
||||
"output_folder": "../outputs/",
|
||||
}
|
||||
|
||||
# 加载环境变量和配置
|
||||
load_dotenv()
|
||||
app = FastAPI()
|
||||
|
||||
with open(config_paths["font"], "r", encoding="utf-8") as f:
|
||||
fonts_config = yaml.safe_load(f)
|
||||
|
||||
|
||||
# 假设的 DeepSeek 提示词分析接口
|
||||
def llm_user_analysis(user_input):
|
||||
# 占位符实现,模拟 DeepSeek 分析
|
||||
if not user_input:
|
||||
user_input = "端午节海报,包含背景和活动亮点"
|
||||
return {
|
||||
"analyzed_prompt": user_input,
|
||||
"keywords": ["端午节", "背景", "活动亮点"],
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"batch_size": 2
|
||||
}
|
||||
|
||||
|
||||
# 假设的 PSD 合成接口(占位符)
|
||||
def create_psd_from_images(img_list, vue_layout_path, output_path):
|
||||
print(f"Generating PSD from {img_list} using layout {vue_layout_path} to {output_path}")
|
||||
return None
|
||||
|
||||
|
||||
# 动态生成 prompts.yaml 基于用户输入
|
||||
def generate_prompts_yaml(user_input):
|
||||
prompts_data = {
|
||||
"user_prompt": user_input,
|
||||
"generated_at": "02:50 PM HKT on Monday, June 09, 2025",
|
||||
"description": f"Generated prompt based on user input: {user_input}"
|
||||
}
|
||||
prompts_yaml_path = os.path.join(config_paths["output_folder"], "prompts.yaml")
|
||||
with open(prompts_yaml_path, "w", encoding="utf-8") as f:
|
||||
yaml.dump(prompts_data, f)
|
||||
return prompts_yaml_path
|
||||
|
||||
|
||||
# 生成动态Vue排版Prompt,支持多张图片
|
||||
def generate_layout_prompt(user_input_analysis_result, parse_imglist):
|
||||
width = user_input_analysis_result["width"]
|
||||
height = user_input_analysis_result["height"]
|
||||
|
||||
# 构造图片信息字符串
|
||||
images_info = "\n".join(
|
||||
[f"- {img['picture_name']} ({img['picture_description']})" for img in parse_imglist]
|
||||
)
|
||||
|
||||
# 调用DeepSeek生成动态排版Prompt
|
||||
system_prompt = "你是一个擅长前端开发的AI,专注于生成Vue.js代码。给定组件尺寸和多张图片信息,自动分析并建议合理的排版位置,使用absolute定位,仅关注位置,不包含样式描述。"
|
||||
prompt = (
|
||||
f"根据组件尺寸 {width}x{height}px 和以下图片信息,生成一个Vue组件代码的Prompt,包含以下部分并指定动态排版位置:\n"
|
||||
f"图片信息:\n{images_info}\n"
|
||||
f"要求:\n"
|
||||
f"1. 背景图层:使用第一张图片,占据整个组件区域。"
|
||||
f"2. 主体图层:包含标题和副标题,位于合适位置,居中。"
|
||||
f"3. 活动亮点:使用剩余图片,位于合适位置,居中,使用网格或分层布局展示所有图片。"
|
||||
f"4. 页脚:包含主办单位信息和logo图片,位于合适位置,居中。"
|
||||
f"组件尺寸为{width}x{height}px,布局使用absolute定位,仅关注排版位置。"
|
||||
f"返回一个格式化的Prompt字符串,供生成Vue代码使用。"
|
||||
)
|
||||
|
||||
result, _ = call_deepseek(prompt=prompt, system_prompt=system_prompt, temperature=0.4)
|
||||
return result
|
||||
|
||||
|
||||
# 一键执行流程
|
||||
def run_pipeline(user_input=None):
|
||||
"""
|
||||
自动执行海报生成流程:
|
||||
1. 使用 llm_user_analysis 分析用户提示词得到 user_input_analysis_result。
|
||||
2. 使用 comfyui_img_info 生成 parse_imglist 列表。
|
||||
3. 根据 user_input_analysis_result 生成文案 suggestions。
|
||||
4. 结合 parse_imglist 和动态生成的 prompts.yaml 生成 Vue 排版文件。
|
||||
5. 将 parse_imglist 组装成 img_list,调用 create_psd_from_images 合成 PSD。
|
||||
:param user_input: 用户提供的提示词(可选,默认使用占位符)
|
||||
:return: 合成海报的路径
|
||||
"""
|
||||
# 步骤 1: 加载配置
|
||||
load_config_from_file(generate_prompts_yaml(user_input)) # 动态生成 prompts.yaml
|
||||
|
||||
# 步骤 2: 分析用户提示词
|
||||
user_input_analysis_result = llm_user_analysis(user_input)
|
||||
print(f"Analyzed result: {user_input_analysis_result}")
|
||||
|
||||
# 步骤 3: 生成图片信息
|
||||
system_prompt = user_input_analysis_result["analyzed_prompt"]
|
||||
parse_imglist = comfyui_img_info(user_input_analysis_result, system_prompt)
|
||||
print(f"Generated image list: {parse_imglist}")
|
||||
|
||||
# 步骤 4: 生成文案
|
||||
suggestions = get_poster_content_suggestions(user_input_analysis_result)
|
||||
print(f"Generated suggestions: {suggestions}")
|
||||
|
||||
# 步骤 5: 生成 Vue 排版(动态Prompt,支持多张图片)
|
||||
dynamic_prompt = generate_layout_prompt(user_input_analysis_result, parse_imglist)
|
||||
print(f"Generated dynamic layout prompt: {dynamic_prompt}")
|
||||
vue_code = generate_vue_code(dynamic_prompt)
|
||||
save_code(vue_code, file_path=os.path.join(config_paths["output_folder"], "generated_code.vue"))
|
||||
print("Generated Vue layout")
|
||||
|
||||
# 步骤 6: 合成 PSD
|
||||
img_list = [(pic["picture_name"], pic["picture_type"]) for pic in parse_imglist]
|
||||
create_psd_from_images(
|
||||
img_list=img_list,
|
||||
vue_layout_path=os.path.join(config_paths["output_folder"], "generated_code.vue"),
|
||||
output_path=os.path.join(config_paths["output_folder"], "final_poster.psd")
|
||||
)
|
||||
print("Generated PSD file")
|
||||
|
||||
return os.path.join(config_paths["output_folder"], "final_poster.png") # 假设 PNG 作为最终输出
|
||||
|
||||
|
||||
# 本地运行函数
|
||||
def run_local_pipeline(user_input=None):
|
||||
"""
|
||||
本地运行整个管道流程,输出结果到控制台和文件系统。
|
||||
:param user_input: 用户提供的提示词(可选,默认使用占位符)
|
||||
:return: None,打印运行结果
|
||||
"""
|
||||
print(f"Starting local pipeline with input: {user_input}")
|
||||
output_path = run_pipeline(user_input)
|
||||
print(f"Pipeline completed. Results saved to:")
|
||||
print(f"- Vue layout: {os.path.join(config_paths['output_folder'], 'generated_code.vue')}")
|
||||
print(f"- PSD file: {os.path.join(config_paths['output_folder'], 'final_poster.psd')}")
|
||||
print(f"- Final poster (placeholder): {output_path}")
|
||||
print("Check the outputs/ directory for generated files.")
|
||||
|
||||
|
||||
# API 端点
|
||||
@app.get("/generate_poster")
|
||||
async def generate_poster(user_input: str = None):
|
||||
output_path = run_pipeline(user_input)
|
||||
return FileResponse(output_path, media_type="image/png")
|
||||
|
||||
|
||||
# 可选 API 端点
|
||||
@app.get("/generate_poster_psd")
|
||||
async def generate_poster_psd(user_input: str = None):
|
||||
try:
|
||||
output_path = run_pipeline(user_input)
|
||||
return {
|
||||
"image_url": output_path,
|
||||
"font_info": fonts_config,
|
||||
"psd_path": os.path.join(config_paths["output_folder"], "final_poster.psd")
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"PSD generation failed: {str(e)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
|
||||
# 启动本地运行(可选)
|
||||
run_local_pipeline("端午节海报,包含背景、活动亮点和图标")
|
||||
# 或者启动API服务器
|
||||
# uvicorn.run(app, host="0.0.0.0", port=8000)
|
208
scripts/run_pipline.md
Normal file
208
scripts/run_pipline.md
Normal file
@ -0,0 +1,208 @@
|
||||
# 自动执行流程说明文档
|
||||
|
||||
本流程通过多个脚本与配置文件协作,自动生成海报的排版、文案、图像并输出 PSD 文件,最终通过 API 提供服务。
|
||||
|
||||
---
|
||||
|
||||
## 一、自动执行流程的步骤
|
||||
|
||||
### 步骤 1: 配置加载
|
||||
|
||||
**目标**:加载必要的配置信息(如 API 密钥、字体规则、Prompt 模板)。
|
||||
|
||||
**涉及文件**:
|
||||
- `.env`:加载 DeepSeek API 密钥等环境变量。
|
||||
- `configs/fonts.yaml`:加载字体与配色规则。
|
||||
- `configs/prompts.json`:加载图像生成 Prompt 模板。
|
||||
|
||||
**过程**:
|
||||
- 使用 `dotenv` 加载 `.env` 中的 `DEEPSEEK_API_KEY`。
|
||||
- 使用 `yaml` 或 `json` 库加载 `fonts.yaml` 和 `prompts.json`。
|
||||
|
||||
**输出**:配置对象(字典或类),供后续步骤使用。
|
||||
|
||||
---
|
||||
|
||||
### 步骤 2: 排版生成
|
||||
|
||||
**目标**:使用 LLM 生成海报的排版结构(Vue 组件)。
|
||||
|
||||
**涉及文件**:
|
||||
- `scripts/generate_layout.py`:调用 DeepSeek API 生成 Vue 组件代码。
|
||||
|
||||
**过程**:
|
||||
- 调用 `generate_layout.py` 中的 `generate_vue_code` 函数。
|
||||
- 传入从 `prompts.json` 动态读取的 Prompt,结合字体规则生成 Vue 代码。
|
||||
|
||||
**输出**:Vue 组件代码,保存为 `outputs/generated_code.vue`。
|
||||
|
||||
---
|
||||
|
||||
### 步骤 3: 文案生成
|
||||
|
||||
**目标**:生成海报文案内容(标题、副标题、活动描述等)。
|
||||
|
||||
**涉及文件**:
|
||||
- `scripts/generate_text.py`:调用 LLM 生成文案。
|
||||
|
||||
**过程**:
|
||||
- 调用脚本生成端午节相关文案(如“端午安康”、“包粽子比赛”)。
|
||||
- 文案可按 `prompts.json` 中模板动态调整。
|
||||
|
||||
**输出**:文案内容(字符串或字典),供后续步骤使用。
|
||||
|
||||
---
|
||||
|
||||
### 步骤 4: 图像生成
|
||||
|
||||
**目标**:使用 ComfyUI 生成海报图层。
|
||||
|
||||
**涉及文件**:
|
||||
- `comfyui_flows/layer_generation.json`:定义图层生成流程。
|
||||
- `scripts/generate_images.py`:调用 ComfyUI API 生成图层。
|
||||
- `images/`:存储背景、前景、文字图层。
|
||||
|
||||
**过程**:
|
||||
- 运行 `generate_images.py`,加载 `layer_generation.json`。
|
||||
- 根据排版与文案生成:
|
||||
- `background.png`
|
||||
- `foreground.png`
|
||||
- `text_overlay.png`
|
||||
|
||||
**输出**:图像文件保存到 `images/` 目录。
|
||||
|
||||
---
|
||||
|
||||
### 步骤 5: 合成海报
|
||||
|
||||
**目标**:将图层合成为最终海报。
|
||||
|
||||
**涉及文件**:
|
||||
- `scripts/compose_poster.py`:合成图层脚本。
|
||||
- `outputs/final_poster.png`:合成结果。
|
||||
|
||||
**过程**:
|
||||
- 读取 `generated_code.vue` 中的排版位置信息。
|
||||
- 使用 `image_utils.py` 对图层进行合成。
|
||||
|
||||
**输出**:`final_poster.png`
|
||||
|
||||
---
|
||||
|
||||
### 步骤 6: 导出 PSD 文件
|
||||
|
||||
**目标**:导出 PSD 文件以便后期修改。
|
||||
|
||||
**涉及文件**:
|
||||
- `scripts/export_psd.py`:PSD 导出脚本。
|
||||
- `outputs/final_poster.psd`:导出的 PSD 文件。
|
||||
|
||||
**过程**:
|
||||
- 将 `final_poster.png` 转换为 PSD。
|
||||
- 保留图层信息。
|
||||
|
||||
**输出**:`final_poster.psd`
|
||||
|
||||
---
|
||||
|
||||
### 步骤 7: 提供前端接口
|
||||
|
||||
**目标**:将结果通过 API 提供给前端调用。
|
||||
|
||||
**涉及文件**:
|
||||
- `run_pipeline.py`:协调整体流程并定义 API 接口。
|
||||
|
||||
**过程**:
|
||||
- 使用 `FastAPI` 或 `Flask` 创建端点(如 `/generate_poster`)。
|
||||
- 接收前端请求,依次调用上述所有步骤。
|
||||
- 返回最终文件的 URL 或文件流。
|
||||
|
||||
**输出**:HTTP 响应,包含 `final_poster.png` 链接或文件流。
|
||||
|
||||
---
|
||||
|
||||
## 二、如何实现自动执行流程
|
||||
|
||||
### 环境准备
|
||||
|
||||
- **依赖安装**:确保 `requirements.txt` 包含以下依赖:
|
||||
- `openai`
|
||||
- `python-dotenv`
|
||||
- `PyYAML`
|
||||
- `requests`(用于 ComfyUI API 调用)
|
||||
- `Pillow`(图像处理)
|
||||
- `psd-tools`(PSD 导出)
|
||||
|
||||
- **API 密钥配置**:在 `.env` 文件中添加以下字段:
|
||||
```env
|
||||
DEEPSEEK_API_KEY=your_api_key
|
||||
COMFYUI_API_KEY=your_comfyui_key
|
||||
|
||||
```python
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from scripts.generate_layout import generate_vue_code
|
||||
from scripts.generate_text import generate_text # 假设存在
|
||||
from scripts.generate_images import generate_images # 假设存在
|
||||
from scripts.compose_poster import compose_poster # 假设存在
|
||||
from scripts.export_psd import export_psd # 假设存在
|
||||
import yaml
|
||||
import json
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.responses import FileResponse
|
||||
|
||||
# 加载环境变量和配置
|
||||
load_dotenv()
|
||||
app = FastAPI()
|
||||
|
||||
with open("configs/fonts.yaml", "r", encoding="utf-8") as f:
|
||||
fonts_config = yaml.safe_load(f)
|
||||
with open("configs/prompts.json", "r", encoding="utf-8") as f:
|
||||
prompts_config = json.load(f)
|
||||
|
||||
# 一键执行流程
|
||||
def run_pipeline():
|
||||
try:
|
||||
# 步骤 1: 排版生成
|
||||
layout_code = generate_vue_code()
|
||||
with open("../outputs/generated_code.vue", "w", encoding="utf-8") as f:
|
||||
f.write(layout_code)
|
||||
|
||||
# 步骤 2: 文案生成
|
||||
text_content = generate_text(prompts_config.get("text_prompt", ""))
|
||||
|
||||
# 步骤 3: 图像生成
|
||||
generate_images(
|
||||
workflow_path="comfyui_flows/layer_generation.json",
|
||||
text_content=text_content,
|
||||
output_dir="images/"
|
||||
)
|
||||
|
||||
# 步骤 4: 合成海报
|
||||
compose_poster(
|
||||
layout_path="../outputs/generated_code.vue",
|
||||
image_dir="images/",
|
||||
output_path="../outputs/final_poster.png"
|
||||
)
|
||||
|
||||
# 步骤 5: 导出 PSD
|
||||
export_psd(
|
||||
input_path="../outputs/final_poster.png",
|
||||
output_path="../outputs/final_poster.psd"
|
||||
)
|
||||
|
||||
return "../outputs/final_poster.png"
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
# API 端点
|
||||
@app.get("/generate_poster")
|
||||
async def generate_poster():
|
||||
output_path = run_pipeline()
|
||||
return FileResponse(output_path, media_type="image/png")
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
|
||||
```
|
Loading…
Reference in New Issue
Block a user