Shell-Scripts/felo/create-cases.mjs

156 lines
5.1 KiB
JavaScript
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
import fs from 'fs';
import os from 'os';
import path from 'path';
import { execFileSync } from 'child_process';
import readline from 'readline';
const AUTHORIZATION = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIyMiJ9.2XLrkX3Fryw4c1Mn3Peqsp8JOMMOu25GP7yxl0gsIG4w9JjfUzlsharGdm8PDusK1fvwMRs5rc1p6LJe0cSg4w';
const BASE_URL = 'https://bops.felo.ai';
const IMAGE_EXTS = new Set(['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp', '.avif']);
// ── 交互输入 ─────────────────────────────────────────────────
function prompt(question) {
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
return new Promise((resolve) => {
rl.question(question, (answer) => {
rl.close();
resolve(answer.trim());
});
});
}
// ── ffmpeg 转换 ──────────────────────────────────────────────
function convertToWebp(inputPath) {
const tmpFile = path.join(os.tmpdir(), `case_upload_${Date.now()}_${Math.random().toString(36).slice(2)}.webp`);
execFileSync('cwebp', ['-q', '80', '-resize', '800', '0', inputPath, '-o', tmpFile], { stdio: 'pipe' });
return tmpFile;
}
// ── 上传图片 ─────────────────────────────────────────────────
async function uploadFile(filePath) {
const formData = new FormData();
const fileData = fs.readFileSync(filePath);
const blob = new Blob([fileData], { type: 'image/webp' });
formData.append('file', blob, path.basename(filePath));
const res = await fetch(`${BASE_URL}/api/home/case/upload`, {
method: 'POST',
headers: { 'Authorization': AUTHORIZATION },
body: formData,
});
const body = await res.json();
return { status: res.status, body };
}
// ── 创建案例 ─────────────────────────────────────────────────
async function createCase(caseTypeId, imageUrl, name, sort) {
const res = await fetch(`${BASE_URL}/api/home/case/create`, {
method: 'POST',
headers: {
'Authorization': AUTHORIZATION,
'Content-Type': 'application/json',
},
body: JSON.stringify({
case_type_id: caseTypeId,
image_url: imageUrl,
name,
sort: 0,
}),
});
const body = await res.json();
return { status: res.status, body };
}
// ── 主流程 ───────────────────────────────────────────────────
async function main() {
const caseTypeId = await prompt('请输入分类 ID (case_type_id): ');
const input = await prompt('请输入图片目录路径: ');
const absDir = path.resolve(input);
if (!fs.existsSync(absDir)) {
console.error(`目录不存在: ${absDir}`);
process.exit(1);
}
const files = fs.readdirSync(absDir)
.filter((f) => IMAGE_EXTS.has(path.extname(f).toLowerCase()))
.sort();
if (files.length === 0) {
console.error('目录中未找到图片文件');
process.exit(1);
}
console.log(`找到 ${files.length} 张图片,开始处理...\n`);
const tmpFiles = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
const inputPath = path.join(absDir, file);
console.log(`[${i + 1}/${files.length}] ${file}`);
// 1. 转换 WebP
let tmpPath;
try {
process.stdout.write(' → ffmpeg 转换... ');
tmpPath = convertToWebp(inputPath);
tmpFiles.push(tmpPath);
console.log('✓');
} catch (err) {
console.log(`✗ 转换失败: ${err.message}`);
continue;
}
// 2. 上传
let imageUrl;
try {
process.stdout.write(' → 上传图片... ');
const uploadRes = await uploadFile(tmpPath);
console.log(`✓ HTTP ${uploadRes.status}`);
console.log(' upload res.data:', JSON.stringify(uploadRes.body, null, 2));
const body = uploadRes.body;
imageUrl = body?.data?.url ?? body?.data ?? body?.url ?? null;
if (!imageUrl) {
console.log(' ⚠ 无法自动提取 image_url请确认上方打印的字段结构后修改脚本');
continue;
}
} catch (err) {
console.log(`✗ 上传失败: ${err.message}`);
continue;
}
// 3. 创建案例
try {
process.stdout.write(` → 创建案例 (sort=${i + 1})... `);
const createRes = await createCase(caseTypeId, imageUrl, path.basename(file, path.extname(file)), i + 1);
if (createRes.status >= 200 && createRes.status < 300) {
console.log(`✓ HTTP ${createRes.status}`);
} else {
console.log(`✗ HTTP ${createRes.status}: ${JSON.stringify(createRes.body)}`);
}
} catch (err) {
console.log(`✗ 创建失败: ${err.message}`);
}
console.log();
}
for (const f of tmpFiles) {
try { fs.unlinkSync(f); } catch {}
}
console.log('完成。');
}
main();