faces-cli 1.7.6 → 1.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/chat/chat.js +8 -0
- package/dist/utils.d.ts +0 -15
- package/dist/utils.js +0 -75
- package/oclif.manifest.json +484 -1394
- package/package.json +1 -1
- package/dist/commands/billing/quota.d.ts +0 -10
- package/dist/commands/billing/quota.js +0 -12
- package/dist/commands/billing/subscription.d.ts +0 -10
- package/dist/commands/billing/subscription.js +0 -24
- package/dist/commands/face/upload.d.ts +0 -17
- package/dist/commands/face/upload.js +0 -66
- package/dist/commands/voiceprint/build-status.d.ts +0 -14
- package/dist/commands/voiceprint/build-status.js +0 -46
- package/dist/commands/voiceprint/build.d.ts +0 -23
- package/dist/commands/voiceprint/build.js +0 -109
- package/dist/commands/voiceprint/get.d.ts +0 -14
- package/dist/commands/voiceprint/get.js +0 -47
- package/dist/commands/voiceprint/refine-status.d.ts +0 -14
- package/dist/commands/voiceprint/refine-status.js +0 -43
- package/dist/commands/voiceprint/refine.d.ts +0 -23
- package/dist/commands/voiceprint/refine.js +0 -88
- package/dist/commands/voiceprint/revert.d.ts +0 -14
- package/dist/commands/voiceprint/revert.js +0 -36
- package/dist/commands/voiceprint/score-status.d.ts +0 -14
- package/dist/commands/voiceprint/score-status.js +0 -46
- package/dist/commands/voiceprint/score.d.ts +0 -24
- package/dist/commands/voiceprint/score.js +0 -114
- package/dist/commands/voiceprint/upload.d.ts +0 -17
- package/dist/commands/voiceprint/upload.js +0 -66
- package/dist/commands/voiceprint/versions.d.ts +0 -14
- package/dist/commands/voiceprint/versions.js +0 -44
- package/dist/voiceprint.d.ts +0 -28
- package/dist/voiceprint.js +0 -55
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { BaseCommand } from '../../base.js';
|
|
2
|
-
export default class VoiceprintScoreStatus extends BaseCommand {
|
|
3
|
-
static description: string;
|
|
4
|
-
static examples: string[];
|
|
5
|
-
static flags: {
|
|
6
|
-
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
-
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
-
};
|
|
10
|
-
static args: {
|
|
11
|
-
job_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
12
|
-
};
|
|
13
|
-
run(): Promise<unknown>;
|
|
14
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Args } from '@oclif/core';
|
|
2
|
-
import { BaseCommand } from '../../base.js';
|
|
3
|
-
import { FacesAPIError } from '../../client.js';
|
|
4
|
-
import { jobFailureMessage } from '../../voiceprint.js';
|
|
5
|
-
import { printScoreReport } from './score.js';
|
|
6
|
-
export default class VoiceprintScoreStatus extends BaseCommand {
|
|
7
|
-
static description = 'Get the status/result of a voiceprint scoring job (from voiceprint:score without --wait)';
|
|
8
|
-
static examples = ['<%= config.bin %> <%= command.id %> 4e13bf03-fbc1-4ad0-92ae-16984e2f9a1d'];
|
|
9
|
-
static flags = { ...BaseCommand.baseFlags };
|
|
10
|
-
static args = {
|
|
11
|
-
job_id: Args.string({ description: 'Scoring job id', required: true }),
|
|
12
|
-
};
|
|
13
|
-
async run() {
|
|
14
|
-
const { args, flags } = await this.parse(VoiceprintScoreStatus);
|
|
15
|
-
const client = this.makeClient(flags);
|
|
16
|
-
let data;
|
|
17
|
-
try {
|
|
18
|
-
data = (await client.get(`/v1/voiceprint/score/${encodeURIComponent(args.job_id)}`));
|
|
19
|
-
}
|
|
20
|
-
catch (err) {
|
|
21
|
-
if (err instanceof FacesAPIError)
|
|
22
|
-
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
23
|
-
throw err;
|
|
24
|
-
}
|
|
25
|
-
if (this.jsonEnabled())
|
|
26
|
-
return data;
|
|
27
|
-
const status = String(data.status ?? 'unknown');
|
|
28
|
-
if (status === 'done') {
|
|
29
|
-
printScoreReport(this, undefined, args.job_id, (data.report ?? {}));
|
|
30
|
-
}
|
|
31
|
-
else if (status === 'failed') {
|
|
32
|
-
this.log(`job: ${args.job_id}`);
|
|
33
|
-
this.log(`status: failed`);
|
|
34
|
-
this.log(`error: ${jobFailureMessage(data.error)}`);
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
const p = data.progress;
|
|
38
|
-
this.log(`job: ${args.job_id}`);
|
|
39
|
-
this.log(`status: ${status}`);
|
|
40
|
-
if (p && typeof p.pairs_done === 'number')
|
|
41
|
-
this.log(`pairs: ${p.pairs_done}/${p.pairs_total ?? '?'}`);
|
|
42
|
-
this.log(`(still running — poll again with: faces voiceprint:score-status ${args.job_id})`);
|
|
43
|
-
}
|
|
44
|
-
return data;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { BaseCommand } from '../../base.js';
|
|
2
|
-
export default class VoiceprintScore extends BaseCommand {
|
|
3
|
-
static description: string;
|
|
4
|
-
static examples: string[];
|
|
5
|
-
static flags: {
|
|
6
|
-
emails: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
-
'emails-dir': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
'author-corpus': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
-
model: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
-
'oauth-only': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
-
wait: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
-
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
-
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
-
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
-
};
|
|
16
|
-
static args: {
|
|
17
|
-
face: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
18
|
-
};
|
|
19
|
-
run(): Promise<unknown>;
|
|
20
|
-
}
|
|
21
|
-
/** Shared score-report formatter (used by voiceprint:score --wait and voiceprint:score-status). */
|
|
22
|
-
export declare function printScoreReport(cmd: {
|
|
23
|
-
log: (m: string) => void;
|
|
24
|
-
}, face: string | undefined, jobId: string, report: Record<string, unknown>): void;
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import { BaseCommand } from '../../base.js';
|
|
3
|
-
import { FacesAPIError } from '../../client.js';
|
|
4
|
-
import { loadVoiceprintEmails } from '../../utils.js';
|
|
5
|
-
import { pollVoiceprintJob, jobFailureMessage } from '../../voiceprint.js';
|
|
6
|
-
/** Minimum held-out emails the scorer needs for a well-posed measurement (handoff §4.5). */
|
|
7
|
-
const MIN_EMAILS = 20;
|
|
8
|
-
export default class VoiceprintScore extends BaseCommand {
|
|
9
|
-
static description = 'Score how closely a face writes like a specific person. Returns VCI (closeness, 0–100) and VFI (voice captured vs a generic baseline, 0–100). Deterministic — ideal for before/after tuning.';
|
|
10
|
-
static examples = [
|
|
11
|
-
'<%= config.bin %> <%= command.id %> "(alice-voiceprint | alice)" --emails ./sent.jsonl --wait',
|
|
12
|
-
'<%= config.bin %> <%= command.id %> alice --emails-dir ./sent-emails/ --wait',
|
|
13
|
-
'<%= config.bin %> <%= command.id %> alice --emails ./sent.json # prints job_id; poll with voiceprint:score-status',
|
|
14
|
-
];
|
|
15
|
-
static flags = {
|
|
16
|
-
...BaseCommand.baseFlags,
|
|
17
|
-
emails: Flags.string({ description: "JSON or JSONL file of the person's real writing — {id?, text} objects or plain strings (provide at least 20)" }),
|
|
18
|
-
'emails-dir': Flags.string({ description: 'Directory with one sample per file (id = filename). Alternative to --emails.', exclusive: ['emails'] }),
|
|
19
|
-
'author-corpus': Flags.string({ description: "Optional larger reference of the person's writing (JSON/JSONL/dir) used to define their voice; defaults to --emails" }),
|
|
20
|
-
model: Flags.string({ description: 'Model used to generate comparison drafts', default: 'gpt-5.4' }),
|
|
21
|
-
'oauth-only': Flags.boolean({ description: 'Only run when a free (OAuth) model route is available; never fall back to billed inference', default: false }),
|
|
22
|
-
wait: Flags.boolean({ description: 'Block and poll until the score is ready, then print it (default: print the job_id and return)', default: false }),
|
|
23
|
-
};
|
|
24
|
-
static args = {
|
|
25
|
-
face: Args.string({ description: 'Face to score (alias, owner:alias, or a union like "(alice-voiceprint | alice)")', required: true }),
|
|
26
|
-
};
|
|
27
|
-
async run() {
|
|
28
|
-
const { args, flags } = await this.parse(VoiceprintScore);
|
|
29
|
-
const client = this.makeClient(flags);
|
|
30
|
-
const json = this.jsonEnabled();
|
|
31
|
-
let emails;
|
|
32
|
-
try {
|
|
33
|
-
emails = loadVoiceprintEmails(flags.emails, flags['emails-dir']);
|
|
34
|
-
}
|
|
35
|
-
catch (err) {
|
|
36
|
-
this.error(err instanceof Error ? err.message : String(err));
|
|
37
|
-
}
|
|
38
|
-
if (emails.length < MIN_EMAILS) {
|
|
39
|
-
this.error(`Need at least ${MIN_EMAILS} writing samples, got ${emails.length}. ~100 gives a well-posed measurement.`);
|
|
40
|
-
}
|
|
41
|
-
const payload = { face: args.face, emails, model: flags.model };
|
|
42
|
-
if (flags['oauth-only'])
|
|
43
|
-
payload.oauth_only = true;
|
|
44
|
-
if (flags['author-corpus']) {
|
|
45
|
-
try {
|
|
46
|
-
payload.author_corpus = loadVoiceprintEmails(flags['author-corpus'], undefined).map((e) => e.text);
|
|
47
|
-
}
|
|
48
|
-
catch (err) {
|
|
49
|
-
this.error(err instanceof Error ? err.message : String(err));
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
let started;
|
|
53
|
-
try {
|
|
54
|
-
started = (await client.post('/v1/voiceprint/score', { body: payload }));
|
|
55
|
-
}
|
|
56
|
-
catch (err) {
|
|
57
|
-
if (err instanceof FacesAPIError)
|
|
58
|
-
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
59
|
-
throw err;
|
|
60
|
-
}
|
|
61
|
-
const jobId = String(started.job_id ?? '');
|
|
62
|
-
if (!jobId)
|
|
63
|
-
this.error('Server did not return a job_id');
|
|
64
|
-
if (!flags.wait) {
|
|
65
|
-
if (!json) {
|
|
66
|
-
this.log(`Scoring started: ${jobId}`);
|
|
67
|
-
this.log(`Poll with: faces voiceprint:score-status ${jobId}`);
|
|
68
|
-
}
|
|
69
|
-
return started;
|
|
70
|
-
}
|
|
71
|
-
if (!json)
|
|
72
|
-
process.stderr.write(`Scoring ${args.face} against ${emails.length} samples (job ${jobId})...\n`);
|
|
73
|
-
let final;
|
|
74
|
-
let lastDone = -1;
|
|
75
|
-
try {
|
|
76
|
-
final = await pollVoiceprintJob(client, '/v1/voiceprint/score', jobId, {
|
|
77
|
-
onPoll: (data) => {
|
|
78
|
-
if (json)
|
|
79
|
-
return;
|
|
80
|
-
const p = data.progress;
|
|
81
|
-
if (p && typeof p.pairs_done === 'number' && p.pairs_done !== lastDone) {
|
|
82
|
-
lastDone = p.pairs_done;
|
|
83
|
-
process.stderr.write(` ${data.status}: ${p.pairs_done}/${p.pairs_total ?? '?'} pairs\n`);
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
catch (err) {
|
|
89
|
-
if (err instanceof FacesAPIError)
|
|
90
|
-
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
91
|
-
this.error(err instanceof Error ? err.message : String(err));
|
|
92
|
-
}
|
|
93
|
-
if (final.status === 'failed')
|
|
94
|
-
this.error(`Scoring failed: ${jobFailureMessage(final.error)}`);
|
|
95
|
-
if (json)
|
|
96
|
-
return final;
|
|
97
|
-
printScoreReport(this, args.face, jobId, (final.report ?? {}));
|
|
98
|
-
return final;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
/** Shared score-report formatter (used by voiceprint:score --wait and voiceprint:score-status). */
|
|
102
|
-
export function printScoreReport(cmd, face, jobId, report) {
|
|
103
|
-
if (face)
|
|
104
|
-
cmd.log(`face: ${face}`);
|
|
105
|
-
cmd.log(`job: ${jobId}`);
|
|
106
|
-
cmd.log(`VCI: ${report.VCI ?? 'n/a'} (voice closeness — 100 = writes indistinguishably from the person)`);
|
|
107
|
-
cmd.log(`VFI: ${report.VFI ?? 'n/a'} (voice fidelity — how much of their voice is captured vs a generic baseline)`);
|
|
108
|
-
if (report.delta_ratio !== undefined)
|
|
109
|
-
cmd.log(`delta: ${report.delta_ratio} (imposter-normalized Burrows' Delta; <1.0 = closer to the author than to others)`);
|
|
110
|
-
if (report.confidence !== undefined)
|
|
111
|
-
cmd.log(`conf: ${report.confidence}`);
|
|
112
|
-
if (report.n_pairs !== undefined)
|
|
113
|
-
cmd.log(`n_pairs: ${report.n_pairs}`);
|
|
114
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { BaseCommand } from '../../base.js';
|
|
2
|
-
export default class VoiceprintUpload extends BaseCommand {
|
|
3
|
-
static description: string;
|
|
4
|
-
static examples: string[];
|
|
5
|
-
static flags: {
|
|
6
|
-
type: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
-
'emails-per-thread': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
-
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
-
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
-
};
|
|
12
|
-
static args: {
|
|
13
|
-
self_alias: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
14
|
-
file: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
15
|
-
};
|
|
16
|
-
run(): Promise<unknown>;
|
|
17
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { BaseCommand } from '../../base.js';
|
|
5
|
-
import { FacesAPIError } from '../../client.js';
|
|
6
|
-
export default class VoiceprintUpload extends BaseCommand {
|
|
7
|
-
static description = "Write a self face's email corpus as threads (the source for a voiceprint build). Pure data write — no compilation, no per-message billing.";
|
|
8
|
-
static examples = [
|
|
9
|
-
'<%= config.bin %> <%= command.id %> alice ./corpus.json',
|
|
10
|
-
'<%= config.bin %> <%= command.id %> alice ./mail.jsonl --type email_jsonl --emails-per-thread 50',
|
|
11
|
-
];
|
|
12
|
-
static flags = {
|
|
13
|
-
...BaseCommand.baseFlags,
|
|
14
|
-
type: Flags.string({
|
|
15
|
-
description: 'thread_json: a JSON array of canonical email objects → one room. email_jsonl: JSONL (one email/line) → chunked into several rooms.',
|
|
16
|
-
options: ['thread_json', 'email_jsonl'],
|
|
17
|
-
default: 'thread_json',
|
|
18
|
-
}),
|
|
19
|
-
'emails-per-thread': Flags.integer({ description: 'For --type email_jsonl: emails per room (default 50)', default: 50 }),
|
|
20
|
-
};
|
|
21
|
-
static args = {
|
|
22
|
-
self_alias: Args.string({ description: 'Self face alias', required: true }),
|
|
23
|
-
file: Args.string({ description: 'Corpus file (JSON array for thread_json, JSONL for email_jsonl)', required: true }),
|
|
24
|
-
};
|
|
25
|
-
async run() {
|
|
26
|
-
const { args, flags } = await this.parse(VoiceprintUpload);
|
|
27
|
-
const client = this.makeClient(flags);
|
|
28
|
-
const json = this.jsonEnabled();
|
|
29
|
-
if (!fs.existsSync(args.file))
|
|
30
|
-
this.error(`File not found: ${args.file}`);
|
|
31
|
-
const filename = path.basename(args.file);
|
|
32
|
-
const fileBlob = new Blob([fs.readFileSync(args.file)], { type: 'application/json' });
|
|
33
|
-
const form = new FormData();
|
|
34
|
-
form.append('file', fileBlob, filename);
|
|
35
|
-
const params = new URLSearchParams();
|
|
36
|
-
params.set('type', flags.type);
|
|
37
|
-
if (flags.type === 'email_jsonl')
|
|
38
|
-
params.set('emails_per_thread', String(flags['emails-per-thread']));
|
|
39
|
-
let data;
|
|
40
|
-
try {
|
|
41
|
-
data = (await client.postForm(`/v1/faces/${encodeURIComponent(args.self_alias)}/upload?${params}`, form));
|
|
42
|
-
}
|
|
43
|
-
catch (err) {
|
|
44
|
-
if (err instanceof FacesAPIError)
|
|
45
|
-
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
46
|
-
throw err;
|
|
47
|
-
}
|
|
48
|
-
if (json)
|
|
49
|
-
return data;
|
|
50
|
-
const roomIds = data.room_ids ?? [];
|
|
51
|
-
this.log(`alias: ${data.alias ?? args.self_alias}`);
|
|
52
|
-
this.log(`type: ${data.type ?? flags.type}`);
|
|
53
|
-
this.log(`message_count: ${data.message_count ?? '?'}`);
|
|
54
|
-
this.log(`room_count: ${data.room_count ?? roomIds.length}`);
|
|
55
|
-
if (roomIds.length > 0) {
|
|
56
|
-
this.log(`room_ids:`);
|
|
57
|
-
for (const id of roomIds)
|
|
58
|
-
this.log(` ${id}`);
|
|
59
|
-
this.log(`\nBuild the voice map: faces voiceprint:build ${args.self_alias} --wait`);
|
|
60
|
-
this.log(`Compile for knowledge (per room):`);
|
|
61
|
-
for (const id of roomIds)
|
|
62
|
-
this.log(` faces compile:thread:make ${id}`);
|
|
63
|
-
}
|
|
64
|
-
return data;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { BaseCommand } from '../../base.js';
|
|
2
|
-
export default class VoiceprintVersions extends BaseCommand {
|
|
3
|
-
static description: string;
|
|
4
|
-
static examples: string[];
|
|
5
|
-
static flags: {
|
|
6
|
-
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
-
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
-
};
|
|
10
|
-
static args: {
|
|
11
|
-
self_alias: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
12
|
-
};
|
|
13
|
-
run(): Promise<unknown>;
|
|
14
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { Args } from '@oclif/core';
|
|
2
|
-
import { BaseCommand } from '../../base.js';
|
|
3
|
-
import { FacesAPIError } from '../../client.js';
|
|
4
|
-
export default class VoiceprintVersions extends BaseCommand {
|
|
5
|
-
static description = "List a self face's voice-map versions (active + one prior). Retention is one-deep; toggle with voiceprint:revert.";
|
|
6
|
-
static examples = ['<%= config.bin %> <%= command.id %> alice'];
|
|
7
|
-
static flags = { ...BaseCommand.baseFlags };
|
|
8
|
-
static args = {
|
|
9
|
-
self_alias: Args.string({ description: 'Self face alias', required: true }),
|
|
10
|
-
};
|
|
11
|
-
async run() {
|
|
12
|
-
const { args, flags } = await this.parse(VoiceprintVersions);
|
|
13
|
-
const client = this.makeClient(flags);
|
|
14
|
-
let data;
|
|
15
|
-
try {
|
|
16
|
-
data = (await client.get(`/v1/voiceprint/versions/${encodeURIComponent(args.self_alias)}`));
|
|
17
|
-
}
|
|
18
|
-
catch (err) {
|
|
19
|
-
if (err instanceof FacesAPIError)
|
|
20
|
-
this.error(`Error (${err.statusCode}): ${err.message}`);
|
|
21
|
-
throw err;
|
|
22
|
-
}
|
|
23
|
-
if (this.jsonEnabled())
|
|
24
|
-
return data;
|
|
25
|
-
const versions = data.versions ?? [];
|
|
26
|
-
this.log(`self_face: ${data.self_face ?? args.self_alias}`);
|
|
27
|
-
if (versions.length === 0) {
|
|
28
|
-
this.log('(no versions — run faces voiceprint:build first)');
|
|
29
|
-
return data;
|
|
30
|
-
}
|
|
31
|
-
for (const v of versions) {
|
|
32
|
-
const mark = v.active ? '* ' : ' ';
|
|
33
|
-
this.log(`${mark}version ${v.version}${v.active ? ' (active)' : ''}`);
|
|
34
|
-
this.log(` VCI/VFI: ${v.baseline_vci ?? 'n/a'} / ${v.baseline_vfi ?? 'n/a'}`);
|
|
35
|
-
if (v.model)
|
|
36
|
-
this.log(` model: ${v.model}`);
|
|
37
|
-
if (v.recipe !== undefined)
|
|
38
|
-
this.log(` recipe: ${JSON.stringify(v.recipe)}`);
|
|
39
|
-
if (v.created_at)
|
|
40
|
-
this.log(` created: ${v.created_at}`);
|
|
41
|
-
}
|
|
42
|
-
return data;
|
|
43
|
-
}
|
|
44
|
-
}
|
package/dist/voiceprint.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared helpers for the voiceprint (Deepself) command family.
|
|
3
|
-
*
|
|
4
|
-
* build / score / refine all follow the same async contract: POST returns
|
|
5
|
-
* 202 {job_id, status:"queued"}; the CLI polls a matching *-status endpoint
|
|
6
|
-
* until status ∈ {done, failed}. These helpers centralize the poll loop and
|
|
7
|
-
* the CHATGPT_AUTH failure hint.
|
|
8
|
-
*/
|
|
9
|
-
import { FacesClient } from './client.js';
|
|
10
|
-
export type JobData = Record<string, unknown>;
|
|
11
|
-
export interface PollJobOptions {
|
|
12
|
-
intervalMs?: number;
|
|
13
|
-
timeoutMs?: number;
|
|
14
|
-
/** Called on every successful poll with the raw job payload (for progress output). */
|
|
15
|
-
onPoll?: (data: JobData) => void;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Poll `GET {basePath}/{jobId}` until the job reaches a terminal status
|
|
19
|
-
* ("done" or "failed"). Returns the final payload (including a failed one — the
|
|
20
|
-
* caller decides how to surface `error`). Throws only on timeout or a
|
|
21
|
-
* non-transient HTTP error.
|
|
22
|
-
*/
|
|
23
|
-
export declare function pollVoiceprintJob(client: FacesClient, basePath: string, jobId: string, opts?: PollJobOptions): Promise<JobData>;
|
|
24
|
-
/**
|
|
25
|
-
* Human-readable failure message for a failed job. Adds a reconnect hint when the
|
|
26
|
-
* backend reports a `CHATGPT_AUTH:` error (the uploaded corpus is preserved).
|
|
27
|
-
*/
|
|
28
|
-
export declare function jobFailureMessage(error: unknown): string;
|
package/dist/voiceprint.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared helpers for the voiceprint (Deepself) command family.
|
|
3
|
-
*
|
|
4
|
-
* build / score / refine all follow the same async contract: POST returns
|
|
5
|
-
* 202 {job_id, status:"queued"}; the CLI polls a matching *-status endpoint
|
|
6
|
-
* until status ∈ {done, failed}. These helpers centralize the poll loop and
|
|
7
|
-
* the CHATGPT_AUTH failure hint.
|
|
8
|
-
*/
|
|
9
|
-
import { FacesAPIError } from './client.js';
|
|
10
|
-
function sleep(ms) {
|
|
11
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Poll `GET {basePath}/{jobId}` until the job reaches a terminal status
|
|
15
|
-
* ("done" or "failed"). Returns the final payload (including a failed one — the
|
|
16
|
-
* caller decides how to surface `error`). Throws only on timeout or a
|
|
17
|
-
* non-transient HTTP error.
|
|
18
|
-
*/
|
|
19
|
-
export async function pollVoiceprintJob(client, basePath, jobId, opts = {}) {
|
|
20
|
-
const interval = opts.intervalMs ?? 3000;
|
|
21
|
-
const timeout = opts.timeoutMs ?? 1_800_000;
|
|
22
|
-
const start = Date.now();
|
|
23
|
-
const endpoint = `${basePath}/${encodeURIComponent(jobId)}`;
|
|
24
|
-
while (true) {
|
|
25
|
-
if (Date.now() - start > timeout) {
|
|
26
|
-
throw new Error(`Timed out after ${Math.round(timeout / 1000)}s (job ${jobId} may still finish; poll it later)`);
|
|
27
|
-
}
|
|
28
|
-
await sleep(interval);
|
|
29
|
-
let data;
|
|
30
|
-
try {
|
|
31
|
-
data = (await client.get(endpoint));
|
|
32
|
-
}
|
|
33
|
-
catch (err) {
|
|
34
|
-
// 5xx is transient — keep polling; anything else propagates.
|
|
35
|
-
if (err instanceof FacesAPIError && err.statusCode >= 500)
|
|
36
|
-
continue;
|
|
37
|
-
throw err;
|
|
38
|
-
}
|
|
39
|
-
opts.onPoll?.(data);
|
|
40
|
-
const status = String(data.status ?? '');
|
|
41
|
-
if (status === 'done' || status === 'failed')
|
|
42
|
-
return data;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Human-readable failure message for a failed job. Adds a reconnect hint when the
|
|
47
|
-
* backend reports a `CHATGPT_AUTH:` error (the uploaded corpus is preserved).
|
|
48
|
-
*/
|
|
49
|
-
export function jobFailureMessage(error) {
|
|
50
|
-
const e = typeof error === 'string' && error ? error : 'unknown error';
|
|
51
|
-
if (e.startsWith('CHATGPT_AUTH:')) {
|
|
52
|
-
return `${e}\nReconnect your ChatGPT account: faces auth:connect openai — then re-run (your uploaded corpus is preserved).`;
|
|
53
|
-
}
|
|
54
|
-
return e;
|
|
55
|
-
}
|