feat(*): 短剧创作工作台 - 完善章节分镜、资产管理、技能运行与生成任务恢复

This commit is contained in:
ddCat
2026-08-29 23:34:46 +08:00
parent 4f07daae9e
commit 2f6832f99c
113 changed files with 7016 additions and 723 deletions

View File

@@ -221,16 +221,54 @@ export function parseAgentSkills(value: unknown) {
const input = item as Record<string, unknown>;
const name = typeof input.name === "string" ? input.name.trim().slice(0, 120) : "";
const instruction = typeof input.instruction === "string" ? input.instruction.trim().slice(0, 24_000) : "";
if (!name || !instruction) return [];
const files = parseAgentSkillFiles(input.files);
if (!name || (!instruction && !files.length)) return [];
return [{
...(typeof input.skillId === "string" ? { skillId: input.skillId.trim().slice(0, 120) } : {}),
name,
...(typeof input.description === "string" ? { description: input.description.trim().slice(0, 500) } : {}),
instruction,
...(typeof input.version === "string" ? { version: input.version.trim().slice(0, 120) } : {}),
...(files.length ? { files } : { instruction }),
}];
});
}
function parseAgentSkillFiles(value: unknown) {
if (!Array.isArray(value)) return [];
const files: Array<{ path: string; mimeType?: string; contentBase64: string }> = [];
const paths = new Set<string>();
let totalBytes = 0;
for (const item of value.slice(0, 512)) {
if (!item || typeof item !== "object" || Array.isArray(item)) return [];
const input = item as Record<string, unknown>;
const filePath = typeof input.path === "string" ? normalizeAgentSkillPath(input.path) : "";
const contentBase64 = typeof input.contentBase64 === "string" ? input.contentBase64.trim() : "";
if (!filePath || paths.has(filePath) || !validBase64(contentBase64)) return [];
const size = Buffer.from(contentBase64, "base64").byteLength;
if (size > 8 * 1024 * 1024) return [];
totalBytes += size;
if (totalBytes > 20 * 1024 * 1024) return [];
paths.add(filePath);
files.push({
path: filePath,
...(typeof input.mimeType === "string" ? { mimeType: input.mimeType.trim().slice(0, 255) } : {}),
contentBase64,
});
}
return files.some((file) => file.path === "SKILL.md") ? files : [];
}
function normalizeAgentSkillPath(value: string) {
const normalized = value.trim().replace(/\\/g, "/");
const segments = normalized.split("/");
if (!normalized || normalized.startsWith("/") || normalized.length > 1000 || segments.some((segment) => !segment || segment === "." || segment === "..") || normalized.includes("\0")) return "";
return normalized;
}
function validBase64(value: string) {
return value.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(value);
}
function queryValue(req: Request, key: string) {
const value = req.query[key];
return Array.isArray(value) ? String(value[0] ?? "") : String(value ?? "");