@stellartech/voice-widget-directus 1.0.3 → 1.0.5
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 +46 -0
- package/dist/index.js +79 -27
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# @stellartech/voice-widget-directus
|
|
2
|
+
|
|
3
|
+
Voice generation widget with model/voice selection and audio preview for Directus.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @stellartech/voice-widget-directus
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Multiple TTS provider support (Gemini, ElevenLabs)
|
|
14
|
+
- Voice selection with audio sample previews
|
|
15
|
+
- Tone and style customization
|
|
16
|
+
- Full voiceover generation with progress tracking
|
|
17
|
+
- Async generation with background processing
|
|
18
|
+
- Audio playback and variant management
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
- Directus ^11.0.0
|
|
23
|
+
- Vue ^3.4.0
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
The widget requires the following collections in your Directus instance:
|
|
28
|
+
|
|
29
|
+
- `Voices` - Available voice options with samples
|
|
30
|
+
- `VoiceTones` - Tone presets for voice generation
|
|
31
|
+
- `VoiceStyles` - Style presets for voice generation
|
|
32
|
+
- `VoiceVariants` - Generated voice variants storage
|
|
33
|
+
- `AudioFiles` - Audio file records
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
After installation, the interface will be available in your Directus instance as a custom interface type. Configure it on a JSON field to enable voice generation for your content.
|
|
38
|
+
|
|
39
|
+
### Widget Options
|
|
40
|
+
|
|
41
|
+
- **Voices Collection**: Collection containing voice definitions
|
|
42
|
+
- **Flow ID**: Directus Flow ID for voice generation proxy
|
|
43
|
+
|
|
44
|
+
## License
|
|
45
|
+
|
|
46
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -530,6 +530,9 @@ function useVoicingApi(api) {
|
|
|
530
530
|
if (!effectiveFlowId) {
|
|
531
531
|
throw new Error("Voice flow ID is not configured. Set it in Widget Config or in the Flow ID field.");
|
|
532
532
|
}
|
|
533
|
+
if (!collection) {
|
|
534
|
+
throw new Error("collection is required but was not provided");
|
|
535
|
+
}
|
|
533
536
|
const voicingPayload = {
|
|
534
537
|
texts: [SAMPLE_TEXT],
|
|
535
538
|
provider,
|
|
@@ -538,7 +541,7 @@ function useVoicingApi(api) {
|
|
|
538
541
|
audio_files_collection: "AudioFiles",
|
|
539
542
|
// Include lesson context for callback tracking
|
|
540
543
|
lesson_id: lessonId || null,
|
|
541
|
-
collection
|
|
544
|
+
collection,
|
|
542
545
|
voice_config: {
|
|
543
546
|
provider,
|
|
544
547
|
voice_id: voiceId,
|
|
@@ -588,7 +591,10 @@ function useVoicingApi(api) {
|
|
|
588
591
|
if (!effectiveFlowId) {
|
|
589
592
|
throw new Error("Voice flow ID is not configured. Set it in Widget Config or in the Flow ID field.");
|
|
590
593
|
}
|
|
591
|
-
|
|
594
|
+
if (!request.collection) {
|
|
595
|
+
throw new Error("collection is required but was not provided");
|
|
596
|
+
}
|
|
597
|
+
const collection = request.collection;
|
|
592
598
|
let texts = [];
|
|
593
599
|
let lessonTitle = `Lesson ${request.lessonId}`;
|
|
594
600
|
try {
|
|
@@ -990,6 +996,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
990
996
|
ref(null);
|
|
991
997
|
const isPollingProgress = ref(false);
|
|
992
998
|
const progressStatus = ref("");
|
|
999
|
+
const pendingVariantId = ref(null);
|
|
993
1000
|
let samplePollingInterval = null;
|
|
994
1001
|
let voiceoverPollingInterval = null;
|
|
995
1002
|
const selectedVariant = computed(() => allVariants.value[currentVariantIndex.value]);
|
|
@@ -1037,12 +1044,15 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1037
1044
|
voices.value[voiceIndex].example_status = "processing";
|
|
1038
1045
|
}
|
|
1039
1046
|
const effectiveFlowId = flowId.value && flowId.value.trim() ? flowId.value.trim() : void 0;
|
|
1047
|
+
if (!props.collection) {
|
|
1048
|
+
throw new Error("collection is required but was not provided");
|
|
1049
|
+
}
|
|
1040
1050
|
generateVoiceSample(
|
|
1041
1051
|
voice.voice,
|
|
1042
1052
|
selectedModel.value,
|
|
1043
1053
|
effectiveFlowId,
|
|
1044
1054
|
props.primaryKey,
|
|
1045
|
-
props.collection
|
|
1055
|
+
props.collection
|
|
1046
1056
|
).then(() => {
|
|
1047
1057
|
console.log("[Voice Widget] Sample generation request sent for", voice.voice);
|
|
1048
1058
|
}).catch((error) => {
|
|
@@ -1111,15 +1121,31 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1111
1121
|
return;
|
|
1112
1122
|
}
|
|
1113
1123
|
voiceoverPollCount++;
|
|
1114
|
-
console.log(`[Voice Widget] Poll #${voiceoverPollCount} for lesson ${voiceoverLessonId}...`);
|
|
1124
|
+
console.log(`[Voice Widget] Poll #${voiceoverPollCount} for lesson ${voiceoverLessonId}, pendingVariantId=${pendingVariantId.value}...`);
|
|
1115
1125
|
try {
|
|
1116
1126
|
const allVariantsNow = await fetchVoiceVariants(voiceoverLessonId);
|
|
1117
1127
|
console.log(`[Voice Widget] Poll #${voiceoverPollCount} raw result:`, JSON.stringify(allVariantsNow));
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1128
|
+
let isNewVariantComplete = false;
|
|
1129
|
+
if (pendingVariantId.value) {
|
|
1130
|
+
const pendingVariant = allVariantsNow.find((v) => v.id === pendingVariantId.value);
|
|
1131
|
+
if (pendingVariant?.audio_file_id) {
|
|
1132
|
+
console.log("[Voice Widget] Pending variant completed with audio:", pendingVariant.audio_file_id);
|
|
1133
|
+
isNewVariantComplete = true;
|
|
1134
|
+
} else {
|
|
1135
|
+
console.log(`[Voice Widget] Poll #${voiceoverPollCount} - pending variant not yet complete`);
|
|
1136
|
+
}
|
|
1137
|
+
} else {
|
|
1138
|
+
const processingThatCompleted = allVariantsNow.find((v) => v.status === "processing" && v.audio_file_id);
|
|
1139
|
+
if (processingThatCompleted) {
|
|
1140
|
+
console.log("[Voice Widget] Found completed processing variant:", processingThatCompleted.id);
|
|
1141
|
+
isNewVariantComplete = true;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
if (isNewVariantComplete) {
|
|
1121
1145
|
console.log("[Voice Widget] COMPLETED! Transitioning to result...");
|
|
1122
1146
|
stopVoiceoverPolling();
|
|
1147
|
+
pendingVariantId.value = null;
|
|
1148
|
+
const completedWithAudio = allVariantsNow.filter((v) => v.audio_file_id);
|
|
1123
1149
|
allVariants.value = completedWithAudio;
|
|
1124
1150
|
for (const v of allVariants.value) {
|
|
1125
1151
|
if (v.audio_file_id) {
|
|
@@ -1181,8 +1207,13 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1181
1207
|
tone_id: selectedToneId.value,
|
|
1182
1208
|
style_id: selectedStyleId.value
|
|
1183
1209
|
};
|
|
1184
|
-
await createPendingVoiceVariant(props.primaryKey, voiceConfig);
|
|
1210
|
+
const newPendingId = await createPendingVoiceVariant(props.primaryKey, voiceConfig);
|
|
1211
|
+
pendingVariantId.value = newPendingId;
|
|
1212
|
+
console.log("[Voice Widget] Created pending variant:", newPendingId);
|
|
1185
1213
|
startVoiceoverPolling();
|
|
1214
|
+
if (!props.collection) {
|
|
1215
|
+
throw new Error("collection is required but was not provided");
|
|
1216
|
+
}
|
|
1186
1217
|
const result = await generateFullVoiceover({
|
|
1187
1218
|
provider: selectedModel.value,
|
|
1188
1219
|
voiceId: providerVoiceId,
|
|
@@ -1190,7 +1221,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1190
1221
|
preprocessing: preprocessingEnabled.value,
|
|
1191
1222
|
flowId: flowId.value,
|
|
1192
1223
|
lessonId: props.primaryKey,
|
|
1193
|
-
collection: props.collection
|
|
1224
|
+
collection: props.collection,
|
|
1194
1225
|
toneId: selectedToneId.value || void 0,
|
|
1195
1226
|
styleId: selectedStyleId.value || void 0
|
|
1196
1227
|
});
|
|
@@ -1225,6 +1256,8 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1225
1256
|
progressPercent.value = 0;
|
|
1226
1257
|
progressStatus.value = "";
|
|
1227
1258
|
isPollingProgress.value = false;
|
|
1259
|
+
pendingVariantId.value = null;
|
|
1260
|
+
stopVoiceoverPolling();
|
|
1228
1261
|
}
|
|
1229
1262
|
function selectVariant(index) {
|
|
1230
1263
|
currentVariantIndex.value = index;
|
|
@@ -1272,11 +1305,12 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1272
1305
|
generatedAudioUrl.value = isUuid ? getAudioUrl(audioFileId) : await resolveAudioFileUrl(audioFileId);
|
|
1273
1306
|
const config = variant.voice_config;
|
|
1274
1307
|
if (config) {
|
|
1308
|
+
isRestoringFromVariant.value = true;
|
|
1275
1309
|
if (config.provider) {
|
|
1276
1310
|
selectedModel.value = config.provider;
|
|
1277
1311
|
}
|
|
1278
1312
|
if (config.voice_id) {
|
|
1279
|
-
const matchingVoice = voices.value.find((v) => v.name === config.voice_id);
|
|
1313
|
+
const matchingVoice = voices.value.find((v) => v.voice === config.voice_id || v.name === config.voice_id);
|
|
1280
1314
|
if (matchingVoice) {
|
|
1281
1315
|
selectedVoiceId.value = matchingVoice.id;
|
|
1282
1316
|
}
|
|
@@ -1290,19 +1324,27 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1290
1324
|
if (typeof config.preprocessing === "boolean") {
|
|
1291
1325
|
preprocessingEnabled.value = config.preprocessing;
|
|
1292
1326
|
}
|
|
1327
|
+
isRestoringFromVariant.value = false;
|
|
1293
1328
|
}
|
|
1294
1329
|
}
|
|
1295
|
-
function regenerateVoiceover() {
|
|
1330
|
+
async function regenerateVoiceover() {
|
|
1331
|
+
const variant = selectedVariant.value;
|
|
1332
|
+
if (variant) {
|
|
1333
|
+
await loadVariantAtIndex(currentVariantIndex.value);
|
|
1334
|
+
}
|
|
1296
1335
|
generateVoiceover();
|
|
1297
1336
|
}
|
|
1298
1337
|
async function confirmVoiceover() {
|
|
1299
1338
|
const variant = selectedVariant.value;
|
|
1300
1339
|
if (!variant) return;
|
|
1301
1340
|
try {
|
|
1341
|
+
if (!props.collection) {
|
|
1342
|
+
throw new Error("collection is required but was not provided");
|
|
1343
|
+
}
|
|
1302
1344
|
await linkAudioToLesson(
|
|
1303
1345
|
props.primaryKey,
|
|
1304
1346
|
variant.audio_file_id,
|
|
1305
|
-
props.collection
|
|
1347
|
+
props.collection
|
|
1306
1348
|
);
|
|
1307
1349
|
const value = {
|
|
1308
1350
|
audio_file_id: variant.audio_file_id,
|
|
@@ -1392,20 +1434,29 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1392
1434
|
console.log("[Voice Widget] Checking variants for lesson:", props.primaryKey);
|
|
1393
1435
|
const variants = await fetchVoiceVariants(props.primaryKey);
|
|
1394
1436
|
console.log("[Voice Widget] All variants for lesson:", variants.length);
|
|
1395
|
-
const
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1437
|
+
const processingVariants = variants.filter((v) => v.status === "processing" && !v.audio_file_id);
|
|
1438
|
+
if (processingVariants.length > 0) {
|
|
1439
|
+
console.log("[Voice Widget] Found", processingVariants.length, "processing voiceovers, showing progress");
|
|
1440
|
+
currentMode.value = "progress";
|
|
1441
|
+
processingMessage.value = "Generating voiceover...";
|
|
1442
|
+
progressPercent.value = 50;
|
|
1443
|
+
startVoiceoverPolling();
|
|
1444
|
+
} else {
|
|
1445
|
+
const completedVariants = variants.filter((v) => v.audio_file_id);
|
|
1446
|
+
hasExistingVoices.value = completedVariants.length > 0;
|
|
1447
|
+
console.log("[Voice Widget] Completed variants with audio:", completedVariants.length);
|
|
1448
|
+
if (completedVariants.length > 0) {
|
|
1449
|
+
allVariants.value = completedVariants;
|
|
1450
|
+
for (const v of allVariants.value) {
|
|
1451
|
+
if (v.audio_file_id) {
|
|
1452
|
+
const isUuid = v.audio_file_id?.includes("-");
|
|
1453
|
+
v.audioUrl = isUuid ? getAudioUrl(v.audio_file_id) : await resolveAudioFileUrl(v.audio_file_id);
|
|
1454
|
+
}
|
|
1404
1455
|
}
|
|
1456
|
+
currentVariantIndex.value = 0;
|
|
1457
|
+
currentMode.value = "result";
|
|
1458
|
+
console.log("[Voice Widget] AUTO-SHOWING RESULT PAGE with", completedVariants.length, "variants");
|
|
1405
1459
|
}
|
|
1406
|
-
currentVariantIndex.value = 0;
|
|
1407
|
-
currentMode.value = "result";
|
|
1408
|
-
console.log("[Voice Widget] AUTO-SHOWING RESULT PAGE with", completedVariants.length, "variants");
|
|
1409
1460
|
}
|
|
1410
1461
|
}
|
|
1411
1462
|
initFromValue();
|
|
@@ -1454,8 +1505,9 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1454
1505
|
}
|
|
1455
1506
|
}
|
|
1456
1507
|
watch(() => props.value, initFromValue, { deep: true });
|
|
1508
|
+
const isRestoringFromVariant = ref(false);
|
|
1457
1509
|
watch(selectedModel, () => {
|
|
1458
|
-
if (currentVoices.value.length > 0) {
|
|
1510
|
+
if (!isRestoringFromVariant.value && currentVoices.value.length > 0) {
|
|
1459
1511
|
selectedVoiceId.value = currentVoices.value[0].id;
|
|
1460
1512
|
}
|
|
1461
1513
|
});
|
|
@@ -1934,10 +1986,10 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1934
1986
|
}
|
|
1935
1987
|
});
|
|
1936
1988
|
|
|
1937
|
-
var css = "\n.voice-widget[data-v-
|
|
1989
|
+
var css = "\n.voice-widget[data-v-e86a7906] {\n font-family: var(--theme--fonts--sans--font-family);\n padding: 16px;\n border: 1px solid var(--theme--form--field--input--border-color);\n border-radius: var(--theme--border-radius);\n background: var(--theme--background);\n}\n.widget__header[data-v-e86a7906] {\n margin-bottom: 20px;\n}\n.widget__header-row[data-v-e86a7906] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 16px;\n}\n.widget__header-text[data-v-e86a7906] {\n flex: 1;\n}\n.widget__title[data-v-e86a7906] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 0 4px 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--theme--foreground);\n}\n.widget__collapse-btn[data-v-e86a7906] {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--theme--foreground-subdued);\n border-radius: 4px;\n}\n.widget__collapse-btn[data-v-e86a7906]:hover {\n background: var(--theme--background-accent);\n}\n.widget__subtitle[data-v-e86a7906] {\n margin: 0;\n font-size: 14px;\n color: var(--theme--foreground-subdued);\n}\n.widget__header-controls[data-v-e86a7906] {\n display: flex;\n gap: 16px;\n align-items: center;\n}\n.widget__url-input[data-v-e86a7906] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.widget__url-label[data-v-e86a7906] {\n font-size: 12px;\n color: var(--theme--foreground-subdued);\n white-space: nowrap;\n}\n.widget__url-field[data-v-e86a7906] {\n padding: 6px 10px;\n border: 1px solid var(--theme--form--field--input--border-color);\n border-radius: var(--theme--border-radius);\n font-size: 12px;\n width: 280px;\n background: var(--theme--form--field--input--background);\n color: var(--theme--foreground);\n}\n.widget__section[data-v-e86a7906] {\n margin-bottom: 20px;\n}\n.widget__section-label[data-v-e86a7906] {\n display: block;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--theme--foreground);\n}\n.widget__model-buttons[data-v-e86a7906] {\n display: flex;\n gap: 8px;\n}\n.widget__model-btn[data-v-e86a7906] {\n padding: 8px 16px;\n border: 1px solid var(--theme--form--field--input--border-color);\n border-radius: var(--theme--border-radius);\n background: var(--theme--background);\n color: var(--theme--foreground);\n cursor: pointer;\n font-size: 14px;\n transition: all 0.15s ease;\n}\n.widget__model-btn[data-v-e86a7906]:hover {\n border-color: var(--theme--primary);\n}\n.widget__model-btn--active[data-v-e86a7906] {\n background: var(--theme--primary);\n border-color: var(--theme--primary);\n color: var(--theme--primary-foreground, #fff);\n}\n.widget__voice-list[data-v-e86a7906] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.widget__section--toggle[data-v-e86a7906] {\n padding: 12px;\n background: var(--theme--background-subdued);\n border-radius: var(--theme--border-radius);\n}\n.widget__toggle[data-v-e86a7906] {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n}\n.widget__toggle input[data-v-e86a7906] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n}\n.widget__toggle-label[data-v-e86a7906] {\n font-size: 14px;\n font-weight: 500;\n color: var(--theme--foreground);\n}\n.widget__toggle-note[data-v-e86a7906] {\n margin: 4px 0 0 24px;\n font-size: 12px;\n color: var(--theme--foreground-subdued);\n}\n.widget__footer[data-v-e86a7906] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-top: 16px;\n border-top: 1px solid var(--theme--border-color-subdued);\n margin-top: 20px;\n}\n.widget__footer-left[data-v-e86a7906],\n.widget__footer-right[data-v-e86a7906] {\n display: flex;\n gap: 8px;\n}\n.widget__variant-nav[data-v-e86a7906] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-bottom: 16px;\n padding: 8px 0;\n}\n.widget__variant-counter[data-v-e86a7906] {\n font-size: 14px;\n font-weight: 500;\n color: var(--theme--foreground-subdued);\n min-width: 60px;\n text-align: center;\n}\n.widget__btn--icon[data-v-e86a7906] {\n padding: 6px;\n min-width: 32px;\n min-height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.widget__result-date[data-v-e86a7906] {\n margin-top: 8px;\n font-size: 12px;\n color: var(--theme--foreground-subdued);\n}\n.widget__btn[data-v-e86a7906] {\n padding: 8px 16px;\n border: none;\n border-radius: var(--theme--border-radius);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.widget__btn[data-v-e86a7906]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.widget__btn--primary[data-v-e86a7906] {\n background: var(--theme--primary);\n color: var(--theme--primary-foreground, #fff);\n}\n.widget__btn--primary[data-v-e86a7906]:hover:not(:disabled) {\n background: var(--theme--primary-accent);\n}\n.widget__btn--secondary[data-v-e86a7906] {\n background: var(--theme--background-accent);\n color: var(--theme--foreground);\n border: 1px solid var(--theme--form--field--input--border-color);\n}\n.widget__btn--secondary[data-v-e86a7906]:hover:not(:disabled) {\n background: var(--theme--background-normal);\n}\n\n/* Processing State */\n.widget__processing[data-v-e86a7906] {\n padding: 40px 20px;\n text-align: center;\n}\n.widget__progress[data-v-e86a7906] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-bottom: 16px;\n font-size: 16px;\n color: var(--theme--foreground);\n}\n.widget__progress-bar[data-v-e86a7906] {\n height: 8px;\n background: var(--theme--background-accent);\n border-radius: 4px;\n overflow: hidden;\n max-width: 400px;\n margin: 0 auto;\n}\n.widget__progress-fill[data-v-e86a7906] {\n height: 100%;\n background: var(--theme--primary);\n transition: width 0.3s ease;\n}\n\n/* Error State */\n.widget__error[data-v-e86a7906] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n padding: 20px;\n color: var(--theme--danger);\n text-align: center;\n}\n.widget__error-actions[data-v-e86a7906] {\n display: flex;\n gap: 8px;\n margin-top: 8px;\n}\n.widget__retry[data-v-e86a7906] {\n padding: 6px 12px;\n background: var(--theme--danger);\n color: #fff;\n border: none;\n border-radius: var(--theme--border-radius);\n cursor: pointer;\n}\n\n/* Loading State */\n.widget__loading[data-v-e86a7906] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: var(--theme--foreground-subdued);\n}\n\n/* Result State */\n.widget__result[data-v-e86a7906] {\n padding: 20px;\n background: var(--theme--background-subdued);\n border-radius: var(--theme--border-radius);\n margin-bottom: 20px;\n}\n.widget__result-info[data-v-e86a7906] {\n margin-top: 16px;\n padding-top: 16px;\n border-top: 1px solid var(--theme--border-color-subdued);\n}\n.widget__result-info p[data-v-e86a7906] {\n margin: 4px 0;\n font-size: 14px;\n color: var(--theme--foreground-subdued);\n}\n.widget__result-info strong[data-v-e86a7906] {\n color: var(--theme--foreground);\n}\n\n/* Variants List View */\n.widget__variants-list[data-v-e86a7906] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n max-height: 400px;\n overflow-y: auto;\n margin-bottom: 16px;\n}\n.widget__variant-item[data-v-e86a7906] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n border: 1px solid var(--theme--border-color-subdued);\n border-radius: var(--theme--border-radius);\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.widget__variant-item[data-v-e86a7906]:hover {\n border-color: var(--theme--primary);\n}\n.widget__variant-item--selected[data-v-e86a7906] {\n border-color: var(--theme--primary);\n background: var(--theme--primary-background);\n}\n.widget__variant-radio[data-v-e86a7906] {\n flex-shrink: 0;\n}\n.widget__variant-radio input[data-v-e86a7906] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n}\n.widget__variant-player[data-v-e86a7906] {\n flex: 1;\n min-width: 200px;\n}\n.widget__variant-meta[data-v-e86a7906] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 120px;\n}\n.widget__variant-voice[data-v-e86a7906] {\n font-size: 13px;\n font-weight: 500;\n color: var(--theme--foreground);\n}\n.widget__variant-date[data-v-e86a7906] {\n font-size: 11px;\n color: var(--theme--foreground-subdued);\n}\n.widget__btn--danger[data-v-e86a7906] {\n color: var(--theme--danger);\n background: transparent;\n border: none;\n}\n.widget__btn--danger[data-v-e86a7906]:hover {\n background: var(--theme--danger-background);\n}\n.widget__selected-info[data-v-e86a7906] {\n padding: 12px;\n background: var(--theme--background-subdued);\n border-radius: var(--theme--border-radius);\n margin-bottom: 16px;\n}\n.widget__selected-info p[data-v-e86a7906] {\n margin: 4px 0;\n font-size: 14px;\n color: var(--theme--foreground-subdued);\n}\n.widget__selected-info strong[data-v-e86a7906] {\n color: var(--theme--foreground);\n}\n.widget__progress-status[data-v-e86a7906] {\n text-align: center;\n font-size: 12px;\n color: var(--theme--foreground-subdued);\n margin-top: 8px;\n}\n\n/* Animations */\n.spinning[data-v-e86a7906] {\n animation: spin-e86a7906 1s linear infinite;\n}\n@keyframes spin-e86a7906 {\nfrom { transform: rotate(0deg);\n}\nto { transform: rotate(360deg);\n}\n}\n";
|
|
1938
1990
|
n(css,{});
|
|
1939
1991
|
|
|
1940
|
-
var InterfaceComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
1992
|
+
var InterfaceComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-e86a7906"], ["__file", "interface.vue"]]);
|
|
1941
1993
|
|
|
1942
1994
|
var index = defineInterface({
|
|
1943
1995
|
id: "voice-widget",
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stellartech/voice-widget-directus",
|
|
3
3
|
"description": "Voice generation widget with model/voice selection and audio preview for Directus",
|
|
4
4
|
"icon": "mic",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.5",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"readme": "README.md",
|
|
8
8
|
"repository": {
|