first commit
This commit is contained in:
BIN
event-publisher/.DS_Store
vendored
Normal file
BIN
event-publisher/.DS_Store
vendored
Normal file
Binary file not shown.
17
event-publisher/.env.example
Normal file
17
event-publisher/.env.example
Normal file
@@ -0,0 +1,17 @@
|
||||
# 豆包图片生成 API
|
||||
DOUBAO_API_KEY=your_doubao_api_key_here
|
||||
|
||||
# Nanobanana 图片生成 API
|
||||
NANOBANANA_API_KEY=your_nanobanana_api_key_here
|
||||
NANOBANANA_BASE_URL=http://zx2.52youxi.cc:3000
|
||||
|
||||
# 图片上传API(上传海报到OSS)
|
||||
UPLOAD_API_URL=https://data.tangledup-ai.com/upload?folder=images%2Factivity_banner
|
||||
|
||||
# 活动发布API
|
||||
ACTIVITY_API_URL=https://market.quant-speed.com/api/community/admin-publish/publish_activity/
|
||||
APIKEY=your_apikey_here
|
||||
PHONE_NUMBER=your_phone_number_here
|
||||
|
||||
# CSRF Token(需要从页面获取)
|
||||
CSRF_TOKEN=your_csrf_token_here
|
||||
2
event-publisher/.gitignore
vendored
Normal file
2
event-publisher/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# 忽略包含敏感信息的 .env 文件
|
||||
.env
|
||||
131
event-publisher/SKILL.md
Normal file
131
event-publisher/SKILL.md
Normal file
@@ -0,0 +1,131 @@
|
||||
---
|
||||
name: event-publisher
|
||||
description: |
|
||||
活动创建发布一条龙助手:创意选题 → 文案生成 → 海报生成(含Logo) → 活动发布
|
||||
|
||||
Triggers when 用户提到:
|
||||
- "发布活动"、"创建活动"
|
||||
- "活动海报"、"活动文案"
|
||||
- "生成海报"、"上传活动"
|
||||
- "过年游园"、"春节活动"
|
||||
---
|
||||
|
||||
## 快速使用
|
||||
|
||||
### 1. 收集活动信息
|
||||
AI 会询问以下信息(或用户直接提供):
|
||||
- 活动主题
|
||||
- 活动时间
|
||||
- 活动地点
|
||||
- 其他要求
|
||||
|
||||
### 2. 生成活动文案 (Robust Step)
|
||||
使用脚本生成标准化的Markdown文案,确保格式正确。
|
||||
|
||||
```bash
|
||||
# 用法
|
||||
./scripts/generate_content.sh "<活动主题>" "<时间>" "<地点>" "<其他信息>"
|
||||
|
||||
# 示例
|
||||
./scripts/generate_content.sh "春节游园会" "2月12日" "市中心广场" "包含灯谜和美食"
|
||||
```
|
||||
|
||||
> 输出:`assets/春节游园会_活动文案.md`
|
||||
|
||||
### 3. 海报生成 (自动加Logo + 保存提示词)
|
||||
生成海报,脚本会自动:
|
||||
1. 调用豆包生成提示词
|
||||
2. 生成3张豆包变体 + 1张Nanobanana创意图
|
||||
3. **自动添加 quant-speed Logo**
|
||||
4. **自动保存每个图片的完整提示词** (.txt文件)
|
||||
|
||||
```bash
|
||||
# 用法
|
||||
./scripts/generate_image.sh all "<活动文案内容>" "<活动名称>"
|
||||
|
||||
# 示例(读取上一步生成的文件内容)
|
||||
content=$(cat "assets/春节游园会_活动文案.md")
|
||||
./scripts/generate_image.sh all "$content" "春节游园会"
|
||||
```
|
||||
|
||||
### 4. 上传图片并发布活动
|
||||
用户选择一张满意的图片(例如 `春节游园会_豆包版1_xxx.jpg`),然后发布。
|
||||
|
||||
```bash
|
||||
# 完整流程:上传图片 + 发布活动
|
||||
./scripts/upload_event.sh all \
|
||||
"<图片文件路径>" \
|
||||
"<标题>" \
|
||||
"<描述文件路径>" \
|
||||
"<开始时间>" \
|
||||
"<结束时间>" \
|
||||
"<地点>"
|
||||
|
||||
# 示例
|
||||
./scripts/upload_event.sh all \
|
||||
"./assets/春节游园会_豆包版1_20240304.jpg" \
|
||||
"2024新春游园会" \
|
||||
"./assets/春节游园会_活动文案.md" \
|
||||
"2026-03-15T10:00:00Z" \
|
||||
"2026-03-15T16:00:00Z" \
|
||||
"市中心广场"
|
||||
```
|
||||
|
||||
## 工作流程
|
||||
|
||||
```
|
||||
1. 用户提供信息
|
||||
↓
|
||||
2. 脚本生成文案 (generate_content.sh) → 得到 .md 文件
|
||||
↓
|
||||
3. 脚本生成海报 (generate_image.sh)
|
||||
→ AI生成提示词
|
||||
→ 生成图片
|
||||
→ 自动叠加Logo (add_logo.py)
|
||||
→ 保存提示词 (.txt)
|
||||
↓
|
||||
4. 用户选择图片
|
||||
↓
|
||||
5. 脚本发布活动 (upload_event.sh)
|
||||
→ 上传图片到OSS
|
||||
→ 读取 .md 文件作为 description
|
||||
→ 发布 API
|
||||
↓
|
||||
6. 返回活动ID ✅
|
||||
```
|
||||
|
||||
## API配置
|
||||
|
||||
| 服务 | API | 状态 |
|
||||
|------|-----|------|
|
||||
| 豆包图片生成 | doubao-seedream-5-0-260128 | ✅ |
|
||||
| 豆包文本生成 | doubao-seed-2-0-pro-260215 | ✅ |
|
||||
| Nanobanana | gemini-3-pro-image-preview | ✅ |
|
||||
| 图片上传OSS | data.tangledup-ai.com/upload | ✅ |
|
||||
| 活动发布 | market.quant-speed.com | ✅ |
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
event-publisher/
|
||||
├── SKILL.md # 本文件
|
||||
├── .env # 环境变量
|
||||
├── assets/ # 资源目录
|
||||
│ ├── quant-speed.svg # Logo文件
|
||||
│ ├── xxx_活动文案.md # 生成的文案
|
||||
│ ├── xxx.jpg # 生成的海报
|
||||
│ └── xxx.jpg.txt # 对应的提示词文件
|
||||
└── scripts/
|
||||
├── generate_content.sh # [新增] 文案生成脚本
|
||||
├── generate_prompt.sh # 提示词生成脚本
|
||||
├── generate_image.sh # 图片生成脚本 (含Logo处理)
|
||||
├── add_logo.py # [新增] Logo添加脚本
|
||||
└── upload_event.sh # 上传发布脚本
|
||||
```
|
||||
|
||||
## Common Gotchas
|
||||
|
||||
- **Logo叠加**: 确保 `assets/quant-speed.svg` 存在。脚本依赖 `rsvg-convert` 和 `python3-pil`。
|
||||
- **文案生成**: 推荐使用 `generate_content.sh` 而不是让AI直接在对话中输出,以保证Markdown格式的准确性。
|
||||
- **提示词保存**: 每个图片都会对应一个同名的 `.txt` 文件,记录了完整的 Prompt 和 Model 信息。
|
||||
- **活动时间**: 发布时请使用 ISO 8601 格式:`2026-03-15T10:00:00Z`。
|
||||
BIN
event-publisher/assets/.DS_Store
vendored
Normal file
BIN
event-publisher/assets/.DS_Store
vendored
Normal file
Binary file not shown.
35
event-publisher/assets/quant-speed.svg
Normal file
35
event-publisher/assets/quant-speed.svg
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="_图层_2" data-name="图层_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 989.55 925.64">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
font-family: Krungthep, Krungthep;
|
||||
font-size: 92.87px;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
fill: #020202;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="_图层_1-2" data-name="图层_1">
|
||||
<g>
|
||||
<path class="cls-2" d="M412.28,0c21.28,5.72,40.43,15.59,58.14,28.66,7.12,5.25,12.47,11.82,17.59,18.76,1.92,2.6,4.75,5.22,3.21,8.74-1.62,3.73-5.57,2.84-8.73,2.95-16.39.58-32.74-.2-49.19,2.09-42.55,5.92-78.84,24.31-111.03,52.05-48.48,41.78-82.1,94.79-111.85,150.21-30.11,56.1-56.75,113.89-72.13,176.2-11.14,45.15-19.93,90.7-19.44,137.28.31,29.14,4.18,58.21,20.59,83.77,1.77,2.75,3.54,5.55,5.67,8.02,10.44,12.13,10.23,13.09-5.05,19.39-53.28,21.97-109.47-4.38-130.35-60.79-4.59-12.4-5.9-25.5-9.73-38.02v-27.12c2.91-18.86,3.06-37.98,4.31-56.94,2.44-36.98,12.09-72.25,22.29-107.44,19.91-68.68,49.59-132.98,88.75-192.85,18.68-28.57,39.12-55.93,62.76-80.53,35.21-36.64,68.51-75.39,113.61-101.27,23.59-13.53,48.25-21.17,75.24-21.91,2.01-.06,4.13.36,5.82-1.23h39.5Z"/>
|
||||
<path class="cls-2" d="M792.19,131.3c-16.86,4.02-33.77,6.89-49.92,12.11-60.19,19.46-111.99,51.88-154.93,98.96-55.08,60.4-107.14,123.35-158.47,186.84-48.14,59.56-99.58,115.86-154.96,168.6-22.57,21.49-45.48,42.8-71.8,59.89-22.13,14.36-41.19,9.39-52.67-14.17-11.63-23.86-13.51-49.64-13.52-75.67,0-4.89,2.35-8.34,6.05-11.5,47.42-40.54,94.77-81.15,142.07-121.83,43.56-37.47,87.81-74.19,130.38-112.76,75.92-68.77,157.11-129.65,250.52-172.89,36.83-17.05,76.31-22.18,116.48-22.94,3.81-.07,8.38-.48,10.77,5.37Z"/>
|
||||
<path class="cls-2" d="M795.46,490.45c-20.17-4.55-38.34-12.09-54.96-22.98-44.94-29.47-80.24-68.78-112.48-111.11-8.45-11.1-16-22.91-24.58-33.91-5.85-7.5-4.36-12.69,2.13-18.88,15.17-14.45,30.01-29.27,44.46-44.45,6.64-6.98,11.38-6.99,18.18-.06,24.18,24.64,49.97,47.41,78.35,67.31,34.67,24.31,72.81,39.36,114.51,45.94,8.93,1.41,17.75,3.48,26.67,4.93,7.45,1.21,10.05,4.16,6.34,11.67-20.49,41.45-48.2,76.2-90.04,98.03-2.86,1.49-5.98,2.47-8.57,3.52Z"/>
|
||||
<path class="cls-2" d="M874.18,155.7c17.01,14.01,30.76,29.06,43.52,44.96,31.34,39.05,54.92,81.89,61.08,132.44,5.37,44.12-2.85,86.74-30.05,121.33-25.28,32.16-62,47.85-104.39,45.61-4.25-.22-10.55,0-11.8-4.7-1.41-5.29,5.19-6.47,8.54-9.01,46.66-35.45,80.06-80.91,87.6-139.08,8.67-66.91-6.32-129.76-51.65-182.74-1.54-1.8-3.86-3.24-2.84-8.8Z"/>
|
||||
<path class="cls-2" d="M393.2,88.88c29.32-14.72,57.46-19.83,87.21-16.33,3.67.43,7.31,1.12,10.99,1.51,19.26,2.03,35.26,8.92,46,26.49,6.81,11.15,15.5,21.23,23.97,31.26,5.93,7.03,3.97,11.44-2.86,15.78-13.88,8.82-27.81,17.57-41.36,26.87-6.79,4.66-10.95,2.94-15.26-3.19-19.76-28.08-45.74-49.27-75.28-66.2-9.89-5.67-20.53-10.01-33.4-16.19Z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="cls-2" d="M642.58,733.79c.17,2.58.53,4.27.34,5.88-1.29,10.63-1.84,11.14-12.88,11.16-28.21.04-56.41,0-84.62.06-3.05,0-6.28.09-9.09,1.09-1.33.48-2.39,3.16-2.52,4.92-.07.87,2.12,2.52,3.49,2.77,2.67.5,5.48.32,8.22.32,28.89.02,57.79.01,86.68.02,2.41,0,4.82.11,7.22.04,5.04-.15,6.34,2.43,6.2,7.12-.43,15.28-2,16.99-17.13,16.99-88.4,0-176.81-.05-265.21.05-16.7.02-14.53-1.71-12.47-14.02,1.68-10.04,1.54-10.14,12.36-10.16,30.27-.04,60.54,0,90.81-.04,3.08,0,6.23.02,9.22-.61,1.25-.27,3.14-2.35,2.99-3.35-.24-1.64-1.63-4.01-3.02-4.41-2.89-.83-6.1-.73-9.18-.73-25.45-.04-50.91-.03-76.36-.03-2.41,0-4.82.05-7.22-.02-7.95-.25-8.85-.92-8.95-6.56-.15-8.44,1.77-10.89,9.63-10.93,28.21-.12,56.41-.05,84.62-.07,3.1,0,6.19.02,9.28-.13,2.92-.15,5.62-.87,5.47-4.61-.15-3.75-3.08-4.1-5.87-4.28-2.74-.18-5.5-.12-8.25-.13-23.05,0-46.09,0-69.14,0-2.41,0-4.82.07-7.22-.03-7.8-.33-8.69-1.35-7.79-9.4.46-4.08,1.25-8.12,1.82-12.19,1.85-13.22,3.54-26.47,5.56-39.67,1.48-9.68,1.67-9.77,11.82-9.8,24.76-.07,49.53-.02,74.29-.02,55.72,0,111.45,0,167.17,0,2.75,0,5.51.13,8.25.02,4.93-.19,6.92,2.06,6.23,6.91-2.74,19.32-5.51,38.64-8.1,57.98-.56,4.21-2.71,6.05-6.76,6.09-4.81.04-9.63.1-14.45.1-22.7.01-45.41,0-68.11.02-2.75,0-5.66-.38-8.19.4-1.9.58-3.3,2.75-4.93,4.2,1.56,1.45,2.89,3.61,4.72,4.16,2.54.76,5.45.37,8.19.37,27.17.02,54.35,0,81.52.03,3.68,0,7.35.31,11.35.5ZM455.08,670.86c-6.47,0-12.98-.37-19.4.21-2.05.19-5.2,2.68-5.5,4.49-.61,3.7,3.08,3.81,5.74,3.84,10.56.13,21.13.1,31.69.08,2.04,0,4.39.35,6.03-.52,1.78-.94,2.89-3.12,4.3-4.75-1.49-1.12-2.92-3.11-4.47-3.2-6.11-.37-12.25-.15-18.39-.16ZM568.87,679.4v.1c5.11,0,10.22.09,15.33-.04,2.01-.05,4.37-.05,5.89-1.08,1.37-.93,2.31-3.18,2.45-4.93.06-.77-2.3-2.49-3.58-2.51-12.94-.17-25.89-.23-38.83.12-1.75.05-4.55,2.23-4.91,3.86-.82,3.65,2.44,4.37,5.25,4.44,6.13.15,12.26.05,18.4.05ZM448.88,706.09s0,.06,0,.09c5.83,0,11.66.09,17.49-.04,3.45-.08,7.64-.22,7.54-4.87-.09-4.28-4.23-3.76-7.17-3.79-10.63-.12-21.26-.08-31.89-.03-1.7,0-3.72-.16-5.01.66-1.52.96-3.2,2.87-3.28,4.45-.06,1.11,2.39,3.27,3.82,3.36,6.15.38,12.33.16,18.5.16ZM564.82,706.13c0-.07,0-.13,0-.2,6.52,0,13.07.31,19.56-.21,1.66-.13,3.1-2.91,4.64-4.47-1.66-1.25-3.27-3.5-4.99-3.58-8.23-.4-16.49-.27-24.74-.23-4.46.02-8.99-.2-13.35.53-1.79.3-3.19,2.85-4.77,4.37,1.7,1.27,3.32,3.49,5.1,3.62,6.15.45,12.36.17,18.54.17Z"/>
|
||||
<path class="cls-2" d="M868.37,736.34c.93-2.22,1.01-3.06,1.46-3.4,12.08-9.08,14.69-22.06,16.41-36.11,3.71-30.24,8.49-60.36,12.83-90.52.2-1.36.44-2.7.64-4.06.49-3.35.06-6.38-3.88-7.18-3.4-.69-7.06-1.04-9.18,2.61-1.19,2.05-1.99,4.37-2.64,6.66-11.58,40.52-23.16,81.03-34.64,121.58-2.94,10.37-2.8,10.46-14.05,10.52-10.91.06-21.82.01-34.19.01,3.56-12.77,6.6-23.89,9.76-34.99,9.17-32.29,18.43-64.56,27.56-96.87,2.22-7.86.78-9.72-7.81-9.94-9.28-.24-18.57-.03-27.86-.1-3.38-.02-6.75-.28-10.77-.47-1.09-9.14.84-17.37,2.71-25.55,1.05-4.59,5.14-3.82,8.47-3.83,16.51-.07,33.02-.04,49.54-.04,2.41,0,4.82.03,7.22-.01,10.21-.18,14.44-7.01,9.93-16.18-1.15-2.34-2.73-4.48-4.59-7.48,2.77-.7,4.63-1.57,6.5-1.58,16.17-.12,32.34-.22,48.5-.02,7.51.09,8.2,1.23,7.24,8.67q-2.15,16.59,14.3,16.61c12.04,0,24.08-.03,36.12.03,3.36.02,6.73.31,11.61.56-1.25,8.79-2.38,16.77-3.51,24.75-.58,4.08-3.6,4.52-6.87,4.53-7.57.03-15.14-.09-22.7.1-7.82.19-8.56.8-9.73,8.79-4.84,33.21-9.54,66.43-14.35,99.65-1.83,12.66-6.05,24.01-18.32,30.38-2.67,1.39-5.76,2.69-8.69,2.77-11.99.31-23.98.13-37.02.13Z"/>
|
||||
<path class="cls-2" d="M971.24,753.75c-1.38,9.62-2.64,17.36-3.55,25.14-.54,4.61-2.77,6.73-7.38,6.6-2.75-.08-5.5.03-8.25.03-48.49,0-96.98-.46-145.45.24-17.85.26-34.82-2.54-51.64-7.68-1.97-.6-3.94-1.22-5.92-1.79-5.09-1.46-9.24-.84-12.55,4.08-1.51,2.24-4.61,4.76-7.05,4.83-15.41.44-30.83.22-46.48.22-1.46-5.71,1.81-9.4,4.11-12.69,8.56-12.25,11.46-26.01,13.27-40.48,3.4-27.17,7.57-54.24,11.39-81.36.33-2.37.54-4.76.72-7.15.35-4.67-.75-8.27-6.45-8.21-5.25.06-6.35-3.05-5.79-7.44.31-2.37.68-4.74,1.06-7.11q2.55-15.9,19.17-15.91c13.76,0,27.51-.1,41.26.05,9.64.1,10.77,1.29,9.45,11-3.59,26.45-7.42,52.88-11.17,79.31-1.54,10.85-3.22,21.67-4.63,32.54-1.32,10.15-.37,11.46,9.82,14.39,10.24,2.95,20.42,6.14,30.79,8.52,6.96,1.59,14.2,2.7,21.32,2.74,46.77.24,93.53.12,140.3.12,4.06,0,8.13,0,13.66,0Z"/>
|
||||
<path class="cls-2" d="M386.62,616.93c1.7-14.64,3.11-27.81,4.81-40.94,1.05-8.13,2.62-16.19,3.84-24.3.76-5.11,3.03-8.23,8.76-7.58,1.36.15,2.75,0,4.12,0,81.07,0,162.13,0,243.2.02,3.67,0,7.33.35,12.14.6-1.25,9.12-2.35,17.17-3.45,25.23-1.8,13.21-3.71,26.41-5.33,39.64-.67,5.47-3.29,7.89-8.82,7.35-2.04-.2-4.12-.02-6.18-.02-80.04,0-160.07,0-240.11,0-4.01,0-8.02,0-12.97,0ZM523.06,590.31c-22.98,0-45.96,0-68.94.01-2.74,0-5.59-.25-8.18.44-1.6.42-3.75,2.3-3.88,3.69-.11,1.29,1.88,3.34,3.41,4.03,1.76.79,4.03.56,6.08.56,47.68.02,95.36.02,143.03,0,2.05,0,4.33.26,6.08-.53,1.52-.69,3.45-2.76,3.36-4.09-.1-1.36-2.26-3.25-3.84-3.67-2.59-.68-5.44-.42-8.18-.42-22.98-.02-45.96-.01-68.94-.01ZM526.45,570.84c24.39,0,48.78.04,73.17-.05,3.23-.01,8.18.98,8.19-3.73,0-4.9-5.06-3.51-8.17-3.54-16.13-.14-32.27-.03-48.4-.03-31.26,0-62.52-.04-93.78-.04-2.74,0-5.56-.1-8.19.51-1.31.3-3.05,2.05-3.13,3.25-.07,1.02,1.79,2.87,3.07,3.15,2.64.58,5.45.46,8.19.46,23.02.03,46.03.01,69.05,0Z"/>
|
||||
<path class="cls-2" d="M664.1,626.08c.35,2.15.7,3.13.65,4.09-.72,13.47-.79,13.54-14.36,13.56-68.72.09-137.44.18-206.16.22-21.6.01-43.19-.1-64.79-.24-9.57-.07-12.19-3.9-8.35-12.73.89-2.03,3.57-3.94,5.81-4.58,2.87-.81,6.13-.31,9.22-.32,59.78,0,119.56,0,179.34,0,29.21,0,58.41,0,87.62,0,3.68,0,7.37,0,11.02,0Z"/>
|
||||
<path class="cls-2" d="M951.96,661.67c0-10.27-.11-20.54.03-30.8.12-8.74.54-9.1,9.52-9.28,5.49-.11,10.99.02,16.49.09,3.73.05,5.71,1.93,5.76,5.7.03,2.74.15,5.48.06,8.21-.56,18.79-1.12,37.58-1.77,56.37-.32,9.24-.43,9.31-9.23,9.51-4.81.11-9.62-.12-14.43,0-4.9.12-6.67-2.33-6.63-6.94.1-10.95.03-21.9.03-32.86.05,0,.11,0,.16,0Z"/>
|
||||
<path class="cls-2" d="M769.69,700.98c2.74-10.45,5-19.3,7.4-28.12,4.14-15.17,8.28-30.34,12.59-45.46,2.46-8.64,3.22-9.12,12.08-9.24,6.07-.09,12.13-.02,19.5-.02-1.06,4.9-1.61,8.18-2.48,11.38-5.76,21.1-11.57,42.2-17.42,63.28-2.35,8.46-2.41,8.57-11.24,8.65-6.35.06-12.7-.28-20.42-.47Z"/>
|
||||
<path class="cls-2" d="M778.14,586.16c-8.58,0-15.33,0-22.09,0-7.56,0-15.12-.07-22.68-.02-3.38.03-6.1-.8-7.29-4.34-3.77-11.29-7.54-22.59-11.52-34.5,2.84-.76,4.7-1.68,6.58-1.7,12.03-.14,24.06-.1,36.08-.07,3.48,0,7.16,0,8.57,4.09,3.98,11.56,7.84,23.16,12.35,36.53Z"/>
|
||||
</g>
|
||||
<text class="cls-1" transform="translate(360.91 887.84)"><tspan x="0" y="0">QUANT SPEED</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.1 KiB |
81
event-publisher/scripts/add_logo.py
Executable file
81
event-publisher/scripts/add_logo.py
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
from PIL import Image
|
||||
|
||||
def add_logo(image_path, logo_svg_path):
|
||||
if not os.path.exists(image_path):
|
||||
print(f"Error: Image not found at {image_path}")
|
||||
return
|
||||
|
||||
if not os.path.exists(logo_svg_path):
|
||||
print(f"Error: Logo SVG not found at {logo_svg_path}")
|
||||
return
|
||||
|
||||
try:
|
||||
# Open the main image
|
||||
img = Image.open(image_path)
|
||||
img_w, img_h = img.size
|
||||
|
||||
# Calculate desired logo width (e.g., 20% of image width)
|
||||
target_logo_width = int(img_w * 0.2)
|
||||
if target_logo_width < 100: target_logo_width = 100 # Minimum width
|
||||
|
||||
# Convert SVG to PNG with the target width using rsvg-convert
|
||||
# We use a temporary file for the logo png
|
||||
logo_png_path = "/tmp/temp_logo.png"
|
||||
|
||||
# Check if rsvg-convert exists
|
||||
rsvg_check = subprocess.run(["which", "rsvg-convert"], capture_output=True, text=True)
|
||||
if rsvg_check.returncode != 0:
|
||||
print("Error: rsvg-convert not found. Please install librsvg.")
|
||||
return
|
||||
|
||||
# Convert SVG to PNG
|
||||
subprocess.run([
|
||||
"rsvg-convert",
|
||||
"-w", str(target_logo_width),
|
||||
"-f", "png",
|
||||
"-o", logo_png_path,
|
||||
logo_svg_path
|
||||
], check=True)
|
||||
|
||||
# Open the logo image
|
||||
logo = Image.open(logo_png_path).convert("RGBA")
|
||||
|
||||
# Calculate position (top-left with margin)
|
||||
margin = int(img_w * 0.05)
|
||||
position = (margin, margin)
|
||||
|
||||
# Paste logo onto image (using alpha channel as mask)
|
||||
# Handle different image modes (RGB vs RGBA)
|
||||
if img.mode != 'RGBA':
|
||||
img = img.convert('RGBA')
|
||||
|
||||
img.paste(logo, position, logo)
|
||||
|
||||
# Save the result (overwrite original or save as new)
|
||||
# We'll overwrite for now as per "add the logo" request implies modification
|
||||
# But if it's JPG, we need to convert back to RGB
|
||||
if image_path.lower().endswith(('.jpg', '.jpeg')):
|
||||
img = img.convert('RGB')
|
||||
|
||||
img.save(image_path)
|
||||
print(f"✅ Logo added to {image_path}")
|
||||
|
||||
# Clean up
|
||||
if os.path.exists(logo_png_path):
|
||||
os.remove(logo_png_path)
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Failed to add logo: {str(e)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: python3 add_logo.py <image_path> <logo_svg_path>")
|
||||
sys.exit(1)
|
||||
|
||||
image_path = sys.argv[1]
|
||||
logo_svg_path = sys.argv[2]
|
||||
add_logo(image_path, logo_svg_path)
|
||||
96
event-publisher/scripts/generate_content.sh
Executable file
96
event-publisher/scripts/generate_content.sh
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
# 活动文案生成脚本 - Event Publisher Skill
|
||||
# 使用豆包大模型生成 Markdown 格式的活动文案
|
||||
|
||||
# 获取脚本所在目录的绝对路径
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
ASSETS_DIR="$SKILL_DIR/assets"
|
||||
|
||||
# 确保 assets 目录存在
|
||||
mkdir -p "$ASSETS_DIR"
|
||||
|
||||
# 加载环境变量
|
||||
if [ -f "$SCRIPT_DIR/.env" ]; then
|
||||
source "$SCRIPT_DIR/.env"
|
||||
elif [ -f "$SKILL_DIR/.env" ]; then
|
||||
source "$SKILL_DIR/.env"
|
||||
fi
|
||||
|
||||
# 默认值
|
||||
DOUBAO_API_KEY="${DOUBAO_API_KEY:-db1f8b60-0ffc-473c-98da-40daa3a95df8}"
|
||||
|
||||
generate_content() {
|
||||
local topic="$1"
|
||||
local time="$2"
|
||||
local location="$3"
|
||||
local extra_info="$4"
|
||||
|
||||
echo "======================================"
|
||||
echo "📝 正在生成活动文案..."
|
||||
echo "======================================"
|
||||
echo ">>> 主题: $topic"
|
||||
echo ">>> 时间: $time"
|
||||
echo ">>> 地点: $location"
|
||||
|
||||
# 构建 Prompt
|
||||
local system_prompt="你是一个专业的活动策划师。请根据用户提供的信息,生成一份精美的活动文案(Markdown格式)。
|
||||
要求:
|
||||
1. 包含主标题(H1)和副标题
|
||||
2. 开头要有吸引人的活动介绍(包含emoji表情)
|
||||
3. 活动亮点部分(使用列表)
|
||||
4. 时间安排(使用表格)
|
||||
5. 活动流程(使用表格)
|
||||
6. 结尾要有号召性用语
|
||||
7. 整体风格要热情、活泼、有感染力
|
||||
8. 直接输出Markdown内容,不要包含```markdown```标记,也不要包含其他解释性文字。"
|
||||
|
||||
local user_prompt="请生成一份活动文案:
|
||||
- 活动主题:$topic
|
||||
- 活动时间:$time
|
||||
- 活动地点:$location
|
||||
- 其他要求:$extra_info"
|
||||
|
||||
# URL编码
|
||||
local user_prompt_encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''$user_prompt'''))")
|
||||
|
||||
# JSON数据
|
||||
local json_data="{\"model\":\"doubao-seed-2-0-pro-260215\",\"messages\":[{\"role\":\"system\",\"content\":\"$system_prompt\"},{\"role\":\"user\",\"content\":\"$user_prompt_encoded\"}],\"max_tokens\":2000}"
|
||||
|
||||
# 调用API
|
||||
response=$(curl -s -X POST "https://ark.cn-beijing.volces.com/api/v3/chat/completions" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $DOUBAO_API_KEY" \
|
||||
--data-binary "$json_data")
|
||||
|
||||
# 解析响应
|
||||
content=$(echo "$response" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['choices'][0]['message']['content'] if d.get('choices') else '')" 2>/dev/null)
|
||||
|
||||
if [ -n "$content" ]; then
|
||||
# 清理可能的 markdown 标记
|
||||
content=$(echo "$content" | sed 's/^```markdown//' | sed 's/^```//' | sed 's/```$//')
|
||||
|
||||
# 生成文件名(使用主题名,替换空格为下划线)
|
||||
safe_topic=$(echo "$topic" | tr ' ' '_')
|
||||
output_file="$ASSETS_DIR/${safe_topic}_活动文案.md"
|
||||
|
||||
echo "$content" > "$output_file"
|
||||
echo ""
|
||||
echo "✅ 活动文案已生成: $output_file"
|
||||
echo "--------------------------------------"
|
||||
head -n 10 "$output_file"
|
||||
echo "..."
|
||||
echo "--------------------------------------"
|
||||
else
|
||||
echo "❌ 文案生成失败"
|
||||
echo "$response"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "用法: $0 <活动主题> [时间] [地点] [其他信息]"
|
||||
echo "示例: $0 '春节游园会' '2月12日' '市中心广场' '包含灯谜和美食'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
generate_content "$1" "$2" "$3" "$4"
|
||||
272
event-publisher/scripts/generate_image.sh
Executable file
272
event-publisher/scripts/generate_image.sh
Executable file
@@ -0,0 +1,272 @@
|
||||
#!/bin/bash
|
||||
# 图片生成脚本 - 活动发布 skill
|
||||
# 使用豆包大模型根据活动内容生成提示词,然后生成海报
|
||||
# 包含:自动添加Logo、保存规范提示词
|
||||
|
||||
# 获取脚本所在目录的绝对路径
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
ASSETS_DIR="$SKILL_DIR/assets"
|
||||
|
||||
# 确保 assets 目录存在
|
||||
mkdir -p "$ASSETS_DIR"
|
||||
|
||||
# 加载环境变量
|
||||
if [ -f "$SCRIPT_DIR/.env" ]; then
|
||||
source "$SCRIPT_DIR/.env"
|
||||
elif [ -f "$SKILL_DIR/.env" ]; then
|
||||
source "$SKILL_DIR/.env"
|
||||
fi
|
||||
|
||||
# 脚本路径
|
||||
PROMPT_SCRIPT="$SCRIPT_DIR/generate_prompt.sh"
|
||||
LOGO_SCRIPT="$SCRIPT_DIR/add_logo.py"
|
||||
LOGO_FILE="$ASSETS_DIR/quant-speed.svg"
|
||||
|
||||
# 默认值
|
||||
DOUBAO_API_KEY="${DOUBAO_API_KEY:-db1f8b60-0ffc-473c-98da-40daa3a95df8}"
|
||||
NANOBANANA_API_KEY="${NANOBANANA_API_KEY:-sk-Cx883TlPrrn0nUvQFmU5wSt99OFv7tiIhg4Re5yHttNtN1Am}"
|
||||
NANOBANANA_BASE_URL="${NANOBANANA_BASE_URL:-http://zx2.52youxi.cc:3000}"
|
||||
|
||||
# 辅助函数:添加Logo
|
||||
add_logo_to_image() {
|
||||
local image_path="$1"
|
||||
if [ -f "$LOGO_SCRIPT" ] && [ -f "$LOGO_FILE" ]; then
|
||||
echo " 🔄 正在添加Logo..."
|
||||
python3 "$LOGO_SCRIPT" "$image_path" "$LOGO_FILE"
|
||||
else
|
||||
echo " ⚠️ Logo脚本或文件不存在,跳过添加Logo"
|
||||
fi
|
||||
}
|
||||
|
||||
# 辅助函数:保存提示词
|
||||
save_prompt_info() {
|
||||
local image_path="$1"
|
||||
local prompt="$2"
|
||||
local model="$3"
|
||||
local timestamp=$(date +%Y-%m-%dT%H:%M:%S%z)
|
||||
|
||||
local txt_file="${image_path}.txt"
|
||||
echo "Image: $(basename "$image_path")
|
||||
Prompt: $prompt
|
||||
Model: $model
|
||||
Timestamp: $timestamp" > "$txt_file"
|
||||
echo " 💾 提示词已保存: $(basename "$txt_file")"
|
||||
}
|
||||
|
||||
# 使用AI生成提示词
|
||||
generate_ai_prompts() {
|
||||
local event_content="$1"
|
||||
|
||||
echo "======================================"
|
||||
echo "🤖 步骤1: 使用豆包AI生成海报提示词"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
# 调用AI生成提示词
|
||||
local result=$(bash "$PROMPT_SCRIPT" ai "$event_content")
|
||||
|
||||
# 提取提示词
|
||||
local doubao_prompt=$(echo "$result" | grep "DOUBAO_PROMPT=" | sed 's/DOUBAO_PROMPT=//')
|
||||
local nano_prompt=$(echo "$result" | grep "NANO_PROMPT=" | sed 's/NANO_PROMPT=//')
|
||||
|
||||
if [ -z "$doubao_prompt" ] || [ -z "$nano_prompt" ]; then
|
||||
echo "❌ AI提示词生成失败,使用默认提示词"
|
||||
doubao_prompt="春节游园会,新春庆典,红灯笼,中国结,舞狮,烟花,喜庆氛围,节日活动"
|
||||
nano_prompt="春节,新年,现代简约设计,扁平化风格,渐变色,孟菲斯风格"
|
||||
fi
|
||||
|
||||
echo "✅ AI提示词生成成功!"
|
||||
echo ""
|
||||
echo "📝 豆包提示词: ${doubao_prompt:0:80}..."
|
||||
echo "📝 创意提示词: ${nano_prompt:0:80}..."
|
||||
echo ""
|
||||
|
||||
# 返回提示词
|
||||
echo "DOUBAO_PROMPT=$doubao_prompt"
|
||||
echo "NANO_PROMPT=$nano_prompt"
|
||||
}
|
||||
|
||||
# 生成豆包图片(3张变体)
|
||||
generate_doubao_images() {
|
||||
local base_prompt="$1"
|
||||
local event_name="$2"
|
||||
|
||||
echo "======================================"
|
||||
echo "🎨 步骤2: 生成豆包海报(3张变体)"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
# 生成3个不同的提示词变体
|
||||
local prompts=$(bash "$PROMPT_SCRIPT" variations "$base_prompt")
|
||||
|
||||
local prompt1=$(echo "$prompts" | sed -n '1p')
|
||||
local prompt2=$(echo "$prompts" | sed -n '2p')
|
||||
local prompt3=$(echo "$prompts" | sed -n '3p')
|
||||
|
||||
echo " 提示词变体1: ${prompt1:0:60}..."
|
||||
echo " 提示词变体2: ${prompt2:0:60}..."
|
||||
echo " 提示词变体3: ${prompt3:0:60}..."
|
||||
echo ""
|
||||
|
||||
local timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local success_count=0
|
||||
|
||||
# 生成3张图片
|
||||
for i in 1 2 3; do
|
||||
local prompt_var=$(eval echo \$prompt$i)
|
||||
local output_file="$ASSETS_DIR/${event_name}_豆包版${i}_${timestamp}.jpg"
|
||||
|
||||
echo ">>> 生成第 $i 张..."
|
||||
|
||||
response=$(curl -s -X POST "https://ark.cn-beijing.volces.com/api/v3/images/generations" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $DOUBAO_API_KEY" \
|
||||
-d "{
|
||||
\"model\": \"doubao-seedream-5-0-260128\",
|
||||
\"prompt\": \"$prompt_var\",
|
||||
\"sequential_image_generation\": \"disabled\",
|
||||
\"response_format\": \"url\",
|
||||
\"size\": \"2K\",
|
||||
\"stream\": false,
|
||||
\"watermark\": true
|
||||
}")
|
||||
|
||||
image_url=$(echo "$response" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['data'][0]['url'] if d.get('data') else '')" 2>/dev/null)
|
||||
|
||||
if [ -n "$image_url" ]; then
|
||||
curl -s -o "$output_file" "$image_url"
|
||||
echo " ✅ 第 $i 张已保存: ${output_file}"
|
||||
|
||||
# 添加Logo
|
||||
add_logo_to_image "$output_file"
|
||||
|
||||
# 保存提示词
|
||||
save_prompt_info "$output_file" "$prompt_var" "doubao-seedream-5-0-260128"
|
||||
|
||||
success_count=$((success_count + 1))
|
||||
else
|
||||
echo " ❌ 第 $i 张生成失败"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "✅ 豆包图片生成完成!成功 $success_count/3 张"
|
||||
}
|
||||
|
||||
# 生成 Nanobanana 图片
|
||||
generate_nanobanana_image() {
|
||||
local prompt="$1"
|
||||
local event_name="$2"
|
||||
|
||||
echo "======================================"
|
||||
echo "🎨 步骤3: 生成 Nanobanana 海报(创意版)"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo " 提示词: ${prompt:0:60}..."
|
||||
echo ""
|
||||
|
||||
local timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local output_file="$ASSETS_DIR/${event_name}_创意版_${timestamp}.png"
|
||||
|
||||
response=$(curl -s -X POST "${NANOBANANA_BASE_URL}/v1/chat/completions" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $NANOBANANA_API_KEY" \
|
||||
-d "{
|
||||
\"model\": \"gemini-3-pro-image-preview\",
|
||||
\"messages\": [{\"role\": \"user\", \"content\": \"生成一张图片:$prompt\"}],
|
||||
\"max_tokens\": 4000
|
||||
}")
|
||||
|
||||
# 提取base64图片数据
|
||||
img_data=$(echo "$response" | python3 -c "
|
||||
import sys, json, re
|
||||
import base64
|
||||
try:
|
||||
d = json.load(sys.stdin)
|
||||
content = d['choices'][0]['message']['content']
|
||||
match = re.search(r'data:image/(\w+);base64,(.+)', content, re.DOTALL)
|
||||
if match:
|
||||
img_type = match.group(1)
|
||||
img_b64 = match.group(2).strip()
|
||||
img_bytes = base64.b64decode(img_b64)
|
||||
import base64 as b64mod
|
||||
print(b64mod.b64encode(img_bytes).decode('utf-8'))
|
||||
except Exception as e:
|
||||
print('')
|
||||
" 2>/dev/null)
|
||||
|
||||
if [ -n "$img_data" ]; then
|
||||
echo "$img_data" | base64 -d > "$output_file" 2>/dev/null
|
||||
echo "✅ Nanobanana 图片已保存: $output_file"
|
||||
|
||||
# 添加Logo
|
||||
add_logo_to_image "$output_file"
|
||||
|
||||
# 保存提示词
|
||||
save_prompt_info "$output_file" "$prompt" "gemini-3-pro-image-preview"
|
||||
else
|
||||
echo "❌ Nanobanana 图片生成失败"
|
||||
fi
|
||||
}
|
||||
|
||||
# 根据活动内容生成所有海报
|
||||
generate_posters_from_content() {
|
||||
local event_content="$1"
|
||||
local event_name="$2"
|
||||
|
||||
echo "======================================"
|
||||
echo "🎉 开始生成活动海报"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
# 步骤1: AI生成提示词
|
||||
local prompts=$(generate_ai_prompts "$event_content")
|
||||
local doubao_prompt=$(echo "$prompts" | grep "DOUBAO_PROMPT=" | sed 's/DOUBAO_PROMPT=//')
|
||||
local nano_prompt=$(echo "$prompts" | grep "NANO_PROMPT=" | sed 's/NANO_PROMPT=//')
|
||||
|
||||
# 步骤2: 生成豆包图片
|
||||
generate_doubao_images "$doubao_prompt" "$event_name"
|
||||
echo ""
|
||||
|
||||
# 步骤3: 生成Nanobanana图片
|
||||
generate_nanobanana_image "$nano_prompt" "$event_name"
|
||||
echo ""
|
||||
|
||||
echo "======================================"
|
||||
echo "✅ 全部海报生成完成!"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo "📁 所有图片保存位置: $ASSETS_DIR"
|
||||
echo ""
|
||||
echo "请选择您喜欢的海报版本:"
|
||||
echo " 1 - 豆包版1"
|
||||
echo " 2 - 豆包版2"
|
||||
echo " 3 - 豆包版3"
|
||||
echo " 4 - 创意版"
|
||||
}
|
||||
|
||||
# 根据参数调用对应函数
|
||||
case "$1" in
|
||||
ai)
|
||||
generate_ai_prompts "$2"
|
||||
;;
|
||||
doubao)
|
||||
generate_doubao_images "$2" "$3"
|
||||
;;
|
||||
nanobanana)
|
||||
generate_nanobanana_image "$2" "$3"
|
||||
;;
|
||||
all)
|
||||
generate_posters_from_content "$2" "$3"
|
||||
;;
|
||||
*)
|
||||
echo "======================================"
|
||||
echo "🖼️ 活动海报生成工具"
|
||||
echo "======================================"
|
||||
echo "用法: $0 all <活动文案> <活动名称>"
|
||||
echo ""
|
||||
echo "示例: "
|
||||
echo ' $0 all "活动名称:春节游园会..." "春节游园会"'
|
||||
;;
|
||||
esac
|
||||
128
event-publisher/scripts/generate_prompt.sh
Executable file
128
event-publisher/scripts/generate_prompt.sh
Executable file
@@ -0,0 +1,128 @@
|
||||
#!/bin/bash
|
||||
# 活动海报提示词生成器 - 使用豆包大模型生成
|
||||
|
||||
# 获取脚本所在目录的绝对路径
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
ASSETS_DIR="$SKILL_DIR/assets"
|
||||
|
||||
# 加载环境变量
|
||||
if [ -f "$SCRIPT_DIR/.env" ]; then
|
||||
source "$SCRIPT_DIR/.env"
|
||||
elif [ -f "$SKILL_DIR/.env" ]; then
|
||||
source "$SKILL_DIR/.env"
|
||||
fi
|
||||
|
||||
# 默认值
|
||||
DOUBAO_API_KEY="${DOUBAO_API_KEY:-db1f8b60-0ffc-473c-98da-40daa3a95df8}"
|
||||
|
||||
# 使用豆包大模型生成海报提示词
|
||||
generate_prompt_with_ai() {
|
||||
local event_content="$1"
|
||||
|
||||
echo "🤖 正在使用豆包大模型生成海报提示词..."
|
||||
|
||||
# 构建prompt,让AI根据活动内容生成适合的图片提示词
|
||||
local system_prompt="你是一个专业的活动海报设计提示词专家。根据用户提供的活动文案内容,生成适合用于AI绘画生成海报的中文提示词。要求:1. 生成的提示词要准确反映活动的主题、氛围和特点 2. 提示词应该是有画面结构,内容文字,用逗号分隔 3. 提示词要包含:活动场景、人物、物品、氛围、风格、构图和海报文字等关键词 4. 适合用于AI图像生成(豆包/Nanobanana等模型)并且文字部分用双引号包起来 5. 建议风格:电影大片感、视觉冲击力、oc渲染,光线追踪、动态模糊、景深、质感真实。请直接输出提示词,不要其他解释。"
|
||||
|
||||
# 将活动内容进行URL编码
|
||||
local user_prompt_encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''请根据以下活动文案内容,生成适合生成活动海报的AI绘画提示词。$event_content。请生成:1. 适合豆包API(写实风格)的提示词 2. 适合Nanobanana API(创意风格)的提示词。格式:豆包提示词:[提示词] 创意提示词:[提示词]'''))")
|
||||
|
||||
# 使用简化的请求
|
||||
local json_data="{\"model\":\"doubao-seed-2-0-pro-260215\",\"messages\":[{\"role\":\"system\",\"content\":\"$system_prompt\"},{\"role\":\"user\",\"content\":\"$user_prompt_encoded\"}],\"max_tokens\":1000}"
|
||||
|
||||
# 调用豆包API
|
||||
response=$(curl -s -X POST "https://ark.cn-beijing.volces.com/api/v3/chat/completions" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $DOUBAO_API_KEY" \
|
||||
--data-binary "$json_data")
|
||||
|
||||
# 保存原始响应用于调试
|
||||
echo "$response" > /tmp/ai_prompt_response.json
|
||||
|
||||
# 解析响应
|
||||
python3 << 'PYEOF'
|
||||
import json
|
||||
import re
|
||||
|
||||
try:
|
||||
with open('/tmp/ai_prompt_response.json', 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
if 'error' in data:
|
||||
print('ERROR: ' + data['error'].get('message', 'Unknown error'))
|
||||
# 使用默认提示词
|
||||
print('DOUBAO_PROMPT=Chinese New Year celebration, red lanterns, traditional festival, festive atmosphere, Chinese style')
|
||||
print('NANO_PROMPT=Chinese New Year, modern design, flat style, vibrant colors, Memphis style')
|
||||
else:
|
||||
content = data['choices'][0]['message']['content']
|
||||
|
||||
# 提取豆包提示词
|
||||
doubao_match = re.search(r'豆包提示词[::]\s*([^\n]+)', content)
|
||||
if doubao_match:
|
||||
doubao_prompt = doubao_match.group(1).strip()
|
||||
else:
|
||||
parts = content.split('创意提示词')
|
||||
if len(parts) > 0:
|
||||
doubao_prompt = parts[0].replace('豆包提示词', '').replace('[提示词]', '').strip()
|
||||
else:
|
||||
doubao_prompt = content.strip()
|
||||
|
||||
# 提取创意提示词
|
||||
nano_match = re.search(r'创意提示词[::]\s*([^\n]+)', content)
|
||||
if nano_match:
|
||||
nano_prompt = nano_match.group(1).strip()
|
||||
else:
|
||||
parts = content.split('豆包提示词')
|
||||
if len(parts) > 1:
|
||||
nano_prompt = parts[1].replace('创意提示词', '').replace('[提示词]', '').strip()
|
||||
else:
|
||||
nano_prompt = ''
|
||||
|
||||
print('DOUBAO_PROMPT=' + doubao_prompt)
|
||||
print('NANO_PROMPT=' + nano_prompt)
|
||||
|
||||
except Exception as e:
|
||||
print('ERROR: ' + str(e))
|
||||
print('DOUBAO_PROMPT=Chinese New Year celebration, red lanterns, traditional festival, festive atmosphere, Chinese style')
|
||||
print('NANO_PROMPT=Chinese New Year, modern design, flat style, vibrant colors, Memphis style')
|
||||
PYEOF
|
||||
}
|
||||
|
||||
# 生成豆包提示词的3个变体
|
||||
generate_doubao_variations() {
|
||||
local base_prompt="$1"
|
||||
|
||||
# 变体1:强调氛围夜景
|
||||
local var1="$base_prompt, cinematic lighting, night scene, lanterns glowing, festive atmosphere, dramatic"
|
||||
|
||||
# 变体2:强调人物活动
|
||||
local var2="$base_prompt, happy crowd, people celebrating, lively atmosphere, traditional costumes, dynamic composition"
|
||||
|
||||
# 变体3:强调元素特写
|
||||
local var3="$base_prompt, close-up view, detailed, main subject focus, premium quality, 8k"
|
||||
|
||||
echo "$var1"
|
||||
echo "$var2"
|
||||
echo "$var3"
|
||||
}
|
||||
|
||||
# 根据参数调用对应函数
|
||||
case "$1" in
|
||||
ai)
|
||||
generate_prompt_with_ai "$2"
|
||||
;;
|
||||
variations)
|
||||
generate_doubao_variations "$2"
|
||||
;;
|
||||
*)
|
||||
echo "======================================"
|
||||
echo "🤖 AI海报提示词生成器"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo "用法: $0 ai <活动文案内容>"
|
||||
echo ""
|
||||
echo "示例: "
|
||||
echo ' $0 ai "活动名称:春节游园会"'
|
||||
;;
|
||||
esac
|
||||
231
event-publisher/scripts/upload_event.sh
Executable file
231
event-publisher/scripts/upload_event.sh
Executable file
@@ -0,0 +1,231 @@
|
||||
#!/bin/bash
|
||||
# 活动上传脚本 - 活动发布 skill
|
||||
# 支持:上传图片 -> 发布活动
|
||||
|
||||
# 获取脚本所在目录的绝对路径
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
ASSETS_DIR="$SKILL_DIR/assets"
|
||||
|
||||
# 加载环境变量
|
||||
if [ -f "$SCRIPT_DIR/.env" ]; then
|
||||
source "$SCRIPT_DIR/.env"
|
||||
elif [ -f "$SKILL_DIR/.env" ]; then
|
||||
source "$SKILL_DIR/.env"
|
||||
fi
|
||||
|
||||
# 默认配置
|
||||
UPLOAD_API_URL="${UPLOAD_API_URL:-https://data.tangledup-ai.com/upload?folder=images%2Factivity_banner}"
|
||||
ACTIVITY_API_URL="${ACTIVITY_API_URL:-https://market.quant-speed.com/api/community/admin-publish/publish_activity/}"
|
||||
APIKEY="${APIKEY:-123quant-speed}"
|
||||
PHONE_NUMBER="${PHONE_NUMBER:-18585164448}"
|
||||
CSRF_TOKEN="${CSRF_TOKEN:-SLbtIrU87YwAvDxE8PfmdG84RqQPp6HeRSEFDvnQEf9fgsElipoRKNJO5oCgabcJ}"
|
||||
|
||||
# 上传图片到OSS
|
||||
upload_image() {
|
||||
local image_file="$1"
|
||||
|
||||
echo "======================================"
|
||||
echo "📤 步骤1: 上传图片到OSS"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
if [ ! -f "$image_file" ]; then
|
||||
echo "❌ 图片文件不存在: $image_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo ">>> 正在上传: $image_file"
|
||||
|
||||
# 上传图片
|
||||
response=$(curl -s -X POST "$UPLOAD_API_URL" \
|
||||
-H "accept: application/json" \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
-F "file=@$image_file")
|
||||
|
||||
# 解析响应
|
||||
echo "$response" | python3 -c "
|
||||
import sys, json
|
||||
|
||||
try:
|
||||
data = json.load(sys.stdin)
|
||||
if data.get('success'):
|
||||
print('✅ 图片上传成功!')
|
||||
print(' File URL:', data.get('file_url'))
|
||||
print(' Object Key:', data.get('object_key'))
|
||||
else:
|
||||
print('❌ 图片上传失败:', data.get('message'))
|
||||
except:
|
||||
print('❌ 解析响应失败')
|
||||
print(response)
|
||||
"
|
||||
|
||||
# 提取URL
|
||||
local file_url=$(echo "$response" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('file_url', ''))" 2>/dev/null)
|
||||
|
||||
if [ -n "$file_url" ]; then
|
||||
echo ""
|
||||
echo "UPLOAD_URL=$file_url"
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 发布活动 - 使用文件作为description
|
||||
publish_activity() {
|
||||
local banner_url="$1"
|
||||
local title="$2"
|
||||
local description_file="$3"
|
||||
local start_time="$4"
|
||||
local end_time="$5"
|
||||
local location="$6"
|
||||
local max_participants="${7:-100}"
|
||||
|
||||
echo "======================================"
|
||||
echo "📝 步骤2: 发布活动"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo ">>> 活动标题: $title"
|
||||
echo ">>> 活动时间: $start_time - $end_time"
|
||||
echo ">>> 活动地点: $location"
|
||||
echo ">>> 海报URL: $banner_url"
|
||||
|
||||
# 读取description文件内容
|
||||
local description=""
|
||||
if [ -f "$description_file" ]; then
|
||||
description=$(cat "$description_file")
|
||||
echo ">>> 活动描述文件: $description_file (已读取)"
|
||||
else
|
||||
description="$description_file"
|
||||
fi
|
||||
|
||||
# 转义description中的特殊字符(处理JSON)
|
||||
description=$(echo "$description" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" | sed 's/^"//' | sed 's/"$//')
|
||||
|
||||
echo ""
|
||||
|
||||
# 构建活动数据
|
||||
local activity_json="{
|
||||
\"signup_form_config\": \"\",
|
||||
\"description\": \"$description\",
|
||||
\"title\": \"$title\",
|
||||
\"banner\": null,
|
||||
\"banner_url\": \"$banner_url\",
|
||||
\"start_time\": \"$start_time\",
|
||||
\"end_time\": \"$end_time\",
|
||||
\"location\": \"$location\",
|
||||
\"max_participants\": $max_participants,
|
||||
\"is_paid\": false,
|
||||
\"price\": \"0\",
|
||||
\"is_active\": true,
|
||||
\"is_visible\": true,
|
||||
\"auto_confirm\": true,
|
||||
\"ask_name\": true,
|
||||
\"ask_phone\": true,
|
||||
\"ask_wechat\": true,
|
||||
\"ask_company\": true
|
||||
}"
|
||||
|
||||
# 发布活动
|
||||
response=$(curl -s -X POST "$ACTIVITY_API_URL?apikey=$APIKEY&phone_number=$PHONE_NUMBER" \
|
||||
-H "accept: */*" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-CSRFTOKEN: $csrf_token" \
|
||||
-d "$activity_json")
|
||||
|
||||
echo "$response" | python3 -c "
|
||||
import sys, json
|
||||
|
||||
try:
|
||||
data = json.load(sys.stdin)
|
||||
if data.get('id'):
|
||||
print('✅ 活动发布成功!')
|
||||
print(' 活动ID:', data.get('id'))
|
||||
print(' 活动标题:', data.get('title'))
|
||||
print(' 创建时间:', data.get('created_at'))
|
||||
else:
|
||||
print('❌ 活动发布失败')
|
||||
print(response)
|
||||
except:
|
||||
print('❌ 解析响应失败')
|
||||
print(response)
|
||||
"
|
||||
|
||||
# 提取活动ID
|
||||
local activity_id=$(echo "$response" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('id', ''))" 2>/dev/null)
|
||||
|
||||
if [ -n "$activity_id" ]; then
|
||||
echo ""
|
||||
echo "ACTIVITY_ID=$activity_id"
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 完整流程:上传图片并发布活动
|
||||
upload_and_publish() {
|
||||
local image_file="$1"
|
||||
local title="$2"
|
||||
local description_file="$3"
|
||||
local start_time="$4"
|
||||
local end_time="$5"
|
||||
local location="$6"
|
||||
local max_participants="${7:-100}"
|
||||
|
||||
echo "======================================"
|
||||
echo "🎉 开始发布活动"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
# 步骤1: 上传图片
|
||||
local upload_result=$(upload_image "$image_file")
|
||||
local banner_url=$(echo "$upload_result" | grep "UPLOAD_URL=" | sed 's/UPLOAD_URL=//')
|
||||
|
||||
if [ -z "$banner_url" ]; then
|
||||
echo "❌ 图片上传失败,无法继续发布活动"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# 步骤2: 发布活动(传递description文件路径)
|
||||
publish_activity "$banner_url" "$title" "$description_file" "$start_time" "$end_time" "$location" "$max_participants"
|
||||
|
||||
echo ""
|
||||
echo "======================================"
|
||||
echo "✅ 活动发布完成!"
|
||||
echo "======================================"
|
||||
}
|
||||
|
||||
# 根据参数调用对应函数
|
||||
case "$1" in
|
||||
upload)
|
||||
upload_image "$2"
|
||||
;;
|
||||
publish)
|
||||
publish_activity "$2" "$3" "$4" "$5" "$6" "$7" "$8"
|
||||
;;
|
||||
all)
|
||||
upload_and_publish "$2" "$3" "$4" "$5" "$6" "$7"
|
||||
;;
|
||||
*)
|
||||
echo "======================================"
|
||||
echo "📤 活动发布工具"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo "用法: $0 <upload|publish|all> [参数]"
|
||||
echo ""
|
||||
echo "命令:"
|
||||
echo " upload <图片文件> - 仅上传图片"
|
||||
echo " all <图片文件> <标题> <描述文件> <开始时间> <结束时间> <地点> [最大人数]"
|
||||
echo " - 上传图片并发布活动"
|
||||
echo ""
|
||||
echo "时间格式: 2026-03-04T05:30:03Z"
|
||||
echo ""
|
||||
echo "示例: "
|
||||
echo ' $0 upload /path/to/image.jpg'
|
||||
echo ' $0 all ./assets/image.jpg "春节游园会" "./assets/活动文案.md" "2026-03-15T10:00:00Z" "2026-03-15T16:00:00Z" "市中心广场"'
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user