fix: wp-tools 插件修复 - register 同步化 + images 参数 + 新增 wp_publish_with_image 工具

修复内容:
- 修复 register must be synchronous 错误(去掉 async 关键字)
- wp_publish 新增 images 参数支持图片上传到 WordPress 媒体库
- 新增 wp_publish_with_image 工具一步完成生图 + 发布
- 更新 wp_generate_image 描述说明图片上传流程

修改文件:
- wp-tools/index.js (data/plugins/wp-tools/index.js)
- wp-tools/index_extensions.js (data/extensions/wp-tools/index.js)
- wp-tools/openclaw.plugin.json (更新 contracts.tools 列表)
This commit is contained in:
shaowu 2026-05-14 15:00:20 +08:00
parent d1f440a8a0
commit 860e8aaa46
3 changed files with 661 additions and 0 deletions

323
wp-tools/index.js Normal file
View File

@ -0,0 +1,323 @@
/**
* WordPress Tools - OpenClaw 插件
* 提供 WordPress 发布和 AI 生图工具
*
* 修复说明
* 1. register 改为同步方法解决 "register must be synchronous" 错误
* 2. wp_publish 新增 images 参数支持传入图片路径上传到媒体库
* 3. 新增 wp_publish_with_image 工具一步完成生图+发布
*/
import { spawn } from 'child_process';
// WordPress 发布脚本路径
const WP_PUBLISH_SCRIPT = '/www/wwwroot/wp-publish/scripts/wp_publish_text.py';
const WP_GENERATE_SCRIPT = '/www/wwwroot/wp-publish/scripts/wp_generate_image.py';
const PYTHON_PATH = '/usr/bin/python3';
/**
* 执行 Python 脚本
*/
function executePythonScript(scriptPath, args) {
return new Promise((resolve, reject) => {
const process = spawn(PYTHON_PATH, [scriptPath, ...args], {
env: { ...process.env },
stdio: ['pipe', 'pipe', 'pipe']
});
let stdout = '';
let stderr = '';
process.stdout.on('data', (data) => {
stdout += data.toString();
});
process.stderr.on('data', (data) => {
stderr += data.toString();
});
process.on('close', (code) => {
if (code === 0) {
resolve(stdout);
} else {
reject(new Error(`脚本执行失败: ${stderr}`));
}
});
process.on('error', (error) => {
reject(error);
});
});
}
/**
* 定义插件入口
*/
export default {
id: 'wp-tools',
name: 'WordPress Tools',
description: 'WordPress 发布和 AI 生图工具',
// 修复1去掉 async改为同步注册
register(api) {
// ========== 工具 1WordPress 发布 ==========
api.registerTool({
name: 'wp_publish',
description: '发布文章到 WordPress 网站。支持文字内容和图片上传。',
parameters: {
type: 'object',
properties: {
text: {
type: 'string',
description: '文章内容(必填)'
},
title: {
type: 'string',
description: '文章标题(可选,默认从内容提取)'
},
category: {
type: 'string',
description: '分类名称ai, ai-kepu, jishu 等)'
},
tags: {
type: 'string',
description: '标签(可选)'
},
status: {
type: 'string',
description: '发布状态publish/draft',
enum: ['publish', 'draft']
},
images: {
type: 'string',
description: '图片文件路径可选多个路径用逗号分隔。AI 生图完成后,将返回的图片路径传入此参数即可自动上传到 WordPress 媒体库。'
}
},
required: ['text']
},
async execute(_id, params) {
try {
const args = [
params.text,
'--title', params.title || '',
'--instruction', params.category ? `#分类 ${params.category}` : '',
'--status', params.status || 'publish'
];
// 修复2支持传入图片路径
if (params.images) {
const imagePaths = params.images.split(',').map(p => p.trim()).filter(Boolean);
for (const imgPath of imagePaths) {
args.push('--images', imgPath);
}
}
const result = await executePythonScript(WP_PUBLISH_SCRIPT, args);
return {
content: [{
type: 'text',
text: `✅ 文章发布成功!\n\n${result}`
}]
};
} catch (error) {
return {
content: [{
type: 'text',
text: `❌ 发布失败:${error.message}`
}]
};
}
}
});
// ========== 工具 2AI 生图 ==========
api.registerTool({
name: 'wp_generate_image',
description: '使用 AI 生成图片。支持通义万相模型,可指定尺寸、格式和数量。生成后的图片可通过 wp_publish 的 images 参数上传到 WordPress 媒体库。',
parameters: {
type: 'object',
properties: {
prompt: {
type: 'string',
description: '图片描述(必填,如:一只可爱的猫咪在草地上晒太阳)'
},
model: {
type: 'string',
description: '模型名称默认wanx-v1',
enum: ['wanx-v1', 'wanx2.1-t2i-turbo', 'wanx2.1-t2i-plus']
},
size: {
type: 'string',
description: '图片尺寸默认1024*1024',
enum: ['1024*1024', '720*1280', '1280*720', '512*512']
},
format: {
type: 'string',
description: '图片格式默认webp',
enum: ['webp', 'jpg', 'png']
},
count: {
type: 'number',
description: '生成数量1-4默认1',
minimum: 1,
maximum: 4
},
style: {
type: 'string',
description: '图片风格(如:写实、动漫、水彩等)'
}
},
required: ['prompt']
},
async execute(_id, params) {
try {
const args = [
params.prompt,
'--model', params.model || 'wanx-v1',
'--size', params.size || '1024*1024',
'--format', params.format || 'webp',
'--count', params.count || 1
];
if (params.style) {
args.push('--style', params.style);
}
const result = await executePythonScript(WP_GENERATE_SCRIPT, args);
return {
content: [{
type: 'text',
text: `✅ AI 生图完成!\n\n${result}`
}]
};
} catch (error) {
return {
content: [{
type: 'text',
text: `❌ AI 生图失败:${error.message}`
}]
};
}
}
});
// ========== 工具 3生图并发布新增 ==========
api.registerTool({
name: 'wp_publish_with_image',
description: '一步完成 AI 生图并发布到 WordPress。自动执行生图 → 上传到媒体库 → 发布文章。',
parameters: {
type: 'object',
properties: {
title: {
type: 'string',
description: '文章标题(必填)'
},
text: {
type: 'string',
description: '文章内容(必填)'
},
image_prompt: {
type: 'string',
description: '图片描述(必填,用于 AI 生图)'
},
image_model: {
type: 'string',
description: '生图模型默认wanx-v1',
enum: ['wanx-v1', 'wanx2.1-t2i-turbo', 'wanx2.1-t2i-plus']
},
image_size: {
type: 'string',
description: '图片尺寸默认1024*1024',
enum: ['1024*1024', '720*1280', '1280*720', '512*512']
},
category: {
type: 'string',
description: '分类名称'
},
tags: {
type: 'string',
description: '标签'
},
status: {
type: 'string',
description: '发布状态publish/draft',
enum: ['publish', 'draft']
}
},
required: ['title', 'text', 'image_prompt']
},
async execute(_id, params) {
try {
// 步骤1先调用生图
const genArgs = [
params.image_prompt,
'--model', params.image_model || 'wanx-v1',
'--size', params.image_size || '1024*1024',
'--format', 'jpg',
'--count', '1'
];
const genResult = await executePythonScript(WP_GENERATE_SCRIPT, genArgs);
// 从生图结果中提取图片路径
let imagePath = '';
try {
// 尝试从输出中提取 JSON 中的 paths
const jsonMatch = genResult.match(/\{[\s\S]*"paths"[\s\S]*\}/);
if (jsonMatch) {
const genJson = JSON.parse(jsonMatch[0]);
if (genJson.paths && genJson.paths.length > 0) {
imagePath = genJson.paths[0];
}
}
} catch (e) {
// 如果解析失败,尝试从文本中提取路径
const pathMatch = genResult.match(/\/www\/wwwroot\/wp-publish\/temp\/[\w.]+/);
if (pathMatch) {
imagePath = pathMatch[0];
}
}
if (!imagePath) {
return {
content: [{
type: 'text',
text: `⚠️ 图片生成完成但未找到路径,直接发布文字内容。\n\n生图结果:${genResult}`
}]
};
}
// 步骤2发布文章并上传图片
const pubArgs = [
params.text,
'--title', params.title,
'--instruction', params.category ? `#分类 ${params.category}` : '',
'--status', params.status || 'publish',
'--images', imagePath
];
const pubResult = await executePythonScript(WP_PUBLISH_SCRIPT, pubArgs);
return {
content: [{
type: 'text',
text: `✅ 生图并发布成功!\n\n生图结果:${genResult}\n\n发布结果:${pubResult}`
}]
};
} catch (error) {
return {
content: [{
type: 'text',
text: `❌ 操作失败:${error.message}`
}]
};
}
}
});
console.log('[wp-tools] WordPress 工具已注册');
}
};

