Initial commit with translated description
This commit is contained in:
100
SKILL.md
Normal file
100
SKILL.md
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
---
|
||||||
|
name: ai-picture-book
|
||||||
|
description: "使用百度AI生成静态或动态绘本视频。"
|
||||||
|
metadata: { "openclaw": { "emoji": "📔", "requires": { "bins": ["python3"], "env":["BAIDU_API_KEY"]},"primaryEnv":"BAIDU_API_KEY" } }
|
||||||
|
---
|
||||||
|
|
||||||
|
# AI Picture Book
|
||||||
|
|
||||||
|
Generate picture book videos from stories or descriptions.
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. **Create Task**: Submit story + type → get task ID
|
||||||
|
2. **Poll Status**: Query every 5-10s until completion
|
||||||
|
3. **Get Results**: Retrieve video URLs when status = 2
|
||||||
|
|
||||||
|
## Book Types
|
||||||
|
|
||||||
|
| Type | Method | Description |
|
||||||
|
|------|--------|-------------|
|
||||||
|
| Static | 9 | Static picture book |
|
||||||
|
| Dynamic | 10 | Dynamic picture book |
|
||||||
|
|
||||||
|
**Required**: User must specify type (static/9 or dynamic/10). If not provided, ask them to choose.
|
||||||
|
|
||||||
|
## Status Codes
|
||||||
|
|
||||||
|
| Code | Status | Action |
|
||||||
|
|-------|---------|---------|
|
||||||
|
| 0, 1, 3 | In Progress | Continue polling |
|
||||||
|
| 2 | Completed | Return results |
|
||||||
|
| Other | Failed | Show error |
|
||||||
|
|
||||||
|
## APIs
|
||||||
|
|
||||||
|
### Create Task
|
||||||
|
|
||||||
|
**Endpoint**: `POST /v2/tools/ai_picture_book/task_create`
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
- `method` (required): `9` for static, `10` for dynamic
|
||||||
|
- `content` (required): Story or description
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
python3 scripts/ai_picture_book_task_create.py 9 "A brave cat explores the world."
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response**:
|
||||||
|
```json
|
||||||
|
{ "task_id": "uuid-string" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Query Task
|
||||||
|
|
||||||
|
**Endpoint**: `GET /v2/tools/ai_picture_book/query`
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
- `task_id` (required): Task ID from create endpoint
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
python3 scripts/ai_picture_book_task_query.py "task-id-here"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response** (Completed):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": 2,
|
||||||
|
"video_bos_url": "https://...",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Polling Strategy
|
||||||
|
|
||||||
|
### Auto Polling (Recommended)
|
||||||
|
```bash
|
||||||
|
python3 scripts/ai_picture_book_poll.py <task_id> [max_attempts] [interval_seconds]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
```bash
|
||||||
|
# Default: 20 attempts, 5s intervals
|
||||||
|
python3 scripts/ai_picture_book_poll.py "task-id-here"
|
||||||
|
|
||||||
|
# Custom: 30 attempts, 10s intervals
|
||||||
|
python3 scripts/ai_picture_book_poll.py "task-id-here" 30 10
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Polling
|
||||||
|
1. Create task → store `task_id`
|
||||||
|
2. Query every 5-10s until status = 2
|
||||||
|
3. Timeout after 2-3 minutes
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
- Invalid content: "Content cannot be empty"
|
||||||
|
- Invalid type: "Invalid type. Use 9 (static) or 10 (dynamic)"
|
||||||
|
- Processing error: "Failed to generate picture book"
|
||||||
|
- Timeout: "Task timed out. Try again later"
|
||||||
6
_meta.json
Normal file
6
_meta.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"ownerId": "kn7akgt520t01vgs2tzx7yk6m180kt26",
|
||||||
|
"slug": "ai-picture-book",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"publishedAt": 1770956044079
|
||||||
|
}
|
||||||
125
scripts/ai_picture_book_poll.py
Normal file
125
scripts/ai_picture_book_poll.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
AI Picture Book - Poll Task
|
||||||
|
Automatically poll task until completion with progress updates.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
from typing import Dict, Any
|
||||||
|
|
||||||
|
STATUS_CODES = {
|
||||||
|
0: "in_progress",
|
||||||
|
1: "in_progress",
|
||||||
|
2: "completed",
|
||||||
|
3: "in_progress",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def query_task(api_key: str, task_id: str) -> Dict[str, Any]:
|
||||||
|
"""Query task status."""
|
||||||
|
url = "https://qianfan.baidubce.com/v2/tools/ai_picture_book/query"
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {api_key}",
|
||||||
|
"X-Appbuilder-From": "openclaw",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
params = {"task_ids": [task_id]}
|
||||||
|
|
||||||
|
response = requests.post(url, headers=headers, json=params, timeout=5)
|
||||||
|
response.raise_for_status()
|
||||||
|
result = response.json()
|
||||||
|
|
||||||
|
if "errno" in result and result["errno"] != 0:
|
||||||
|
raise RuntimeError(result.get("errmsg", "Unknown error"))
|
||||||
|
|
||||||
|
return result["data"]
|
||||||
|
|
||||||
|
|
||||||
|
def poll_task(api_key: str, task_id: str, max_attempts: int = 20, interval: int = 5):
|
||||||
|
"""Poll task until completion or timeout.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
api_key: Baidu API key
|
||||||
|
task_id: Task ID
|
||||||
|
max_attempts: Maximum poll attempts (default 20)
|
||||||
|
interval: Seconds between polls (default 5)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Final task data
|
||||||
|
"""
|
||||||
|
data = None
|
||||||
|
for attempt in range(max_attempts):
|
||||||
|
try:
|
||||||
|
data = query_task(api_key, task_id)
|
||||||
|
if not data or len(data) == 0:
|
||||||
|
print(f"\n✗ No task data returned")
|
||||||
|
return data
|
||||||
|
|
||||||
|
status = data[0].get("status")
|
||||||
|
result = data[0].get("result", {})
|
||||||
|
if result and "video_bos_url" in result:
|
||||||
|
result = {"video_bos_url": result["video_bos_url"]}
|
||||||
|
|
||||||
|
if status == 2:
|
||||||
|
print("\n" + "=" * 50)
|
||||||
|
print("✓ PICTURE BOOK GENERATED SUCCESSFULLY")
|
||||||
|
print("=" * 50)
|
||||||
|
print(json.dumps(result, indent=2, ensure_ascii=False))
|
||||||
|
return data
|
||||||
|
|
||||||
|
elif status in [0, 1, 3]:
|
||||||
|
print(f"[{attempt + 1}/{max_attempts}] Processing...")
|
||||||
|
time.sleep(interval)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(f"\n✗ Task failed: status={status}")
|
||||||
|
print(json.dumps(data, indent=2, ensure_ascii=False))
|
||||||
|
return data
|
||||||
|
|
||||||
|
except RuntimeError as e:
|
||||||
|
print(f"\n✗ Error: {str(e)}")
|
||||||
|
return data
|
||||||
|
except Exception as e:
|
||||||
|
if attempt == max_attempts - 1:
|
||||||
|
print(f"\n✗ Unexpected error: {str(e)}")
|
||||||
|
return data
|
||||||
|
time.sleep(interval)
|
||||||
|
|
||||||
|
print(f"\n✗ Timeout after {max_attempts * interval} seconds")
|
||||||
|
print("Task may still be running. Try querying manually:")
|
||||||
|
print(f" python scripts/ai_picture_book_task_query.py {task_id}")
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print(json.dumps({
|
||||||
|
"error": "Missing task ID",
|
||||||
|
"usage": "python ai_picture_book_poll.py <task_id> [max_attempts] [interval_seconds]"
|
||||||
|
}, indent=2))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
task_id = sys.argv[1]
|
||||||
|
max_attempts = int(sys.argv[2]) if len(sys.argv) > 2 else 20
|
||||||
|
interval = int(sys.argv[3]) if len(sys.argv) > 3 else 5
|
||||||
|
|
||||||
|
api_key = os.getenv("BAIDU_API_KEY")
|
||||||
|
if not api_key:
|
||||||
|
print(json.dumps({
|
||||||
|
"error": "BAIDU_API_KEY environment variable not set"
|
||||||
|
}, indent=2))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"Polling task: {task_id}")
|
||||||
|
print(f"Max attempts: {max_attempts}, Interval: {interval}s")
|
||||||
|
print("-" * 50)
|
||||||
|
|
||||||
|
poll_task(api_key, task_id, max_attempts, interval)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
49
scripts/ai_picture_book_task_create.py
Normal file
49
scripts/ai_picture_book_task_create.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def ai_picture_book_task_create(api_key: str, method: int, content):
|
||||||
|
url = "https://qianfan.baidubce.com/v2/tools/ai_picture_book/task_create"
|
||||||
|
headers = {
|
||||||
|
"Authorization": "Bearer %s" % api_key,
|
||||||
|
"X-Appbuilder-From": "openclaw",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
params = {
|
||||||
|
"method": method,
|
||||||
|
"input_type": "1",
|
||||||
|
"input_content": content,
|
||||||
|
}
|
||||||
|
response = requests.post(url, headers=headers, json=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
result = response.json()
|
||||||
|
if "code" in result:
|
||||||
|
raise RuntimeError(result["detail"])
|
||||||
|
if "errno" in result and result["errno"] != 0:
|
||||||
|
raise RuntimeError(result["errmsg"])
|
||||||
|
return result["data"]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
print("Usage: python ai_picture_book_task_create.py <method> <content>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
method = int(sys.argv[1])
|
||||||
|
if method not in [9, 10]:
|
||||||
|
print("Error: method must be 9 or 10.")
|
||||||
|
sys.exit(1)
|
||||||
|
content = sys.argv[2]
|
||||||
|
|
||||||
|
api_key = os.getenv("BAIDU_API_KEY")
|
||||||
|
if not api_key:
|
||||||
|
print("Error: BAIDU_API_KEY must be set in environment.")
|
||||||
|
sys.exit(1)
|
||||||
|
try:
|
||||||
|
results = ai_picture_book_task_create(api_key, method, content)
|
||||||
|
print(json.dumps(results, ensure_ascii=False, indent=2))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {str(e)}")
|
||||||
|
sys.exit(1)
|
||||||
52
scripts/ai_picture_book_task_query.py
Normal file
52
scripts/ai_picture_book_task_query.py
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def ai_picture_book_task_query(api_key: str, task_id: str):
|
||||||
|
url = "https://qianfan.baidubce.com/v2/tools/ai_picture_book/query"
|
||||||
|
headers = {
|
||||||
|
"Authorization": "Bearer %s" % api_key,
|
||||||
|
"X-Appbuilder-From": "openclaw",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
task_ids = task_id.split(",")
|
||||||
|
params = {
|
||||||
|
"task_ids": task_ids,
|
||||||
|
}
|
||||||
|
response = requests.post(url, headers=headers, json=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
result = response.json()
|
||||||
|
datas = []
|
||||||
|
if "code" in result:
|
||||||
|
raise RuntimeError(result["detail"])
|
||||||
|
if "errno" in result and result["errno"] != 0:
|
||||||
|
raise RuntimeError(result["errmsg"])
|
||||||
|
if "data" in result and len(result["data"]) > 0:
|
||||||
|
for item in result["data"]:
|
||||||
|
if item["result"]:
|
||||||
|
bosUrl = item["result"].get("video_bos_url", "")
|
||||||
|
del item["result"]
|
||||||
|
item["video_bos_url"] = bosUrl
|
||||||
|
datas.append(item)
|
||||||
|
return datas
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python ai_picture_book_task_query.py <task_ids>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
task_ids = sys.argv[1]
|
||||||
|
|
||||||
|
api_key = os.getenv("BAIDU_API_KEY")
|
||||||
|
if not api_key:
|
||||||
|
print("Error: BAIDU_API_KEY must be set in environment.")
|
||||||
|
sys.exit(1)
|
||||||
|
try:
|
||||||
|
results = ai_picture_book_task_query(api_key, task_ids)
|
||||||
|
print(json.dumps(results, ensure_ascii=False, indent=2))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {str(e)}")
|
||||||
|
sys.exit(1)
|
||||||
Reference in New Issue
Block a user