|
@@ -2,6 +2,7 @@
|
|
|
* fun 解析与执行 + 执行入口:registry/executeAction 由 ctx 传入(来自 workflow-json-parser),本模块负责 parse/runAction/run/supports
|
|
* fun 解析与执行 + 执行入口:registry/executeAction 由 ctx 传入(来自 workflow-json-parser),本模块负责 parse/runAction/run/supports
|
|
|
*/
|
|
*/
|
|
|
const path = require('path')
|
|
const path = require('path')
|
|
|
|
|
+const variableParser = require('../variable-parser.js')
|
|
|
|
|
|
|
|
const FUN_REGISTRY_TYPES = [
|
|
const FUN_REGISTRY_TYPES = [
|
|
|
'fun',
|
|
'fun',
|
|
@@ -10,7 +11,7 @@ const FUN_REGISTRY_TYPES = [
|
|
|
'read-last-message', 'smart-chat-append',
|
|
'read-last-message', 'smart-chat-append',
|
|
|
'extract-messages', 'ocr-chat', 'ocr-chat-history', 'extract-chat-history',
|
|
'extract-messages', 'ocr-chat', 'ocr-chat-history', 'extract-chat-history',
|
|
|
'save-messages', 'generate-summary', 'generate-history-summary',
|
|
'save-messages', 'generate-summary', 'generate-history-summary',
|
|
|
- 'ai-generate', 'string-press',
|
|
|
|
|
|
|
+ 'ai-generate', 'string-press','download',
|
|
|
]
|
|
]
|
|
|
|
|
|
|
|
const types = FUN_REGISTRY_TYPES
|
|
const types = FUN_REGISTRY_TYPES
|
|
@@ -112,6 +113,9 @@ function parse(action, parseContext) {
|
|
|
parsed.savePath = action.inVars?.[1] ?? action.savePath
|
|
parsed.savePath = action.inVars?.[1] ?? action.savePath
|
|
|
if (action.outVars && action.outVars.length > 0) parsed.variable = extractVarName(action.outVars[0])
|
|
if (action.outVars && action.outVars.length > 0) parsed.variable = extractVarName(action.outVars[0])
|
|
|
break
|
|
break
|
|
|
|
|
+ case 'download':
|
|
|
|
|
+ parsed.variable = action.outVars?.[0] ? extractVarName(action.outVars[0]) : extractVarName(action.variable)
|
|
|
|
|
+ break
|
|
|
default:
|
|
default:
|
|
|
parsed.inVars = action.inVars && Array.isArray(action.inVars) ? action.inVars.map(v => extractVarName(v)) : []
|
|
parsed.inVars = action.inVars && Array.isArray(action.inVars) ? action.inVars.map(v => extractVarName(v)) : []
|
|
|
parsed.outVars = action.outVars && Array.isArray(action.outVars) ? action.outVars.map(v => extractVarName(v)) : []
|
|
parsed.outVars = action.outVars && Array.isArray(action.outVars) ? action.outVars.map(v => extractVarName(v)) : []
|
|
@@ -130,16 +134,17 @@ async function runAction(action, device, folderPath, resolution, ctx) {
|
|
|
return { success: true, skipped: true }
|
|
return { success: true, skipped: true }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (action.type === 'fun' && action.method) {
|
|
|
|
|
- return run(action.method, action, ctx, device, folderPath)
|
|
|
|
|
|
|
+ const resolvedAction = variableParser.resolveActionInputs(action, variableContext)
|
|
|
|
|
+
|
|
|
|
|
+ if (resolvedAction.type === 'fun' && resolvedAction.method) {
|
|
|
|
|
+ return run(resolvedAction.method, resolvedAction, ctx, device, folderPath)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // fun 类 type(如 img-center-point-location)必须走 run() 才会执行逻辑并写变量,不能走 registry 的 stub execute
|
|
|
|
|
- if (supports(action.type)) {
|
|
|
|
|
- return run(action.type, action, ctx, device, folderPath)
|
|
|
|
|
|
|
+ if (supports(resolvedAction.type)) {
|
|
|
|
|
+ return run(resolvedAction.type, resolvedAction, ctx, device, folderPath)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (registry && registry[action.type]) {
|
|
|
|
|
|
|
+ if (registry && registry[resolvedAction.type]) {
|
|
|
const execCtx = {
|
|
const execCtx = {
|
|
|
device,
|
|
device,
|
|
|
folderPath,
|
|
folderPath,
|
|
@@ -158,10 +163,10 @@ async function runAction(action, device, folderPath, resolution, ctx) {
|
|
|
calculateWaitTime: ctx.calculateWaitTime,
|
|
calculateWaitTime: ctx.calculateWaitTime,
|
|
|
DEFAULT_SCROLL_DISTANCE: ctx.DEFAULT_SCROLL_DISTANCE,
|
|
DEFAULT_SCROLL_DISTANCE: ctx.DEFAULT_SCROLL_DISTANCE,
|
|
|
}
|
|
}
|
|
|
- return await executeAction(action.type, action, execCtx)
|
|
|
|
|
|
|
+ return await executeAction(resolvedAction.type, resolvedAction, execCtx)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return { success: false, error: `未知的操作类型: ${action.type}` }
|
|
|
|
|
|
|
+ return { success: false, error: `未知的操作类型: ${resolvedAction.type}` }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const cache = new Map()
|
|
const cache = new Map()
|
|
@@ -233,15 +238,14 @@ async function run(actionType, action, ctx, device, folderPath) {
|
|
|
let regionPath = action.region
|
|
let regionPath = action.region
|
|
|
if (action.inVars && Array.isArray(action.inVars)) {
|
|
if (action.inVars && Array.isArray(action.inVars)) {
|
|
|
if (action.inVars.length === 1) {
|
|
if (action.inVars.length === 1) {
|
|
|
- const firstVar = extractVarName(action.inVars[0])
|
|
|
|
|
- const firstValue = variableContext[firstVar]
|
|
|
|
|
- regionPath = firstValue && typeof firstValue === 'string' && !firstValue.includes('{') ? firstValue : action.inVars[0]
|
|
|
|
|
|
|
+ const firstValue = variableContext[extractVarName(action.inVars[0])] ?? resolveValue(action.inVars[0], variableContext)
|
|
|
|
|
+ regionPath = firstValue != null && typeof firstValue === 'string' && !String(firstValue).includes('{') ? firstValue : action.inVars[0]
|
|
|
screenshotPath = null
|
|
screenshotPath = null
|
|
|
} else if (action.inVars.length >= 2) {
|
|
} else if (action.inVars.length >= 2) {
|
|
|
- const sv = variableContext[extractVarName(action.inVars[0])]
|
|
|
|
|
- screenshotPath = sv && typeof sv === 'string' && !sv.includes('{') ? sv : action.inVars[0]
|
|
|
|
|
- const rv = variableContext[extractVarName(action.inVars[1])]
|
|
|
|
|
- regionPath = rv && typeof rv === 'string' && !rv.includes('{') ? rv : action.inVars[1]
|
|
|
|
|
|
|
+ const sv = variableContext[extractVarName(action.inVars[0])] ?? resolveValue(action.inVars[0], variableContext)
|
|
|
|
|
+ screenshotPath = sv != null && typeof sv === 'string' && !sv.includes('{') ? sv : action.inVars[0]
|
|
|
|
|
+ const rv = variableContext[extractVarName(action.inVars[1])] ?? resolveValue(action.inVars[1], variableContext)
|
|
|
|
|
+ regionPath = rv != null && typeof rv === 'string' && !rv.includes('{') ? rv : action.inVars[1]
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
if (screenshotPath !== null && !screenshotPath) screenshotPath = action.screenshot
|
|
if (screenshotPath !== null && !screenshotPath) screenshotPath = action.screenshot
|
|
@@ -262,9 +266,8 @@ async function run(actionType, action, ctx, device, folderPath) {
|
|
|
const { executeImgCenterPointLocation } = get(funcDir, 'img')
|
|
const { executeImgCenterPointLocation } = get(funcDir, 'img')
|
|
|
let templatePath = action.template
|
|
let templatePath = action.template
|
|
|
if (action.inVars?.length > 0) {
|
|
if (action.inVars?.length > 0) {
|
|
|
- const templateVar = extractVarName(action.inVars[0])
|
|
|
|
|
- const templateValue = variableContext[templateVar]
|
|
|
|
|
- templatePath = templateValue && typeof templateValue === 'string' && !templateValue.includes('{') ? templateValue : action.inVars[0]
|
|
|
|
|
|
|
+ const templateValue = variableContext[extractVarName(action.inVars[0])] ?? resolveValue(action.inVars[0], variableContext)
|
|
|
|
|
+ templatePath = templateValue != null && typeof templateValue === 'string' && !String(templateValue).includes('{') ? templateValue : action.inVars[0]
|
|
|
}
|
|
}
|
|
|
if (!templatePath) templatePath = action.template
|
|
if (!templatePath) templatePath = action.template
|
|
|
if (!templatePath) return { success: false, error: '缺少模板图片路径' }
|
|
if (!templatePath) return { success: false, error: '缺少模板图片路径' }
|
|
@@ -285,14 +288,8 @@ async function run(actionType, action, ctx, device, folderPath) {
|
|
|
let area = action.area
|
|
let area = action.area
|
|
|
let savePath = action.savePath
|
|
let savePath = action.savePath
|
|
|
if (action.inVars && Array.isArray(action.inVars)) {
|
|
if (action.inVars && Array.isArray(action.inVars)) {
|
|
|
- if (action.inVars.length > 0) {
|
|
|
|
|
- const areaValue = variableContext[extractVarName(action.inVars[0])]
|
|
|
|
|
- area = areaValue !== undefined ? areaValue : resolveValue(action.inVars[0])
|
|
|
|
|
- }
|
|
|
|
|
- if (action.inVars.length > 1) {
|
|
|
|
|
- const savePathValue = variableContext[extractVarName(action.inVars[1])]
|
|
|
|
|
- savePath = savePathValue !== undefined ? savePathValue : resolveValue(action.inVars[1])
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (action.inVars.length > 0) area = variableContext[extractVarName(action.inVars[0])] ?? resolveValue(action.inVars[0], variableContext)
|
|
|
|
|
+ if (action.inVars.length > 1) savePath = variableContext[extractVarName(action.inVars[1])] ?? resolveValue(action.inVars[1], variableContext)
|
|
|
}
|
|
}
|
|
|
if (!area) return { success: false, error: 'img-cropping 缺少 area 参数' }
|
|
if (!area) return { success: false, error: 'img-cropping 缺少 area 参数' }
|
|
|
if (!savePath) return { success: false, error: 'img-cropping 缺少 savePath 参数' }
|
|
if (!savePath) return { success: false, error: 'img-cropping 缺少 savePath 参数' }
|
|
@@ -334,12 +331,10 @@ async function run(actionType, action, ctx, device, folderPath) {
|
|
|
const { executeReadTxt } = get(funcDir, 'io')
|
|
const { executeReadTxt } = get(funcDir, 'io')
|
|
|
let filePath = action.filePath
|
|
let filePath = action.filePath
|
|
|
let varName = action.variable
|
|
let varName = action.variable
|
|
|
- if (action.inVars?.length > 0) {
|
|
|
|
|
- const filePathValue = variableContext[extractVarName(action.inVars[0])]
|
|
|
|
|
- filePath = filePathValue !== undefined ? filePathValue : resolveValue(action.inVars[0])
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (action.inVars?.length > 0) filePath = variableContext[extractVarName(action.inVars[0])] ?? resolveValue(action.inVars[0], variableContext)
|
|
|
if (action.outVars?.length > 0) varName = extractVarName(action.outVars[0])
|
|
if (action.outVars?.length > 0) varName = extractVarName(action.outVars[0])
|
|
|
else if (action.variable) varName = extractVarName(action.variable)
|
|
else if (action.variable) varName = extractVarName(action.variable)
|
|
|
|
|
+ else if (action.variable) varName = extractVarName(action.variable)
|
|
|
if (!filePath) return { success: false, error: 'read-txt 缺少 filePath 参数' }
|
|
if (!filePath) return { success: false, error: 'read-txt 缺少 filePath 参数' }
|
|
|
if (!varName) return { success: false, error: 'read-txt 缺少 variable 参数' }
|
|
if (!varName) return { success: false, error: 'read-txt 缺少 variable 参数' }
|
|
|
const result = await executeReadTxt({ filePath, folderPath })
|
|
const result = await executeReadTxt({ filePath, folderPath })
|
|
@@ -356,14 +351,8 @@ async function run(actionType, action, ctx, device, folderPath) {
|
|
|
let history = action.history
|
|
let history = action.history
|
|
|
let current = action.current
|
|
let current = action.current
|
|
|
if (action.inVars && Array.isArray(action.inVars)) {
|
|
if (action.inVars && Array.isArray(action.inVars)) {
|
|
|
- if (action.inVars.length > 0) {
|
|
|
|
|
- const historyValue = variableContext[extractVarName(action.inVars[0])]
|
|
|
|
|
- history = historyValue !== undefined ? historyValue : resolveValue(action.inVars[0])
|
|
|
|
|
- }
|
|
|
|
|
- if (action.inVars.length > 1) {
|
|
|
|
|
- const currentValue = variableContext[extractVarName(action.inVars[1])]
|
|
|
|
|
- current = currentValue !== undefined ? currentValue : resolveValue(action.inVars[1])
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (action.inVars.length > 0) history = variableContext[extractVarName(action.inVars[0])] ?? resolveValue(action.inVars[0], variableContext)
|
|
|
|
|
+ if (action.inVars.length > 1) current = variableContext[extractVarName(action.inVars[1])] ?? resolveValue(action.inVars[1], variableContext)
|
|
|
}
|
|
}
|
|
|
if (history === undefined || history === null) history = ''
|
|
if (history === undefined || history === null) history = ''
|
|
|
if (current === undefined || current === null) current = ''
|
|
if (current === undefined || current === null) current = ''
|
|
@@ -383,14 +372,8 @@ async function run(actionType, action, ctx, device, folderPath) {
|
|
|
let filePath = action.filePath
|
|
let filePath = action.filePath
|
|
|
let content = action.content
|
|
let content = action.content
|
|
|
if (action.inVars && Array.isArray(action.inVars)) {
|
|
if (action.inVars && Array.isArray(action.inVars)) {
|
|
|
- if (action.inVars.length > 0) {
|
|
|
|
|
- const contentValue = variableContext[extractVarName(action.inVars[0])]
|
|
|
|
|
- content = contentValue !== undefined ? contentValue : resolveValue(action.inVars[0])
|
|
|
|
|
- }
|
|
|
|
|
- if (action.inVars.length > 1) {
|
|
|
|
|
- const filePathValue = variableContext[extractVarName(action.inVars[1])]
|
|
|
|
|
- filePath = filePathValue !== undefined ? filePathValue : resolveValue(action.inVars[1])
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (action.inVars.length > 0) content = variableContext[extractVarName(action.inVars[0])] ?? resolveValue(action.inVars[0], variableContext)
|
|
|
|
|
+ if (action.inVars.length > 1) filePath = variableContext[extractVarName(action.inVars[1])] ?? resolveValue(action.inVars[1], variableContext)
|
|
|
}
|
|
}
|
|
|
if (!filePath) return { success: false, error: 'save-txt 缺少 filePath 参数' }
|
|
if (!filePath) return { success: false, error: 'save-txt 缺少 filePath 参数' }
|
|
|
if (content === undefined || content === null) return { success: false, error: 'save-txt 缺少 content 参数' }
|
|
if (content === undefined || content === null) return { success: false, error: 'save-txt 缺少 content 参数' }
|
|
@@ -417,37 +400,27 @@ async function run(actionType, action, ctx, device, folderPath) {
|
|
|
|
|
|
|
|
if (action.inVars && Array.isArray(action.inVars)) {
|
|
if (action.inVars && Array.isArray(action.inVars)) {
|
|
|
if (action.inVars.length >= 3) {
|
|
if (action.inVars.length >= 3) {
|
|
|
- const param1 = resolveValue(action.inVars[0])
|
|
|
|
|
- const param2 = resolveValue(action.inVars[1])
|
|
|
|
|
|
|
+ const param1 = resolveValue(action.inVars[0], variableContext)
|
|
|
|
|
+ const param2 = resolveValue(action.inVars[1], variableContext)
|
|
|
if (typeof param1 === 'string' && rgbPattern.test(param1.trim()) && typeof param2 === 'string' && rgbPattern.test(param2.trim())) {
|
|
if (typeof param1 === 'string' && rgbPattern.test(param1.trim()) && typeof param2 === 'string' && rgbPattern.test(param2.trim())) {
|
|
|
friendRgb = param1.trim()
|
|
friendRgb = param1.trim()
|
|
|
myRgb = param2.trim()
|
|
myRgb = param2.trim()
|
|
|
- const regionVar = extractVarName(action.inVars[2])
|
|
|
|
|
- regionArea = variableContext[regionVar]
|
|
|
|
|
- if (regionArea === undefined) {
|
|
|
|
|
- const regionResolved = resolveValue(action.inVars[2])
|
|
|
|
|
- if (regionResolved && typeof regionResolved === 'object') regionArea = regionResolved
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ regionArea = variableContext[extractVarName(action.inVars[2])] ?? resolveValue(action.inVars[2], variableContext)
|
|
|
} else {
|
|
} else {
|
|
|
avatar1Name = action.inVars[0]
|
|
avatar1Name = action.inVars[0]
|
|
|
avatar2Name = action.inVars[1]
|
|
avatar2Name = action.inVars[1]
|
|
|
- const regionVar = extractVarName(action.inVars[2])
|
|
|
|
|
- regionArea = variableContext[regionVar]
|
|
|
|
|
- if (regionArea === undefined) {
|
|
|
|
|
- const regionResolved = resolveValue(action.inVars[2])
|
|
|
|
|
- if (regionResolved && typeof regionResolved === 'object') regionArea = regionResolved
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ regionArea = variableContext[extractVarName(action.inVars[2])] ?? resolveValue(action.inVars[2], variableContext)
|
|
|
}
|
|
}
|
|
|
regionArea = parseRegion(regionArea)
|
|
regionArea = parseRegion(regionArea)
|
|
|
} else if (action.inVars.length >= 2) {
|
|
} else if (action.inVars.length >= 2) {
|
|
|
- const param1 = resolveValue(action.inVars[0])
|
|
|
|
|
- const param2 = resolveValue(action.inVars[1])
|
|
|
|
|
|
|
+ const param1 = resolveValue(action.inVars[0], variableContext)
|
|
|
|
|
+ const param2 = resolveValue(action.inVars[1], variableContext)
|
|
|
if (typeof param1 === 'string' && rgbPattern.test(param1.trim()) && typeof param2 === 'string' && rgbPattern.test(param2.trim())) {
|
|
if (typeof param1 === 'string' && rgbPattern.test(param1.trim()) && typeof param2 === 'string' && rgbPattern.test(param2.trim())) {
|
|
|
friendRgb = param1.trim()
|
|
friendRgb = param1.trim()
|
|
|
myRgb = param2.trim()
|
|
myRgb = param2.trim()
|
|
|
} else {
|
|
} else {
|
|
|
- avatar1Name = action.inVars[0]
|
|
|
|
|
- avatar2Name = action.inVars[1]
|
|
|
|
|
|
|
+ avatar1Name = param1
|
|
|
|
|
+ avatar2Name = param2
|
|
|
}
|
|
}
|
|
|
} else if (action.inVars.length === 1) {
|
|
} else if (action.inVars.length === 1) {
|
|
|
avatar1Name = action.inVars[0]
|
|
avatar1Name = action.inVars[0]
|
|
@@ -459,11 +432,11 @@ async function run(actionType, action, ctx, device, folderPath) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (avatar1Name) {
|
|
if (avatar1Name) {
|
|
|
- const resolved = resolveValue(avatar1Name)
|
|
|
|
|
|
|
+ const resolved = resolveValue(avatar1Name, variableContext)
|
|
|
if (resolved) avatar1Path = `${folderName}/resources/${resolved}`
|
|
if (resolved) avatar1Path = `${folderName}/resources/${resolved}`
|
|
|
}
|
|
}
|
|
|
if (avatar2Name) {
|
|
if (avatar2Name) {
|
|
|
- const resolved = resolveValue(avatar2Name)
|
|
|
|
|
|
|
+ const resolved = resolveValue(avatar2Name, variableContext)
|
|
|
if (resolved) avatar2Path = `${folderName}/resources/${resolved}`
|
|
if (resolved) avatar2Path = `${folderName}/resources/${resolved}`
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -513,11 +486,11 @@ async function run(actionType, action, ctx, device, folderPath) {
|
|
|
if (Array.isArray(parsed) && parsed.length === 0) replaceValue = ''
|
|
if (Array.isArray(parsed) && parsed.length === 0) replaceValue = ''
|
|
|
} catch (e) {}
|
|
} catch (e) {}
|
|
|
}
|
|
}
|
|
|
- prompt = prompt.replace(new RegExp(`{${varName}}`.replace(/[{}]/g, '\\$&'), 'g'), replaceValue)
|
|
|
|
|
|
|
+ prompt = (prompt || '').replace(new RegExp(`\\{${varName.replace(/[{}]/g, '\\$&')}\\}`, 'g'), replaceValue)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- if (prompt.includes('{historySummary}') && getHistorySummary) {
|
|
|
|
|
|
|
+ if (prompt && prompt.includes('{historySummary}') && getHistorySummary) {
|
|
|
let historySummary = variableContext['historySummary'] || ''
|
|
let historySummary = variableContext['historySummary'] || ''
|
|
|
if (!historySummary) {
|
|
if (!historySummary) {
|
|
|
historySummary = await getHistorySummary(folderPath)
|
|
historySummary = await getHistorySummary(folderPath)
|
|
@@ -603,7 +576,7 @@ async function run(actionType, action, ctx, device, folderPath) {
|
|
|
case 'string-press': {
|
|
case 'string-press': {
|
|
|
const api = ctx.electronAPI
|
|
const api = ctx.electronAPI
|
|
|
const inVars = action.inVars || []
|
|
const inVars = action.inVars || []
|
|
|
- let targetText = inVars.length > 0 ? (variableContext[extractVarName(inVars[0])] || action.value) : (resolveValue(action.value, variableContext) || action.value)
|
|
|
|
|
|
|
+ const targetText = inVars.length > 0 ? (variableContext[extractVarName(inVars[0])] ?? resolveValue(inVars[0], variableContext) ?? action.value) : (action.value ?? '')
|
|
|
if (!targetText) return { success: false, error: 'string-press 操作缺少文字内容' }
|
|
if (!targetText) return { success: false, error: 'string-press 操作缺少文字内容' }
|
|
|
if (!api?.findTextAndGetCoordinate) return { success: false, error: '文字识别 API 不可用' }
|
|
if (!api?.findTextAndGetCoordinate) return { success: false, error: '文字识别 API 不可用' }
|
|
|
const matchResult = await api.findTextAndGetCoordinate(device, targetText)
|
|
const matchResult = await api.findTextAndGetCoordinate(device, targetText)
|