View File

@ -0,0 +1,323 @@
/**
* WordPress Tools - OpenClaw 插件
* 提供 WordPress 发布和 AI 生图工具
*
* 修复说明
* 1. register 改为同步方法解决 "register must be synchronous" 错误
* 2. wp_publish 新增 images 参数支持传入图片路径上传到媒体库
* 3. 新增 wp_publish_with_image 工具一步完成生图+发布
*/
import { spawn } from 'child_process';
// WordPress 发布脚本路径
const WP_PUBLISH_SCRIPT = '/www/wwwroot/wp-publish/scripts/wp_publish_text.py';
const WP_GENERATE_SCRIPT = '/www/wwwroot/wp-publish/scripts/wp_generate_image.py';
const PYTHON_PATH = '/usr/bin/python3';
/**
* 执行 Python 脚本
*/
function executePythonScript(scriptPath, args) {
return new Promise((resolve, reject) => {
const process = spawn(PYTHON_PATH, [scriptPath, ...args], {
env: { ...process.env },
stdio: ['pipe', 'pipe', 'pipe']
});
let stdout = '';
let stderr = '';
process.stdout.on('data', (data) => {
stdout += data.toString();
});
process.stderr.on('data', (data) => {
stderr += data.toString();
});
process.on('close', (code) => {
if (code === 0) {
resolve(stdout);
} else {
reject(new Error(`脚本执行失败: ${stderr}`));
}
});
process.on('error', (error) => {
reject(error);
});
});
}
/**
* 定义插件入口
*/
export default {
id: 'wp-tools',
name: 'WordPress Tools',
description: 'WordPress 发布和 AI 生图工具',
// 修复1去掉 async改为同步注册
register(api) {
// ========== 工具 1WordPress 发布 ==========
api.registerTool({
name: 'wp_publish',
description: '发布文章到 WordPress 网站。支持文字内容和图片上传。',
parameters: {
type: 'object',
properties: {
text: {
type: 'string',
description: '文章内容(必填)'
},
title: {
type: 'string',
description: '文章标题(可选,默认从内容提取)'
},
category: {
type: 'string',
description: '分类名称ai, ai-kepu, jishu 等)'
},
tags: {
type: 'string',
description: '标签(可选)'
},
status: {
type: 'string',
description: '发布状态publish/draft',
enum: ['publish', 'draft']
},
images: {
type: 'string',
description: '图片文件路径可选多个路径用逗号分隔。AI 生图完成后,将返回的图片路径传入此参数即可自动上传到 WordPress 媒体库。'
}
},
required: ['text']
},
async execute(_id, params) {
try {
const args = [
params.text,
'--title', params.title || '',
'--instruction', params.category ? `#分类 ${params.category}` : '',
'--status', params.status || 'publish'
];
// 修复2支持传入图片路径
if (params.images) {
const imagePaths = params.images.split(',').map(p => p.trim()).filter(Boolean);
for (const imgPath of imagePaths) {
args.push('--images', imgPath);
}
}
const result = await executePythonScript(WP_PUBLISH_SCRIPT, args);
return {
content: [{
type: 'text',
text: `✅ 文章发布成功!\n\n${result}`
}]
};
} catch (error) {
return {
content: [{
type: 'text',
text: `❌ 发布失败:${error.message}`
}]
};
}
}
});
// ========== 工具 2AI 生图 ==========
api.registerTool({
name: 'wp_generate_image',
description: '使用 AI 生成图片。支持通义万相模型,可指定尺寸、格式和数量。生成后的图片可通过 wp_publish 的 images 参数上传到 WordPress 媒体库。',
parameters: {
type: 'object',
properties: {
prompt: {
type: 'string',
description: '图片描述(必填,如:一只可爱的猫咪在草地上晒太阳)'
},
model: {
type: 'string',
description: '模型名称默认wanx-v1',
enum: ['wanx-v1', 'wanx2.1-t2i-turbo', 'wanx2.1-t2i-plus']
},
size: {
type: 'string',
description: '图片尺寸默认1024*1024',
enum: ['1024*1024', '720*1280', '1280*720', '512*512']
},
format: {
type: 'string',
description: '图片格式默认webp',
enum: ['webp', 'jpg', 'png']
},
count: {
type: 'number',
description: '生成数量1-4默认1',
minimum: 1,
maximum: 4
},
style: {
type: 'string',
description: '图片风格(如:写实、动漫、水彩等)'
}
},
required: ['prompt']
},
async execute(_id, params) {
try {
const args = [
params.prompt,
'--model', params.model || 'wanx-v1',
'--size', params.size || '1024*1024',
'--format', params.format || 'webp',
'--count', params.count || 1
];
if (params.style) {
args.push('--style', params.style);
}
const result = await executePythonScript(WP_GENERATE_SCRIPT, args);
return {
content: [{
type: 'text',
text: `✅ AI 生图完成!\n\n${result}`
}]
};
} catch (error) {
return {
content: [{
type: 'text',
text: `❌ AI 生图失败:${error.message}`
}]
};
}
}
});
// ========== 工具 3生图并发布新增 ==========
api.registerTool({
name: 'wp_publish_with_image',
description: '一步完成 AI 生图并发布到 WordPress。自动执行生图 → 上传到媒体库 → 发布文章。',
parameters: {
type: 'object',
properties: {
title: {
type: 'string',
description: '文章标题(必填)'
},
text: {
type: 'string',
description: '文章内容(必填)'
},
image_prompt: {
type: 'string',
description: '图片描述(必填,用于 AI 生图)'
},
image_model: {
type: 'string',
description: '生图模型默认wanx-v1',
enum: ['wanx-v1', 'wanx2.1-t2i-turbo', 'wanx2.1-t2i-plus']
},
image_size: {
type: 'string',
description: '图片尺寸默认1024*1024',
enum: ['1024*1024', '720*1280', '1280*720', '512*512']
},
category: {
type: 'string',
description: '分类名称'
},
tags: {
type: 'string',
description: '标签'
},
status: {
type: 'string',
description: '发布状态publish/draft',
enum: ['publish', 'draft']
}
},
required: ['title', 'text', 'image_prompt']
},
async execute(_id, params) {
try {
// 步骤1先调用生图
const genArgs = [
params.image_prompt,
'--model', params.image_model || 'wanx-v1',
'--size', params.image_size || '1024*1024',
'--format', 'jpg',
'--count', '1'
];
const genResult = await executePythonScript(WP_GENERATE_SCRIPT, genArgs);
// 从生图结果中提取图片路径
let imagePath = '';
try {
// 尝试从输出中提取 JSON 中的 paths
const jsonMatch = genResult.match(/\{[\s\S]*"paths"[\s\S]*\}/);
if (jsonMatch) {
const genJson = JSON.parse(jsonMatch[0]);
if (genJson.paths && genJson.paths.length > 0) {
imagePath = genJson.paths[0];
}
}
} catch (e) {
// 如果解析失败,尝试从文本中提取路径
const pathMatch = genResult.match(/\/www\/wwwroot\/wp-publish\/temp\/[\w.]+/);
if (pathMatch) {
imagePath = pathMatch[0];
}
}
if (!imagePath) {
return {
content: [{
type: 'text',
text: `⚠️ 图片生成完成但未找到路径,直接发布文字内容。\n\n生图结果:${genResult}`
}]
};
}
// 步骤2发布文章并上传图片
const pubArgs = [
params.text,
'--title', params.title,
'--instruction', params.category ? `#分类 ${params.category}` : '',
'--status', params.status || 'publish',
'--images', imagePath
];
const pubResult = await executePythonScript(WP_PUBLISH_SCRIPT, pubArgs);
return {
content: [{
type: 'text',
text: `✅ 生图并发布成功!\n\n生图结果:${genResult}\n\n发布结果:${pubResult}`
}]
};
} catch (error) {
return {
content: [{
type: 'text',
text: `❌ 操作失败:${error.message}`
}]
};
}
}
});
console.log('[wp-tools] WordPress 工具已注册');
}
};

View File

@ -0,0 +1,15 @@
{
"id": "wp-tools",
"name": "WordPress Tools",
"description": "WordPress 发布和 AI 生图工具",
"contracts": {
"tools": ["wp_publish", "wp_generate_image", "wp_publish_with_image"]
},
"activation": {
"onStartup": true
},
"configSchema": {
"type": "object",
"additionalProperties": false
}
}