callkaro-cli-unofficial 0.1.0
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/README.md +196 -0
- package/dist/commands/accounts.js +275 -0
- package/dist/commands/agentPhone.js +50 -0
- package/dist/commands/agentVersions.js +228 -0
- package/dist/commands/agents.js +455 -0
- package/dist/commands/analytics.js +77 -0
- package/dist/commands/analyzers.js +130 -0
- package/dist/commands/auditStrategies.js +178 -0
- package/dist/commands/batches.js +189 -0
- package/dist/commands/calls.js +193 -0
- package/dist/commands/chatAgents.js +251 -0
- package/dist/commands/jsonInput.js +56 -0
- package/dist/commands/kpi.js +681 -0
- package/dist/commands/models.js +99 -0
- package/dist/commands/numbers.js +154 -0
- package/dist/commands/ongoing.js +39 -0
- package/dist/commands/secrets.js +124 -0
- package/dist/commands/setJson.js +42 -0
- package/dist/commands/simulations.js +139 -0
- package/dist/commands/skills.js +318 -0
- package/dist/commands/transcribers.js +95 -0
- package/dist/commands/update.js +86 -0
- package/dist/commands/voices.js +211 -0
- package/dist/data/catalog.json +1978 -0
- package/dist/endpoints.json +8 -0
- package/dist/index.js +684 -0
- package/dist/lib/agentImport.js +60 -0
- package/dist/lib/agentUpdate.js +262 -0
- package/dist/lib/api.js +287 -0
- package/dist/lib/browserAuth.js +93 -0
- package/dist/lib/catalog.js +136 -0
- package/dist/lib/config.js +354 -0
- package/dist/lib/dashboardApi.js +197 -0
- package/dist/lib/dashboardAuth.js +339 -0
- package/dist/lib/dbFields.js +30 -0
- package/dist/lib/logQuery.js +140 -0
- package/dist/lib/looseJson.js +198 -0
- package/dist/lib/session.js +17 -0
- package/dist/lib/types.js +15 -0
- package/dist/lib/ui.js +91 -0
- package/dist/lib/versions.js +19 -0
- package/package.json +52 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.voicesCommand = voicesCommand;
|
|
4
|
+
const session_1 = require("../lib/session");
|
|
5
|
+
const ui_1 = require("../lib/ui");
|
|
6
|
+
const slug = (value) => String(value).toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
7
|
+
/**
|
|
8
|
+
* CLI flag -> candidate provider filter names, in priority order. The provider
|
|
9
|
+
* catalogue declares which filters it actually accepts, so a flag maps to
|
|
10
|
+
* whichever name that provider uses (or is reported unsupported).
|
|
11
|
+
*/
|
|
12
|
+
const filterOptions = [
|
|
13
|
+
{ option: 'model', names: ['model'] },
|
|
14
|
+
{ option: 'language', names: ['language', 'locale', 'languages'] },
|
|
15
|
+
{ option: 'locale', names: ['locale'] },
|
|
16
|
+
{ option: 'gender', names: ['gender'] },
|
|
17
|
+
{ option: 'query', names: ['query'] },
|
|
18
|
+
{ option: 'voiceId', names: ['voiceId', 'id'] },
|
|
19
|
+
{ option: 'voiceName', names: ['voiceName', 'voice_name'] },
|
|
20
|
+
{ option: 'style', names: ['style'] },
|
|
21
|
+
{ option: 'languages', names: ['languages'] },
|
|
22
|
+
{ option: 'accent', names: ['accent'] },
|
|
23
|
+
{ option: 'useCases', names: ['useCases'] },
|
|
24
|
+
{ option: 'category', names: ['category'] },
|
|
25
|
+
{ option: 'voiceType', names: ['voiceType'] },
|
|
26
|
+
{ option: 'highQuality', names: ['highQuality'] },
|
|
27
|
+
{ option: 'voiceIds', names: ['voiceIds'] },
|
|
28
|
+
{ option: 'collectionId', names: ['collectionId'] },
|
|
29
|
+
{ option: 'sort', names: ['sort'] },
|
|
30
|
+
{ option: 'sortDirection', names: ['sortDirection'] },
|
|
31
|
+
{ option: 'isOwner', names: ['isOwner'] },
|
|
32
|
+
{ option: 'includeArchived', names: ['includeArchived'] },
|
|
33
|
+
{ option: 'type', names: ['type'] },
|
|
34
|
+
{ option: 'projectId', names: ['projectId'] },
|
|
35
|
+
{ option: 'id', names: ['id'] },
|
|
36
|
+
{ option: 'limit', names: ['limit'] },
|
|
37
|
+
];
|
|
38
|
+
function findProvider(providers, name) {
|
|
39
|
+
return providers.find((provider) => slug(provider.provider) === slug(name));
|
|
40
|
+
}
|
|
41
|
+
function providerLanguages(provider) {
|
|
42
|
+
const configured = (provider.modelConfigurations || []).flatMap((m) => m.languages || []);
|
|
43
|
+
const direct = (provider.languages || []).map((l) => (typeof l === 'string' ? l : l.value || ''));
|
|
44
|
+
return [...new Set([...configured, ...direct].filter(Boolean))];
|
|
45
|
+
}
|
|
46
|
+
function listProviders(providers, json) {
|
|
47
|
+
if (json)
|
|
48
|
+
return void console.log(JSON.stringify(providers, null, 2));
|
|
49
|
+
(0, ui_1.table)(['PROVIDER', 'MODELS', 'LANGUAGES', 'VOICES FROM'], providers.map((provider) => [
|
|
50
|
+
provider.provider,
|
|
51
|
+
(provider.models || []).join('\n') || '(none)',
|
|
52
|
+
providerLanguages(provider).join(' ') || 'voice catalogue',
|
|
53
|
+
provider.voiceSource?.type === 'endpoint' ? 'backend catalogue' : provider.voiceSource?.type || '',
|
|
54
|
+
]));
|
|
55
|
+
(0, ui_1.info)(`\n${providers.length} provider(s). Use \`cku voices --provider <name> --fields\` for configuration fields.`);
|
|
56
|
+
}
|
|
57
|
+
function showFields(provider, json) {
|
|
58
|
+
const fields = Object.keys(provider.defaultConfiguration || {});
|
|
59
|
+
const details = {
|
|
60
|
+
provider: provider.provider,
|
|
61
|
+
fields,
|
|
62
|
+
models: provider.modelConfigurations,
|
|
63
|
+
defaults: provider.defaultConfiguration,
|
|
64
|
+
controls: provider.controls,
|
|
65
|
+
controlConfigurations: provider.controlConfigurations,
|
|
66
|
+
filters: provider.filters,
|
|
67
|
+
};
|
|
68
|
+
if (json)
|
|
69
|
+
return void console.log(JSON.stringify(details, null, 2));
|
|
70
|
+
(0, ui_1.keyValue)({
|
|
71
|
+
provider: provider.provider,
|
|
72
|
+
'voice_configuration keys': fields.join(', '),
|
|
73
|
+
models: (provider.models || []).join(', ') || '(no voice_model key)',
|
|
74
|
+
languages: providerLanguages(provider).join(' ') || '(from voice catalogue)',
|
|
75
|
+
'search filters': Object.keys(provider.filters || {}).join(', ') || '(none)',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/** Flatten a provider's varied voice response into one table row shape. */
|
|
79
|
+
function normalizeVoices(provider, response) {
|
|
80
|
+
const defaultModel = String(provider.defaultConfiguration?.voice_model || '');
|
|
81
|
+
const defaultLanguage = String(provider.defaultConfiguration?.voice_language || '');
|
|
82
|
+
return (Array.isArray(response.voices) ? response.voices : []).map((voice) => ({
|
|
83
|
+
...voice,
|
|
84
|
+
provider: provider.provider,
|
|
85
|
+
name: String(voice.DisplayName || voice.display_name || voice.name || voice.voice_name || voice.id || ''),
|
|
86
|
+
id: String(voice.ShortName || voice.voice_id || voice.id || voice.voice_name || ''),
|
|
87
|
+
model: String(voice.model || response.model || defaultModel),
|
|
88
|
+
language: String(voice.Locale || voice.locale || voice.sublanguage || voice.language || response.locale || defaultLanguage),
|
|
89
|
+
gender: String(voice.Gender || voice.labels?.gender || voice.gender || '').toLowerCase(),
|
|
90
|
+
extra: Array.isArray(voice.StyleList)
|
|
91
|
+
? voice.StyleList.join(',')
|
|
92
|
+
: String(voice.description || voice.category || voice.style || ''),
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
/** Validate one filter value against the provider's declared filter schema. */
|
|
96
|
+
function normalizeFilterValue(name, value, definition) {
|
|
97
|
+
if (definition.type === 'integer') {
|
|
98
|
+
const parsed = Number(value);
|
|
99
|
+
if (!Number.isInteger(parsed) ||
|
|
100
|
+
(definition.min !== undefined && parsed < definition.min) ||
|
|
101
|
+
(definition.max !== undefined && parsed > definition.max)) {
|
|
102
|
+
throw new Error(`--${name} must be an integer between ${definition.min} and ${definition.max}.`);
|
|
103
|
+
}
|
|
104
|
+
return parsed;
|
|
105
|
+
}
|
|
106
|
+
if (definition.type === 'boolean')
|
|
107
|
+
return Boolean(value);
|
|
108
|
+
const normalized = String(value).trim();
|
|
109
|
+
if (!normalized)
|
|
110
|
+
throw new Error(`--${name} cannot be empty.`);
|
|
111
|
+
if (definition.type === 'string[]') {
|
|
112
|
+
const values = normalized.split(',').map((item) => item.trim()).filter(Boolean);
|
|
113
|
+
if (!values.length || (definition.maxItems !== undefined && values.length > definition.maxItems)) {
|
|
114
|
+
throw new Error(`--${name} must contain between 1 and ${definition.maxItems || 'more'} values.`);
|
|
115
|
+
}
|
|
116
|
+
return values.join(',');
|
|
117
|
+
}
|
|
118
|
+
if (definition.values && !definition.values.includes(normalized)) {
|
|
119
|
+
// Providers disagree on gender spelling; accept either and send the provider's.
|
|
120
|
+
const genderAliases = {
|
|
121
|
+
male: 'masculine', female: 'feminine', masculine: 'male', feminine: 'female',
|
|
122
|
+
};
|
|
123
|
+
const alias = genderAliases[normalized];
|
|
124
|
+
if (name === 'gender' && alias && definition.values.includes(alias))
|
|
125
|
+
return alias;
|
|
126
|
+
throw new Error(`--${name} must be one of: ${definition.values.join(', ')}.`);
|
|
127
|
+
}
|
|
128
|
+
return normalized;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Map CLI flags onto the filters this provider accepts. `strict` (a provider was
|
|
132
|
+
* named explicitly) turns a bad value into an error; otherwise the provider is
|
|
133
|
+
* just skipped as unsupported, so a cross-provider query still returns rows.
|
|
134
|
+
*/
|
|
135
|
+
function providerFilters(provider, opts, strict) {
|
|
136
|
+
const filters = {};
|
|
137
|
+
const unsupported = [];
|
|
138
|
+
for (const { option, names } of filterOptions) {
|
|
139
|
+
const value = opts[option];
|
|
140
|
+
if (value === undefined)
|
|
141
|
+
continue;
|
|
142
|
+
const filterName = names.find((name) => provider.filters?.[name]);
|
|
143
|
+
if (!filterName) {
|
|
144
|
+
unsupported.push(String(option));
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
filters[filterName] = normalizeFilterValue(String(option), String(value), provider.filters[filterName]);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
if (strict)
|
|
152
|
+
throw error;
|
|
153
|
+
unsupported.push(String(option));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return { filters, unsupported };
|
|
157
|
+
}
|
|
158
|
+
function unknownProvider(name, providers) {
|
|
159
|
+
const available = providers.map((p) => p.provider).join(', ');
|
|
160
|
+
(0, ui_1.info)(`Voice provider "${name}" is not available.${available ? ` Available: ${available}.` : ''}`);
|
|
161
|
+
process.exitCode = 1;
|
|
162
|
+
}
|
|
163
|
+
async function voicesCommand(opts) {
|
|
164
|
+
try {
|
|
165
|
+
const api = (0, session_1.requireApi)();
|
|
166
|
+
const { providers } = await api.getVoiceCatalog();
|
|
167
|
+
const wanted = opts.provider ? findProvider(providers || [], opts.provider) : undefined;
|
|
168
|
+
if (opts.provider && !wanted)
|
|
169
|
+
return unknownProvider(opts.provider, providers || []);
|
|
170
|
+
const selected = wanted ? [wanted] : providers || [];
|
|
171
|
+
if (opts.providers)
|
|
172
|
+
return listProviders(selected, opts.json);
|
|
173
|
+
if (opts.fields) {
|
|
174
|
+
if (!wanted) {
|
|
175
|
+
(0, ui_1.info)('--fields needs a provider, e.g. `cku voices --provider cartesia --fields`.');
|
|
176
|
+
process.exitCode = 1;
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
return showFields(wanted, opts.json);
|
|
180
|
+
}
|
|
181
|
+
const providerRequests = selected.map((provider) => ({
|
|
182
|
+
provider,
|
|
183
|
+
...providerFilters(provider, opts, Boolean(wanted)),
|
|
184
|
+
}));
|
|
185
|
+
if (wanted && providerRequests[0].unsupported.length) {
|
|
186
|
+
(0, ui_1.info)(`${wanted.provider} does not support: ${providerRequests[0].unsupported.map((n) => `--${n}`).join(', ')}. ` +
|
|
187
|
+
'Use --fields to list its filters.');
|
|
188
|
+
process.exitCode = 1;
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const relevant = providerRequests.filter(({ unsupported }) => unsupported.length === 0);
|
|
192
|
+
// One provider failing must not lose the others' rows.
|
|
193
|
+
const results = await Promise.allSettled(relevant.map(async ({ provider, filters }) => {
|
|
194
|
+
const response = await api.getProviderVoices(provider.provider, filters);
|
|
195
|
+
return normalizeVoices(provider, response);
|
|
196
|
+
}));
|
|
197
|
+
const rows = results.flatMap((r) => (r.status === 'fulfilled' ? r.value : []));
|
|
198
|
+
if (opts.json)
|
|
199
|
+
return void console.log(JSON.stringify(rows, null, 2));
|
|
200
|
+
if (!rows.length)
|
|
201
|
+
return void (0, ui_1.info)('No voices matched. Try fewer filters, or `cku voices --providers`.');
|
|
202
|
+
(0, ui_1.table)(['PROVIDER', 'NAME', 'VOICE ID', 'MODEL', 'LANGUAGE', 'GENDER', 'NOTES'], rows.map((row) => [row.provider, row.name, row.id, row.model, row.language, row.gender, row.extra]));
|
|
203
|
+
(0, ui_1.info)(`\n${rows.length} voice(s).`);
|
|
204
|
+
const failed = relevant.filter((_, index) => results[index].status === 'rejected');
|
|
205
|
+
if (failed.length)
|
|
206
|
+
(0, ui_1.info)(`Note: some providers failed: ${failed.map(({ provider }) => provider.provider).join(', ')}`);
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
(0, ui_1.handleError)(err);
|
|
210
|
+
}
|
|
211
|
+
}
|