| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- /**
- * fun 结点:根据描述词(prompt)用 python/imagedl 搜索并下载一张图片到 savePath
- * 入参:prompt(描述词), savePath(相对路径时基于 folderPath)
- */
- const path = require('path')
- const fs = require('fs')
- const { spawnSync } = require('child_process')
- const configPath = process.env.STATIC_ROOT
- ? path.join(path.dirname(process.env.STATIC_ROOT), 'configs', 'config.js')
- : path.join(__dirname, '..', '..', '..', '..', 'configs', 'config.js')
- const projectRoot = path.dirname(path.dirname(path.resolve(configPath)))
- const config = fs.existsSync(configPath) ? require(configPath) : {}
- const scriptPath = path.join(projectRoot, 'python', 'scripts', 'download-img-by-prompt.py')
- const imagedlParent = path.join(projectRoot, 'python')
- const imagedlRequirements = path.join(projectRoot, 'python', 'imagedl', 'requirements.txt')
- function getPythonPath() {
- const base = config.pythonPath?.path || config.pythonVenvPath || path.join(projectRoot, 'python', process.arch === 'arm64' ? 'arm64' : 'x64')
- const envPy = path.join(base, 'env', 'Scripts', 'python.exe')
- const scriptsPy = path.join(base, 'Scripts', 'python.exe')
- const pyEmbedded = path.join(base, 'py', 'python.exe')
- if (fs.existsSync(envPy)) return envPy
- if (fs.existsSync(scriptsPy)) return scriptsPy
- if (fs.existsSync(pyEmbedded)) return pyEmbedded
- return 'python'
- }
- function buildSavePath(savePath, folderPath) {
- if (!savePath || typeof savePath !== 'string') return null
- const trimmed = savePath.trim()
- if (path.isAbsolute(trimmed) || trimmed.match(/^[A-Za-z]:/)) return trimmed
- return folderPath ? path.join(folderPath, trimmed) : path.resolve(projectRoot, trimmed)
- }
- async function executeDownloadImg({ prompt, savePath, folderPath }) {
- if (!prompt || typeof prompt !== 'string' || !prompt.trim()) return { success: false, error: 'download-img 缺少 prompt 参数' }
- if (savePath == null) return { success: false, error: 'download-img 缺少 savePath 参数' }
- const absolutePath = buildSavePath(String(savePath).trim(), folderPath)
- if (!absolutePath) return { success: false, error: 'download-img savePath 无效' }
- if (!fs.existsSync(scriptPath)) return { success: false, error: `脚本不存在: ${scriptPath}` }
- const pythonPath = getPythonPath()
- const args = [scriptPath, '--prompt', prompt.trim(), '--save-path', absolutePath.replace(/\\/g, '/')]
- const runScript = () => spawnSync(pythonPath, args, {
- encoding: 'utf-8',
- timeout: 120000,
- env: { ...process.env, PYTHONIOENCODING: 'utf-8', IMAGEDL_PARENT: imagedlParent },
- cwd: projectRoot
- })
- let r = runScript()
- let out = (r.stdout || '').trim()
- const err = (r.stderr || '').trim()
- const fullOut = out + (err ? '\n' + err : '')
- if (r.status !== 0 && fs.existsSync(imagedlRequirements) && (fullOut.includes('No module named') || fullOut.includes('ModuleNotFoundError'))) {
- spawnSync(pythonPath, ['-m', 'pip', 'install', '-r', imagedlRequirements, '-q'], {
- encoding: 'utf-8',
- timeout: 180000,
- cwd: projectRoot
- })
- r = runScript()
- out = (r.stdout || '').trim()
- }
- if (r.status !== 0) {
- return { success: false, error: (r.stderr || r.stdout || '').trim() || 'download-img 执行失败' }
- }
- // stdout 可能包含进度条等,取最后一行以 { 开头的行作为 JSON
- const lines = out.split(/\r?\n/).map(s => s.trim()).filter(Boolean)
- let jsonStr = lines[lines.length - 1]
- if (!jsonStr || !jsonStr.startsWith('{')) {
- const lastJson = lines.filter(l => l.startsWith('{')).pop()
- jsonStr = lastJson || out
- }
- let result
- try {
- result = JSON.parse(jsonStr)
- } catch (_) {
- return { success: false, error: out.slice(-300) || '无法解析输出' }
- }
- if (!result.success) return { success: false, error: result.error || '未下载到图片' }
- return { success: true, path: result.path }
- }
- module.exports = { executeDownloadImg }
|