Add HyperFrames skills (from heygen-com/hyperframes, Apache-2.0)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXVsD1DgdzZLiPuwtKzMSY
This commit is contained in:
300 files changed
+49175
No files matched your search
@@ -0,0 +1,175 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
|
||||
const ttsUrl = new URL("./tts.mjs", import.meta.url).href;
|
||||
const stub = `#!${process.execPath}
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const args = process.argv.slice(2);
|
||||
if (args[0] === "--version") {
|
||||
console.log("Python 3.12.0");
|
||||
process.exit(0);
|
||||
}
|
||||
const input = args[2];
|
||||
const output = args[0] === "-c" ? args[4] : args[args.indexOf("--output") + 1];
|
||||
const text = fs.readFileSync(input, "utf8");
|
||||
fs.writeFileSync(output + ".started", input);
|
||||
const finish = () => {
|
||||
if (text === "slow" && !fs.existsSync(process.env.RELEASE_FILE)) {
|
||||
setTimeout(finish, 5);
|
||||
return;
|
||||
}
|
||||
const consumed = fs.readFileSync(input, "utf8");
|
||||
fs.writeFileSync(output + ".json", JSON.stringify({ input, text, consumed, args }));
|
||||
if (process.env.CASE_MODE === "nonzero") process.exit(7);
|
||||
if (process.env.CASE_MODE !== "no-output") fs.writeFileSync(output, consumed);
|
||||
};
|
||||
setTimeout(finish, 10);
|
||||
`;
|
||||
|
||||
const exercise = `
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import childProcess from "node:child_process";
|
||||
import { syncBuiltinESMExports } from "node:module";
|
||||
import { join, dirname } from "node:path";
|
||||
const { CASE_ROOT: root, CASE_MODE: mode, CASE_PROVIDER: provider } = process.env;
|
||||
const temp = join(root, "tmp");
|
||||
const preexisting = join(temp, "hf-txt-preexisting");
|
||||
fs.mkdirSync(preexisting);
|
||||
fs.writeFileSync(join(preexisting, "marker"), "keep");
|
||||
const injected = Object.assign(new Error("synthetic " + mode), { code: "EACCES" });
|
||||
const originalMkdtemp = fs.mkdtempSync;
|
||||
const originalWrite = fs.writeFileSync;
|
||||
const originalRm = fs.rmSync;
|
||||
if (mode === "allocation") fs.mkdtempSync = (prefix, ...args) => {
|
||||
if (prefix.startsWith(join(temp, "hf-txt-"))) throw injected;
|
||||
return originalMkdtemp(prefix, ...args);
|
||||
};
|
||||
if (mode === "write") fs.writeFileSync = (file, ...args) => {
|
||||
if (String(file).endsWith("line.txt")) {
|
||||
originalWrite(file, "partial");
|
||||
throw injected;
|
||||
}
|
||||
return originalWrite(file, ...args);
|
||||
};
|
||||
if (mode === "spawn-throw") childProcess.spawn = () => { throw injected; };
|
||||
if (mode === "cleanup") fs.rmSync = (dir, ...args) => {
|
||||
if (String(dir).startsWith(join(temp, "hf-txt-"))) throw injected;
|
||||
return originalRm(dir, ...args);
|
||||
};
|
||||
syncBuiltinESMExports();
|
||||
const { synthesizeOne } = await import(${JSON.stringify(ttsUrl)});
|
||||
const project = join(root, "project");
|
||||
const wavAbs = join(project, "line.wav");
|
||||
const request = (chosen = provider, text = "synthetic café", output = wavAbs) =>
|
||||
synthesizeOne({ provider: chosen, text, voiceId: "synthetic-voice", lang: "es",
|
||||
speed: 0.8, wavAbs: output, hyperframesDir: project });
|
||||
const owned = () => fs.readdirSync(temp).filter(name => name !== "hf-txt-preexisting");
|
||||
if (["allocation", "write", "spawn-throw"].includes(mode)) {
|
||||
await assert.rejects(request(), error => error === injected);
|
||||
assert.equal(fs.existsSync(wavAbs), false);
|
||||
} else if (mode === "concurrent") {
|
||||
const slowWav = join(project, "slow.wav");
|
||||
const slow = request("elevenlabs", "slow", slowWav);
|
||||
try {
|
||||
const deadline = Date.now() + 5000;
|
||||
while (!fs.existsSync(slowWav + ".started")) {
|
||||
assert.ok(Date.now() < deadline, "slow subprocess must start");
|
||||
await new Promise(resolve => setTimeout(resolve, 5));
|
||||
}
|
||||
const slowInput = fs.readFileSync(slowWav + ".started", "utf8");
|
||||
assert.deepEqual(await request("kokoro"), { ok: true, words: null });
|
||||
assert.deepEqual(owned(), [dirname(slowInput).split(/[\\\\/]/).pop()]);
|
||||
assert.equal(fs.readFileSync(slowInput, "utf8"), "slow");
|
||||
} finally {
|
||||
fs.writeFileSync(process.env.RELEASE_FILE, "release");
|
||||
await slow;
|
||||
}
|
||||
assert.equal(fs.readFileSync(slowWav, "utf8"), "slow");
|
||||
} else {
|
||||
const result = await request();
|
||||
const label = provider === "elevenlabs" ? "elevenlabs (python)" : "kokoro (npx hyperframes tts)";
|
||||
if (["nonzero", "enoent", "no-output"].includes(mode)) {
|
||||
const error = mode === "no-output" ? label + " produced no wav file" :
|
||||
label + " exited with status " + (mode === "enoent" ? -1 : 7);
|
||||
assert.deepEqual(result, { ok: false, words: null, error });
|
||||
assert.equal(fs.existsSync(wavAbs), false);
|
||||
} else {
|
||||
assert.deepEqual(result, { ok: true, words: null });
|
||||
assert.equal(fs.readFileSync(wavAbs, "utf8"), "synthetic café");
|
||||
}
|
||||
if (mode !== "enoent") {
|
||||
const log = JSON.parse(fs.readFileSync(wavAbs + ".json", "utf8"));
|
||||
assert.equal(log.text, "synthetic café");
|
||||
assert.equal(log.consumed, log.text);
|
||||
if (provider === "kokoro") assert.deepEqual(log.args.slice(-4), ["--lang", "es", "--speed", "0.8"]);
|
||||
}
|
||||
}
|
||||
if (mode === "cleanup") assert.equal(owned().length, 1);
|
||||
else assert.deepEqual(owned(), [], "owned text directories must be removed");
|
||||
assert.equal(fs.readFileSync(join(preexisting, "marker"), "utf8"), "keep");
|
||||
`;
|
||||
|
||||
function runCase(provider, mode) {
|
||||
const root = mkdtempSync(join(tmpdir(), "tts-cleanup-test-"));
|
||||
try {
|
||||
for (const dir of ["home", "tmp", "bin", "project"]) mkdirSync(join(root, dir));
|
||||
if (mode !== "enoent") {
|
||||
for (const name of ["npx", "python3"]) {
|
||||
const executable = join(root, "bin", name);
|
||||
writeFileSync(executable, stub);
|
||||
chmodSync(executable, 0o755);
|
||||
}
|
||||
}
|
||||
const result = spawnSync(process.execPath, ["--input-type=module", "-e", exercise], {
|
||||
encoding: "utf8",
|
||||
timeout: 15000,
|
||||
env: {
|
||||
HOME: join(root, "home"),
|
||||
USERPROFILE: join(root, "home"),
|
||||
TMPDIR: join(root, "tmp"),
|
||||
TMP: join(root, "tmp"),
|
||||
TEMP: join(root, "tmp"),
|
||||
PATH: join(root, "bin"),
|
||||
CASE_ROOT: root,
|
||||
CASE_PROVIDER: provider,
|
||||
CASE_MODE: mode,
|
||||
RELEASE_FILE: join(root, "release"),
|
||||
},
|
||||
});
|
||||
assert.equal(result.error, undefined);
|
||||
assert.equal(result.status, 0, result.stdout + result.stderr);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
for (const provider of ["elevenlabs", "kokoro"]) {
|
||||
for (const mode of [
|
||||
"success",
|
||||
"nonzero",
|
||||
"no-output",
|
||||
"enoent",
|
||||
"spawn-throw",
|
||||
"allocation",
|
||||
"write",
|
||||
"cleanup",
|
||||
]) {
|
||||
test(
|
||||
`synthesizeOne(${provider}) preserves ${mode} behavior and cleans only its text directory`,
|
||||
{ skip: process.platform === "win32" },
|
||||
() => runCase(provider, mode),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
test(
|
||||
"concurrent providers retain each other's text until their subprocess finishes",
|
||||
{ skip: process.platform === "win32" },
|
||||
() => runCase("kokoro", "concurrent"),
|
||||
);
|
||||
Reference in new issue
Block a user