From b554e130252f1ab17cbd34e4f911c87480e7f61f Mon Sep 17 00:00:00 2001 From: jinye_huang Date: Fri, 25 Apr 2025 10:11:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86poster=5Fgen?= =?UTF-8?q?=E7=9A=84=E7=9B=AE=E5=BD=95=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 350 +++++++----------- core/__init__.py | 2 +- core/__pycache__/__init__.cpython-312.pyc | Bin 452 -> 453 bytes core/__pycache__/poster_gen.cpython-312.pyc | Bin 0 -> 37762 bytes core/{posterGen.py => poster_gen.py} | 0 examples/test_image_processing.py | 4 +- examples/test_poster_generator.py | 4 +- main.py | 2 +- poster_config.json | 45 +++ test_poster.py | 232 ++++++++++++ test_topic_content.py | 261 +++++++++++++ topic_content_config.json | 72 ++++ .../tweet_generator.cpython-312.pyc | Bin 29552 -> 29553 bytes utils/tweet_generator.py | 2 +- 14 files changed, 754 insertions(+), 220 deletions(-) create mode 100644 core/__pycache__/poster_gen.cpython-312.pyc rename core/{posterGen.py => poster_gen.py} (100%) create mode 100644 poster_config.json create mode 100644 test_poster.py create mode 100644 test_topic_content.py create mode 100644 topic_content_config.json diff --git a/README.md b/README.md index e634a23..7061e77 100644 --- a/README.md +++ b/README.md @@ -1,260 +1,184 @@ -# 旅游内容创作工具 (Travel Content Creator) +# TravelContentCreator -这是一个基于AI的旅游内容自动生成工具,可以根据景点信息自动生成高质量的旅游推文和宣传海报。 +TravelContentCreator是一个用于自动化生成旅游内容和宣传海报的系统。该系统利用AI技术生成景点选题、撰写文章内容并制作相应的宣传海报。 ## 功能特点 -- **自动选题生成**:根据提供的景点信息和配置的提示词模板,自动生成吸引人的旅游选题 -- **内容创作**:基于选题和配置的提示词模板,自动生成文字内容(标题、正文) -- **海报制作**:结合景点图片和生成的文字内容,自动创建精美的宣传海报 -- **批量处理**:支持一次性生成多个选题和多个变体内容 -- **模块化设计**:核心功能(配置加载、提示词管理、AI交互、选题、内容生成、海报制作)分离,方便维护和扩展 -- **配置驱动**:通过配置文件集中管理所有运行参数 +- 自动生成旅游景点选题(包括目标受众、写作风格等) +- 根据选题生成详细的旅游文章内容 +- 为生成的文章制作美观的宣传海报 +- 支持多种写作风格和目标受众需求 +- 文件模糊匹配功能,增强系统健壮性 +- 模块化设计,可单独使用选题、内容生成或海报生成功能 -## 新功能: 流式输出处理 +## 目录结构 -TravelContentCreator 现已支持三种流式输出处理方法,提供了更灵活的 AI 文本生成体验: +``` +TravelContentCreator/ +├── core/ # 核心功能模块 +├── utils/ # 工具类和辅助函数 +├── genPrompts/ # 生成提示词 +│ ├── Style/ # 风格提示词 +│ ├── Demand/ # 需求提示词 +│ └── Refer/ # 参考提示词 +├── SelectPrompt/ # 选题提示词 +├── resource/ # 资源文件 +├── main.py # 主程序 +├── test_topic_content.py # 选题和内容生成测试脚本 +├── test_poster.py # 海报生成测试脚本 +├── topic_content_config.json # 选题和内容生成配置 +├── poster_config.json # 海报生成配置 +└── poster_gen_config.json # 主程序配置 +``` -- **同步流式响应**: 使用流式 API 但返回完整响应 -- **回调式流式响应**: 通过回调函数处理每个文本块 -- **异步流式响应**: 使用异步生成器返回文本流 - -这些功能大大提升了长文本生成的用户体验和系统响应性。 - -详细文档请参阅: -- [流式处理文档](docs/streaming.md) -- [流式处理演示](examples/test_stream.py) - -## 快速开始 - -### 1. 环境准备 +## 安装 +1. 克隆仓库 ```bash -# 克隆项目 -git clone https://github.com/yourusername/TravelContentCreator.git +git clone [仓库URL] cd TravelContentCreator - -# 安装依赖 (假设有requirements.txt文件) -# pip install -r requirements.txt -# 或者手动安装 -pip install numpy pandas opencv-python pillow requests tqdm ``` -### 2. 配置设置 +2. 安装依赖 +```bash +pip install -r requirements.txt +``` + +3. 配置环境 + - 确保安装了Python 3.6+ + - 配置好AI模型API(本系统默认使用QwenAPI) + - 准备好必要的素材和资源文件 + +## 使用说明 + +### 1. 主程序 + +主程序可以执行完整的流程,包括选题生成、内容生成和海报生成: ```bash -# 复制示例配置(选择一个或从基础开始) -cp configs/basic_config.json poster_gen_config.json - -# 编辑配置文件 -vim poster_gen_config.json -# 必须修改:api_url, api_key, image_base_dir +python main.py [--config CONFIG_PATH] [--run_id RUN_ID] [--topics_file TOPICS_FILE] [--debug] ``` -### 3. 运行系统 +参数说明: +- `--config`: 配置文件路径,默认为`poster_gen_config.json` +- `--run_id`: 自定义运行ID,用于区分不同批次的生成结果 +- `--topics_file`: 预生成的选题文件路径,如果提供则跳过选题生成步骤 +- `--debug`: 启用调试级别日志 + +### 2. 测试选题和内容生成 + +使用专门的测试脚本运行选题和内容生成模块: ```bash -# 完整流程(从选题到海报生成) -python main.py - -# 或分阶段执行 (使用默认配置) -python examples/run_step1_topics.py -# 记下输出的Run ID -python examples/run_step2_content_posters.py YOUR_RUN_ID - -# 使用特定配置运行 -# python main.py --config configs/social_media_config.json +python test_topic_content.py [--config CONFIG_PATH] [--run_id RUN_ID] [--topics_file TOPICS_FILE] [--debug] ``` -### 4. 查看结果 +参数说明: +- `--config`: 配置文件路径,默认为`topic_content_config.json` +- `--run_id`: 自定义运行ID +- `--topics_file`: 预生成的选题文件路径,如果提供则跳过选题生成 +- `--debug`: 启用调试级别日志 + +### 3. 测试海报生成 + +使用专门的测试脚本运行海报生成模块: ```bash -# 结果保存在配置的output_dir目录下(默认为./result/) -ls -la ./result/最新的Run_ID/ +python test_poster.py --topics_file TOPICS_FILE [--config CONFIG_PATH] [--topic_index TOPIC_INDEX] [--run_id RUN_ID] [--debug] ``` -## 核心组件说明 +参数说明: +- `--topics_file`: 必需的选题JSON文件路径,用于获取海报生成的主题数据 +- `--config`: 配置文件路径,默认为`poster_config.json` +- `--topic_index`: 要生成海报的特定选题索引,如果未提供则为所有选题生成海报 +- `--run_id`: 自定义运行ID +- `--debug`: 启用调试级别日志 -项目采用模块化设计,主要包含以下组件: +## 配置文件说明 -- **主流程协调器** (`main.py`): 负责加载配置并协调执行整个生成流程 -- **AI交互模块** (`core/ai_agent.py`): 封装与大语言模型的通信 -- **选题生成器** (`utils/tweet_generator.py`): 生成旅游选题 -- **内容生成器** (`core/contentGen.py`): 处理内容创作 -- **海报制作器** (`core/posterGen.py`): 合成文字和图片,生成最终海报 - -## 资源准备指南 - -### 1. 景点信息文件 - -在 `resource/Object/` 目录创建景点信息文件,示例格式: - -``` -景点名称:泰宁古城 -位置:福建省三明市泰宁县 -简介:泰宁古城始建于宋代... -特色:古城墙、古街巷... -历史:泰宁古城有着悠久的历史... -适合游客:喜欢历史文化的游客、摄影爱好者 -建议游览时间:2-3小时 -最佳季节:春季和秋季 -``` - -> **提示**:景点信息越详细,生成的内容质量越高 - -### 2. 图片资源结构 - -图片资源应按以下结构组织(可通过配置自定义目录名): - -``` -/ # 配置中的图片根目录 -├── 相机/ # 存放原始照片 (camera_image_subdir) -│ ├── 泰宁古城/ -│ │ ├── 图片1.jpg -│ │ ├── 图片2.jpg -│ │ └── description.txt (可选的图片描述) -│ └── 其他景点/ -└── modify/ # 存放处理后的图片 (modify_image_subdir) - ├── 泰宁古城/ - │ ├── 图片1.jpg - │ └── ... - └── 其他景点/ -``` - -> **重要**:确保每个景点的图片目录名与景点信息文件中的名称匹配。海报生成默认从 `modify/` 目录选取图片。 - -## 配置文件详解 - -`poster_gen_config.json` 是系统的核心配置文件,包含以下主要配置项: - -### 基础配置 +### 选题和内容生成配置 (topic_content_config.json) ```json { - "date": "5月15日", // 日期标记,用于提示词 - "num": 5, // 生成选题数量 - "variants": 3 // 每个选题生成的变体数量 + "date": "5月15日, 5月16日, 5月17日, 6月1日", // 选题日期 + "num": 2, // 生成选题数量 + "variants": 1, // 每个选题的变体数量 + "topic_temperature": 0.2, // 选题生成的temperature参数 + "content_temperature": 0.3, // 内容生成的temperature参数 + "model": "qwenQWQ", // 使用的AI模型 + "api_url": "http://localhost:8000/v1/", // API地址 + "api_key": "EMPTY", // API密钥 + "topic_system_prompt": "./SelectPrompt/systemPrompt.txt", // 选题系统提示词路径 + "topic_user_prompt": "./SelectPrompt/userPrompt.txt", // 选题用户提示词路径 + "content_system_prompt": "./genPrompts/systemPrompt.txt", // 内容系统提示词路径 + "prompts_config": [ // 提示词配置 + { + "type": "Style", // 风格提示词 + "file_path": [...] // 风格提示词文件路径列表 + }, + { + "type": "Demand", // 需求提示词 + "file_path": [...] // 需求提示词文件路径列表 + }, + ... + ], + "resource_dir": [ // 资源目录配置 + { + "type": "Object", // 对象类型 + "file_path": [...] // 对象文件路径列表 + }, + ... + ] } ``` -### AI模型配置 +### 海报生成配置 (poster_config.json) ```json { - "model": "qwen", // 使用的模型名称 - "api_url": "http://localhost:8000/v1/", // API端点 - "api_key": "YOUR_API_KEY", // API密钥 - "topic_temperature": 0.2, // 选题生成的随机性 - "content_temperature": 0.3 // 内容生成的随机性 + "variants": 1, // 每个选题的变体数量 + "model": "qwenQWQ", // 使用的AI模型 + "api_url": "http://localhost:8000/v1/", // API地址 + "api_key": "EMPTY", // API密钥 + "poster_content_system_prompt": "./genPrompts/poster_content_systemPrompt.txt", // 海报内容系统提示词路径 + "resource_dir": [...], // 资源目录配置 + "output_dir": "./result", // 输出目录 + "image_base_dir": "...", // 图片基础目录 + "poster_assets_base_dir": "...", // 海报素材基础目录 + "poster_target_size": [900, 1200], // 海报目标尺寸 + "text_possibility": 0.3, // 文本可能性 + "img_frame_possibility": 0.7, // 图像框可能性 + "text_bg_possibility": 0 // 文本背景可能性 } ``` -### 资源路径配置 +## 结果输出 -```json -{ - "resource_dir": [ // 景点信息资源 - { - "type": "Object", - "num": 3, - "file_path": [ - "./resource/Object/景点信息-泰宁古城.txt", - "./resource/Object/景点信息-尚书第.txt" - ] - } - ], - "image_base_dir": "/path/to/your/image/directory", // 图片根目录 - "camera_image_subdir": "相机", // 原始照片子目录 - "modify_image_subdir": "modify" // 处理后图片子目录 -} -``` +生成的结果保存在配置文件中指定的`output_dir`目录下,按照`run_id`组织。每次运行的结果包括: -### 提示词配置 +- 选题文件:`tweet_topic_{run_id}.json` +- 选题使用的提示词:`tweet_prompt_{run_id}.txt` +- 文章内容:分目录保存在`{run_id}/{topic_index}_{variant_index}/article.json` +- 海报图像:保存在`{run_id}/{topic_index}_{variant_index}/poster/poster.jpg` +- 拼贴图像:保存在`{run_id}/{topic_index}_{variant_index}/collage_img/` -```json -{ - "topic_system_prompt": "./SelectPrompt/systemPrompt.txt", - "topic_user_prompt": "./SelectPrompt/userPrompt.txt", - "content_system_prompt": "./genPrompts/systemPrompt.txt", - "prompts_dir": "./genPrompts" -} -``` +## 自定义扩展 -### 输出配置 +系统各部分设计为模块化,您可以: -```json -{ - "output_dir": "./result", // 输出目录 - "poster_target_size": [900, 1200], // 海报尺寸 - "text_possibility": 0.3 // 文字元素出现概率 -} -``` +1. 添加新的风格提示词到`genPrompts/Style/`目录 +2. 添加新的需求提示词到`genPrompts/Demand/`目录 +3. 添加新的景点资源到`resource/Object/`目录 +4. 修改AI模型参数以适应不同生成需求 +5. 自定义海报生成的尺寸和样式 -## 配置示例 +## 注意事项 -本项目提供了多种预设配置文件,适用于不同场景。这些配置文件位于 `configs/` 目录下: +- 确保提示词文件和资源文件的编码为UTF-8 +- API密钥应妥善保管,建议使用环境变量或外部配置 +- 图像生成需要足够的系统资源,建议在性能良好的设备上运行 +- 文件模糊匹配功能可以处理一些文件名不完全匹配的情况,但建议尽量保持文件名规范 -- **基础配置** (`configs/basic_config.json`): 适合初次使用和测试 -- **OpenAI配置** (`configs/openai_config.json`): 使用OpenAI API的配置 -- **高质量配置** (`configs/high_quality_config.json`): 更高质量的生成设置 -- **批量处理配置** (`configs/batch_processing_config.json`): 处理大量景点信息 -- **社交媒体配置** (`configs/social_media_config.json`): 针对多个社交平台优化 -- **本地LLM配置** (`configs/local_llm_config.json`): 使用本地部署的LLM模型 +## 贡献 -使用示例配置: - -```bash -# 复制适合您场景的配置 -cp configs/social_media_config.json poster_gen_config.json - -# 按需修改配置 -vim poster_gen_config.json -``` - -详细说明请参阅 `configs/README.md` 文件。 - -## 高级使用指南 - -### 自定义提示词 - -编辑 `SelectPrompt/` 和 `genPrompts/` 目录下的提示词文件,可自定义生成内容的风格和侧重点。 - -### 调整生成参数 - -- 增加 `variants` 值可获得更多内容变体 -- 调整 `temperature` 参数可以改变生成内容的创造性 -- 修改 `poster_target_size` 可以设置不同的海报尺寸 - -### 分布式执行 - -利用分阶段执行功能,可在不同机器上完成选题生成和内容生成: - -1. 机器A执行选题生成 (`run_step1_topics.py`),将结果保存到共享存储 -2. 机器B从共享存储读取选题 (`run_step2_content_posters.py `),执行计算密集的内容和海报生成 - -## 常见问题 - -1. **生成内容质量不高?** - - 尝试提供更详细的景点信息 - - 调整提示词模板 - - 降低 `temperature` 参数以减少随机性 - -2. **找不到景点图片?** - - 确保图片目录名与景点信息匹配 - - 检查配置文件中的 `image_base_dir` 路径是否正确 - -3. **API调用失败?** - - 验证 API Key 和 URL 是否正确 - - 检查网络连接和防火墙设置 - -## 示例 - -查看 `examples/` 目录中的示例脚本及其 `README.md` 文件,了解更多使用方法。 - -## 贡献指南 - -欢迎提交 Pull Request 或 Issue 来帮助改进本项目。 - -## 许可证 - -本项目采用 MIT 许可证。 +欢迎提交问题报告和功能建议,或直接提交代码改进。 diff --git a/core/__init__.py b/core/__init__.py index f3b3e22..2f3c374 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,7 +1,7 @@ from .ai_agent import AI_Agent from .topic_parser import TopicParser from .contentGen import ContentGenerator -from .posterGen import PosterGenerator +from .poster_gen import PosterGenerator from .simple_collage import process_directory __all__ = ['AI_Agent', 'TopicParser', 'ContentGenerator', 'PosterGenerator', 'process_directory'] \ No newline at end of file diff --git a/core/__pycache__/__init__.cpython-312.pyc b/core/__pycache__/__init__.cpython-312.pyc index c380f473435dfeec2bcac1eb2804a841629612c7..20067b51956c7346d2c5cbafc0af7a35ae87fa97 100644 GIT binary patch delta 51 zcmX@Ye3Y5@G%qg~0}!~p=gLsu$Scao$yJbFT#{N8pFUZOv4>CnE`#nPuEa+6B7UGM E0AlYAfdBvi delta 50 zcmX@ge1w_zG%qg~0}wnj=E_jp$Scao!C8=BT#{PkK3SWwhfnP;gYF})#76caexM=% DO>hk5 diff --git a/core/__pycache__/poster_gen.cpython-312.pyc b/core/__pycache__/poster_gen.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ee9d849c97e2b2e4f10542f8b58e94d9792f919 GIT binary patch literal 37762 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 A;s5{u diff --git a/utils/tweet_generator.py b/utils/tweet_generator.py index 8d1f759..c14030d 100644 --- a/utils/tweet_generator.py +++ b/utils/tweet_generator.py @@ -24,7 +24,7 @@ from core.ai_agent import AI_Agent from core.topic_parser import TopicParser from utils.prompt_manager import PromptManager # Keep this as it's importing from the same level package 'utils' from core import contentGen as core_contentGen -from core import posterGen as core_posterGen +from core import poster_gen as core_posterGen from core import simple_collage as core_simple_collage from .output_handler import OutputHandler # <-- 添加导入