@stellartech/voice-widget-directus 1.0.0 → 1.0.2
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/index.js +444 -307
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -461,14 +461,13 @@ function useVoicingApi(api) {
|
|
|
461
461
|
try {
|
|
462
462
|
const response = await api.get(`/items/${collection}`, {
|
|
463
463
|
params: {
|
|
464
|
-
filter: { status: { _eq: "published" } },
|
|
465
464
|
sort: ["sort", "name"],
|
|
466
|
-
fields: ["
|
|
465
|
+
fields: ["*"]
|
|
467
466
|
}
|
|
468
467
|
});
|
|
469
468
|
return response.data.data || [];
|
|
470
469
|
} catch (error) {
|
|
471
|
-
console.error("Failed to fetch voices:", error);
|
|
470
|
+
console.error("Failed to fetch voices:", error?.response?.data || error?.message || error);
|
|
472
471
|
return [];
|
|
473
472
|
}
|
|
474
473
|
}
|
|
@@ -486,7 +485,6 @@ function useVoicingApi(api) {
|
|
|
486
485
|
try {
|
|
487
486
|
const response = await api.get(`/items/${collection}`, {
|
|
488
487
|
params: {
|
|
489
|
-
filter: { status: { _eq: "published" } },
|
|
490
488
|
sort: ["sort", "name"],
|
|
491
489
|
fields: ["id", "name", "prompt", "sort", "is_custom"]
|
|
492
490
|
}
|
|
@@ -502,19 +500,13 @@ function useVoicingApi(api) {
|
|
|
502
500
|
return tones;
|
|
503
501
|
} catch (error) {
|
|
504
502
|
console.error("Failed to fetch tones:", error);
|
|
505
|
-
return [
|
|
506
|
-
{ id: "teacher", name: "Teacher", prompt: "Speak in a clear, educational, and patient manner", sort: 1, is_custom: false },
|
|
507
|
-
{ id: "storyteller", name: "Storyteller", prompt: "Speak in an engaging, narrative style with varied pacing", sort: 2, is_custom: false },
|
|
508
|
-
{ id: "podcaster", name: "Podcaster", prompt: "Speak in a conversational, informal yet professional tone", sort: 3, is_custom: false },
|
|
509
|
-
{ id: "other", name: "Other (Custom)", prompt: "", sort: 9999, is_custom: true }
|
|
510
|
-
];
|
|
503
|
+
return [];
|
|
511
504
|
}
|
|
512
505
|
}
|
|
513
506
|
async function fetchStyles(collection = "VoiceStyles") {
|
|
514
507
|
try {
|
|
515
508
|
const response = await api.get(`/items/${collection}`, {
|
|
516
509
|
params: {
|
|
517
|
-
filter: { status: { _eq: "published" } },
|
|
518
510
|
sort: ["sort", "name"],
|
|
519
511
|
fields: ["id", "name", "prompt", "sort", "is_custom"]
|
|
520
512
|
}
|
|
@@ -530,12 +522,7 @@ function useVoicingApi(api) {
|
|
|
530
522
|
return styles;
|
|
531
523
|
} catch (error) {
|
|
532
524
|
console.error("Failed to fetch styles:", error);
|
|
533
|
-
return [
|
|
534
|
-
{ id: "happy", name: "Happy", prompt: "enthusiastic and cheerful", sort: 1, is_custom: false },
|
|
535
|
-
{ id: "chill", name: "Chill", prompt: "relaxed and calm", sort: 2, is_custom: false },
|
|
536
|
-
{ id: "excited", name: "Excited", prompt: "energetic and animated", sort: 3, is_custom: false },
|
|
537
|
-
{ id: "other", name: "Other (Custom)", prompt: "", sort: 9999, is_custom: true }
|
|
538
|
-
];
|
|
525
|
+
return [];
|
|
539
526
|
}
|
|
540
527
|
}
|
|
541
528
|
async function generateVoiceSample(voiceId, provider, flowId = DEFAULT_FLOW_ID) {
|
|
@@ -547,7 +534,8 @@ function useVoicingApi(api) {
|
|
|
547
534
|
texts: [SAMPLE_TEXT],
|
|
548
535
|
provider,
|
|
549
536
|
preprocessing: false,
|
|
550
|
-
title: `Voice Sample - ${voiceId}
|
|
537
|
+
title: `Voice Sample - ${voiceId}`,
|
|
538
|
+
audio_files_collection: "AudioFiles"
|
|
551
539
|
};
|
|
552
540
|
if (provider === "gemini") {
|
|
553
541
|
voicingPayload.speakers = [{ voice: voiceId, name: "Sample", style: "neutral" }];
|
|
@@ -557,14 +545,28 @@ function useVoicingApi(api) {
|
|
|
557
545
|
voicingPayload.voice_id = voiceId;
|
|
558
546
|
}
|
|
559
547
|
try {
|
|
548
|
+
console.log("[Voice Widget] Calling flow:", effectiveFlowId);
|
|
560
549
|
const response = await api.post(`/flows/trigger/${effectiveFlowId}`, voicingPayload);
|
|
550
|
+
console.log("[Voice Widget] Full response:", JSON.stringify(response.data, null, 2));
|
|
561
551
|
const flowResponse = response.data;
|
|
562
|
-
|
|
552
|
+
let audioFileId = null;
|
|
553
|
+
if (flowResponse?.data?.audio_file_id) {
|
|
554
|
+
audioFileId = flowResponse.data.audio_file_id;
|
|
555
|
+
} else if (flowResponse?.audio_file_id) {
|
|
556
|
+
audioFileId = flowResponse.audio_file_id;
|
|
557
|
+
} else if (typeof flowResponse === "string") {
|
|
558
|
+
try {
|
|
559
|
+
const parsed = JSON.parse(flowResponse);
|
|
560
|
+
audioFileId = parsed?.data?.audio_file_id || parsed?.audio_file_id;
|
|
561
|
+
} catch {
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
console.log("[Voice Widget] Extracted audioFileId:", audioFileId);
|
|
563
565
|
if (audioFileId) {
|
|
564
566
|
const url = await resolveAudioFileUrl(audioFileId);
|
|
565
567
|
return { url, audioFileId };
|
|
566
568
|
}
|
|
567
|
-
throw new Error("No audio file returned from voice generation");
|
|
569
|
+
throw new Error("No audio file returned from voice generation. Response: " + JSON.stringify(flowResponse));
|
|
568
570
|
} catch (e) {
|
|
569
571
|
console.error("Failed to generate voice sample:", e);
|
|
570
572
|
throw new Error(e.response?.data?.detail || e.message || "Failed to generate sample");
|
|
@@ -576,10 +578,11 @@ function useVoicingApi(api) {
|
|
|
576
578
|
if (!effectiveFlowId) {
|
|
577
579
|
throw new Error("Voice flow ID is not configured. Set it in Widget Config or in the Flow ID field.");
|
|
578
580
|
}
|
|
581
|
+
const collection = request.collection || "SM_Lessons";
|
|
579
582
|
let texts = [];
|
|
580
583
|
let lessonTitle = `Lesson ${request.lessonId}`;
|
|
581
584
|
try {
|
|
582
|
-
const lessonResponse = await api.get(`/items
|
|
585
|
+
const lessonResponse = await api.get(`/items/${collection}/${request.lessonId}`, {
|
|
583
586
|
params: { fields: ["text", "title"] }
|
|
584
587
|
});
|
|
585
588
|
const textContent = lessonResponse.data.data?.text || "";
|
|
@@ -596,11 +599,24 @@ function useVoicingApi(api) {
|
|
|
596
599
|
console.error("Failed to fetch lesson text content:", e);
|
|
597
600
|
throw new Error(e.message || "Failed to fetch lesson text content");
|
|
598
601
|
}
|
|
602
|
+
const voiceConfig = {
|
|
603
|
+
provider: request.provider,
|
|
604
|
+
voice_id: request.voiceId,
|
|
605
|
+
style: request.style,
|
|
606
|
+
preprocessing: request.preprocessing,
|
|
607
|
+
tone_id: request.toneId,
|
|
608
|
+
style_id: request.styleId
|
|
609
|
+
};
|
|
599
610
|
const voicingPayload = {
|
|
600
611
|
texts,
|
|
601
612
|
provider: request.provider,
|
|
602
613
|
preprocessing: request.preprocessing,
|
|
603
|
-
title: `Voiceover - ${lessonTitle}
|
|
614
|
+
title: `Voiceover - ${lessonTitle}`,
|
|
615
|
+
audio_files_collection: "AudioFiles",
|
|
616
|
+
// Pass these so the flow can include them in callback_data
|
|
617
|
+
lesson_id: request.lessonId,
|
|
618
|
+
collection,
|
|
619
|
+
voice_config: voiceConfig
|
|
604
620
|
};
|
|
605
621
|
if (request.provider === "gemini") {
|
|
606
622
|
voicingPayload.speakers = [{
|
|
@@ -617,43 +633,20 @@ function useVoicingApi(api) {
|
|
|
617
633
|
const response = await api.post(`/flows/trigger/${effectiveFlowId}`, voicingPayload);
|
|
618
634
|
const flowResponse = response.data;
|
|
619
635
|
const data = flowResponse?.data || flowResponse;
|
|
620
|
-
let
|
|
621
|
-
if (data?.
|
|
636
|
+
let jobId = null;
|
|
637
|
+
if (data?.callback_data) {
|
|
622
638
|
try {
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
fileUuid = audioFilesResponse.data.data?.file || null;
|
|
627
|
-
} catch (e) {
|
|
628
|
-
console.warn("[Voice Widget] Could not resolve file UUID:", e);
|
|
629
|
-
}
|
|
630
|
-
if (fileUuid) {
|
|
631
|
-
try {
|
|
632
|
-
await api.post("/items/VoiceVariants", {
|
|
633
|
-
lesson_id: request.lessonId,
|
|
634
|
-
audio_file_id: fileUuid,
|
|
635
|
-
voice_config: {
|
|
636
|
-
provider: request.provider,
|
|
637
|
-
voice_id: request.voiceId,
|
|
638
|
-
style: request.style,
|
|
639
|
-
preprocessing: request.preprocessing,
|
|
640
|
-
tone_id: request.toneId,
|
|
641
|
-
style_id: request.styleId
|
|
642
|
-
},
|
|
643
|
-
callback_data: data.callback_data || null,
|
|
644
|
-
status: "published"
|
|
645
|
-
});
|
|
646
|
-
console.log("[Voice Widget] Saved voice variant with file UUID:", fileUuid);
|
|
647
|
-
} catch (saveError) {
|
|
648
|
-
console.warn("Failed to save voice variant:", saveError);
|
|
649
|
-
}
|
|
639
|
+
const callbackData = JSON.parse(data.callback_data);
|
|
640
|
+
jobId = callbackData.job_id || null;
|
|
641
|
+
} catch {
|
|
650
642
|
}
|
|
651
643
|
}
|
|
652
644
|
return {
|
|
653
|
-
audio_file_id:
|
|
654
|
-
status: data?.status ||
|
|
645
|
+
audio_file_id: data?.audio_file_id || null,
|
|
646
|
+
status: data?.status || "processing",
|
|
655
647
|
callback_data: data?.callback_data || null,
|
|
656
|
-
generation_time: data?.generation_time || null
|
|
648
|
+
generation_time: data?.generation_time || null,
|
|
649
|
+
job_id: jobId
|
|
657
650
|
};
|
|
658
651
|
} catch (e) {
|
|
659
652
|
console.error("Failed to generate voiceover:", e);
|
|
@@ -668,7 +661,8 @@ function useVoicingApi(api) {
|
|
|
668
661
|
const response = await api.get(`/items/AudioFiles/${audioFilesRecordId}`, {
|
|
669
662
|
params: { fields: ["file"] }
|
|
670
663
|
});
|
|
671
|
-
const
|
|
664
|
+
const fileField = response.data.data?.file;
|
|
665
|
+
const fileId = typeof fileField === "string" ? fileField : fileField?.id;
|
|
672
666
|
if (fileId) {
|
|
673
667
|
return `/assets/${fileId}`;
|
|
674
668
|
}
|
|
@@ -694,14 +688,18 @@ function useVoicingApi(api) {
|
|
|
694
688
|
}
|
|
695
689
|
async function updateVoiceSampleFile(voiceId, audioFilesRecordId, collection = "Voices") {
|
|
696
690
|
try {
|
|
691
|
+
console.log(`[Voice Widget] updateVoiceSampleFile called with voiceId=${voiceId}, audioFilesRecordId=${audioFilesRecordId}, collection=${collection}`);
|
|
697
692
|
const response = await api.get(`/items/AudioFiles/${audioFilesRecordId}`, {
|
|
698
693
|
params: { fields: ["file"] }
|
|
699
694
|
});
|
|
700
|
-
|
|
695
|
+
console.log("[Voice Widget] AudioFiles response:", response.data);
|
|
696
|
+
const fileField = response.data.data?.file;
|
|
697
|
+
const fileUuid = typeof fileField === "string" ? fileField : fileField?.id;
|
|
701
698
|
if (!fileUuid) {
|
|
702
|
-
console.warn("[Voice Widget] Could not get file UUID from AudioFiles record");
|
|
699
|
+
console.warn("[Voice Widget] Could not get file UUID from AudioFiles record. fileField:", fileField);
|
|
703
700
|
return;
|
|
704
701
|
}
|
|
702
|
+
console.log(`[Voice Widget] Patching ${collection}/${voiceId} with sample_file=${fileUuid}`);
|
|
705
703
|
await api.patch(`/items/${collection}/${voiceId}`, {
|
|
706
704
|
sample_file: fileUuid
|
|
707
705
|
});
|
|
@@ -710,6 +708,66 @@ function useVoicingApi(api) {
|
|
|
710
708
|
console.error("[Voice Widget] Failed to update voice sample_file:", error);
|
|
711
709
|
}
|
|
712
710
|
}
|
|
711
|
+
async function deleteVoiceVariant(variantId) {
|
|
712
|
+
try {
|
|
713
|
+
await api.delete(`/items/VoiceVariants/${variantId}`);
|
|
714
|
+
console.log(`[Voice Widget] Deleted voice variant: ${variantId}`);
|
|
715
|
+
} catch (error) {
|
|
716
|
+
console.error("[Voice Widget] Failed to delete voice variant:", error);
|
|
717
|
+
throw error;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
async function createVoiceVariant(lessonId, audioFileId, voiceConfig) {
|
|
721
|
+
try {
|
|
722
|
+
const response = await api.post("/items/VoiceVariants", {
|
|
723
|
+
lesson_id: lessonId,
|
|
724
|
+
audio_file_id: audioFileId,
|
|
725
|
+
voice_config: voiceConfig,
|
|
726
|
+
status: "draft"
|
|
727
|
+
});
|
|
728
|
+
const variantId = response.data.data?.id;
|
|
729
|
+
console.log(`[Voice Widget] Created VoiceVariant: ${variantId}`);
|
|
730
|
+
return variantId;
|
|
731
|
+
} catch (error) {
|
|
732
|
+
console.error("[Voice Widget] Failed to create VoiceVariant:", error);
|
|
733
|
+
throw error;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async function linkAudioToLesson(lessonId, audioFileId, collection) {
|
|
737
|
+
try {
|
|
738
|
+
await api.patch(`/items/${collection}/${lessonId}`, {
|
|
739
|
+
audio: audioFileId
|
|
740
|
+
});
|
|
741
|
+
console.log(`[Voice Widget] Linked audio ${audioFileId} to lesson ${lessonId} in ${collection}`);
|
|
742
|
+
} catch (error) {
|
|
743
|
+
console.error("[Voice Widget] Failed to link audio to lesson:", error);
|
|
744
|
+
throw error;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
async function pollVoicingJob(jobId) {
|
|
748
|
+
try {
|
|
749
|
+
const response = await api.get("/items/VoicingJobs", {
|
|
750
|
+
params: {
|
|
751
|
+
filter: { job_id: { _eq: jobId } },
|
|
752
|
+
fields: ["status", "progress", "message", "audio_file_id"],
|
|
753
|
+
limit: 1
|
|
754
|
+
}
|
|
755
|
+
});
|
|
756
|
+
const job = response.data.data?.[0];
|
|
757
|
+
if (job) {
|
|
758
|
+
return {
|
|
759
|
+
status: job.status,
|
|
760
|
+
progress: job.progress,
|
|
761
|
+
message: job.message,
|
|
762
|
+
audio_file_id: job.audio_file_id
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
return null;
|
|
766
|
+
} catch (error) {
|
|
767
|
+
console.error("[Voice Widget] Failed to poll voicing job:", error);
|
|
768
|
+
return null;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
713
771
|
return {
|
|
714
772
|
fetchVoices,
|
|
715
773
|
fetchFlowId,
|
|
@@ -720,7 +778,11 @@ function useVoicingApi(api) {
|
|
|
720
778
|
getAudioUrl,
|
|
721
779
|
resolveAudioFileUrl,
|
|
722
780
|
fetchVoiceVariants,
|
|
723
|
-
updateVoiceSampleFile
|
|
781
|
+
updateVoiceSampleFile,
|
|
782
|
+
deleteVoiceVariant,
|
|
783
|
+
createVoiceVariant,
|
|
784
|
+
linkAudioToLesson,
|
|
785
|
+
pollVoicingJob
|
|
724
786
|
};
|
|
725
787
|
}
|
|
726
788
|
|
|
@@ -733,49 +795,56 @@ const _hoisted_3 = { class: "widget__progress" };
|
|
|
733
795
|
const _hoisted_4 = { class: "widget__progress-bar" };
|
|
734
796
|
const _hoisted_5 = {
|
|
735
797
|
key: 0,
|
|
798
|
+
class: "widget__progress-status"
|
|
799
|
+
};
|
|
800
|
+
const _hoisted_6 = {
|
|
801
|
+
key: 1,
|
|
736
802
|
class: "widget__error"
|
|
737
803
|
};
|
|
738
|
-
const
|
|
739
|
-
const
|
|
740
|
-
const
|
|
741
|
-
const
|
|
742
|
-
const
|
|
743
|
-
const
|
|
744
|
-
const
|
|
745
|
-
const
|
|
746
|
-
const
|
|
747
|
-
const
|
|
748
|
-
const
|
|
749
|
-
const
|
|
750
|
-
const
|
|
751
|
-
const
|
|
752
|
-
const
|
|
753
|
-
const _hoisted_21 = { class: "widget__section" };
|
|
804
|
+
const _hoisted_7 = { class: "widget__loading" };
|
|
805
|
+
const _hoisted_8 = { class: "widget__error" };
|
|
806
|
+
const _hoisted_9 = { class: "widget__header" };
|
|
807
|
+
const _hoisted_10 = { class: "widget__header-row" };
|
|
808
|
+
const _hoisted_11 = { class: "widget__header-text" };
|
|
809
|
+
const _hoisted_12 = { class: "widget__title" };
|
|
810
|
+
const _hoisted_13 = ["title"];
|
|
811
|
+
const _hoisted_14 = { class: "widget__header-controls" };
|
|
812
|
+
const _hoisted_15 = { class: "widget__url-input" };
|
|
813
|
+
const _hoisted_16 = ["disabled"];
|
|
814
|
+
const _hoisted_17 = { class: "widget__section" };
|
|
815
|
+
const _hoisted_18 = { class: "widget__model-buttons" };
|
|
816
|
+
const _hoisted_19 = ["onClick"];
|
|
817
|
+
const _hoisted_20 = { class: "widget__section" };
|
|
818
|
+
const _hoisted_21 = { class: "widget__voice-list" };
|
|
754
819
|
const _hoisted_22 = { class: "widget__section" };
|
|
755
|
-
const _hoisted_23 = { class: "widget__section
|
|
756
|
-
const _hoisted_24 = { class: "
|
|
757
|
-
const _hoisted_25 = { class: "
|
|
758
|
-
const _hoisted_26 = { class: "widget__footer
|
|
759
|
-
const _hoisted_27 =
|
|
820
|
+
const _hoisted_23 = { class: "widget__section" };
|
|
821
|
+
const _hoisted_24 = { class: "widget__section widget__section--toggle" };
|
|
822
|
+
const _hoisted_25 = { class: "widget__toggle" };
|
|
823
|
+
const _hoisted_26 = { class: "widget__footer" };
|
|
824
|
+
const _hoisted_27 = { class: "widget__footer-right" };
|
|
760
825
|
const _hoisted_28 = ["disabled"];
|
|
761
|
-
const _hoisted_29 =
|
|
762
|
-
const _hoisted_30 = { class: "widget__header
|
|
763
|
-
const _hoisted_31 = { class: "widget__header-
|
|
764
|
-
const _hoisted_32 = { class: "
|
|
765
|
-
const _hoisted_33 = { class: "
|
|
766
|
-
const _hoisted_34 = {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
};
|
|
770
|
-
const
|
|
771
|
-
const
|
|
772
|
-
const
|
|
773
|
-
const
|
|
774
|
-
const
|
|
775
|
-
const
|
|
826
|
+
const _hoisted_29 = ["disabled"];
|
|
827
|
+
const _hoisted_30 = { class: "widget__header" };
|
|
828
|
+
const _hoisted_31 = { class: "widget__header-row" };
|
|
829
|
+
const _hoisted_32 = { class: "widget__header-text" };
|
|
830
|
+
const _hoisted_33 = { class: "widget__title" };
|
|
831
|
+
const _hoisted_34 = { class: "widget__subtitle" };
|
|
832
|
+
const _hoisted_35 = { class: "widget__variants-list" };
|
|
833
|
+
const _hoisted_36 = ["onClick"];
|
|
834
|
+
const _hoisted_37 = { class: "widget__variant-radio" };
|
|
835
|
+
const _hoisted_38 = ["checked", "onChange"];
|
|
836
|
+
const _hoisted_39 = { class: "widget__variant-player" };
|
|
837
|
+
const _hoisted_40 = { class: "widget__variant-meta" };
|
|
838
|
+
const _hoisted_41 = { class: "widget__variant-voice" };
|
|
839
|
+
const _hoisted_42 = { class: "widget__variant-date" };
|
|
840
|
+
const _hoisted_43 = ["onClick"];
|
|
841
|
+
const _hoisted_44 = {
|
|
776
842
|
key: 0,
|
|
777
|
-
class: "
|
|
843
|
+
class: "widget__selected-info"
|
|
778
844
|
};
|
|
845
|
+
const _hoisted_45 = { class: "widget__footer" };
|
|
846
|
+
const _hoisted_46 = { class: "widget__footer-right" };
|
|
847
|
+
const _hoisted_47 = ["disabled"];
|
|
779
848
|
var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
780
849
|
__name: "interface",
|
|
781
850
|
props: {
|
|
@@ -804,7 +873,11 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
804
873
|
getAudioUrl,
|
|
805
874
|
resolveAudioFileUrl,
|
|
806
875
|
fetchVoiceVariants,
|
|
807
|
-
updateVoiceSampleFile
|
|
876
|
+
updateVoiceSampleFile,
|
|
877
|
+
deleteVoiceVariant,
|
|
878
|
+
createVoiceVariant,
|
|
879
|
+
linkAudioToLesson,
|
|
880
|
+
pollVoicingJob
|
|
808
881
|
} = useVoicingApi(api);
|
|
809
882
|
const currentMode = ref("selection");
|
|
810
883
|
const loading = ref(true);
|
|
@@ -832,13 +905,17 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
832
905
|
const hasExistingVoices = ref(false);
|
|
833
906
|
const allVariants = ref([]);
|
|
834
907
|
const currentVariantIndex = ref(0);
|
|
908
|
+
const currentJobId = ref(null);
|
|
909
|
+
const isPollingProgress = ref(false);
|
|
910
|
+
const progressStatus = ref("");
|
|
911
|
+
const selectedVariant = computed(() => allVariants.value[currentVariantIndex.value]);
|
|
835
912
|
const currentVoices = computed(() => {
|
|
836
913
|
return voices.value.filter((v) => v.provider === selectedModel.value);
|
|
837
914
|
});
|
|
838
915
|
const canGenerate = computed(() => {
|
|
839
916
|
return selectedVoiceId.value !== null && selectedToneId.value !== null && selectedStyleId.value !== null;
|
|
840
917
|
});
|
|
841
|
-
|
|
918
|
+
computed(() => {
|
|
842
919
|
const variant = allVariants.value[currentVariantIndex.value];
|
|
843
920
|
if (!variant?.date_created) return null;
|
|
844
921
|
return new Date(variant.date_created).toLocaleString();
|
|
@@ -906,15 +983,15 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
906
983
|
if (!canGenerate.value) return;
|
|
907
984
|
currentMode.value = "progress";
|
|
908
985
|
errorMessage.value = null;
|
|
909
|
-
processingMessage.value = "
|
|
910
|
-
progressPercent.value =
|
|
986
|
+
processingMessage.value = "Starting generation...";
|
|
987
|
+
progressPercent.value = 5;
|
|
988
|
+
progressStatus.value = "";
|
|
911
989
|
try {
|
|
912
990
|
const tonePrompt = getSelectedTonePrompt();
|
|
913
991
|
const stylePrompt = getSelectedStylePrompt();
|
|
914
992
|
const combinedStyle = `${tonePrompt}. ${stylePrompt}`.trim();
|
|
915
993
|
const selectedVoice = voices.value.find((v) => v.id === selectedVoiceId.value);
|
|
916
994
|
const providerVoiceId = selectedVoice?.voice_id || selectedVoiceId.value;
|
|
917
|
-
progressPercent.value = 30;
|
|
918
995
|
const result = await generateFullVoiceover({
|
|
919
996
|
provider: selectedModel.value,
|
|
920
997
|
voiceId: providerVoiceId,
|
|
@@ -922,25 +999,41 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
922
999
|
preprocessing: preprocessingEnabled.value,
|
|
923
1000
|
flowId: flowId.value,
|
|
924
1001
|
lessonId: props.primaryKey,
|
|
1002
|
+
collection: props.collection || "SM_Lessons",
|
|
925
1003
|
toneId: selectedToneId.value || void 0,
|
|
926
1004
|
styleId: selectedStyleId.value || void 0
|
|
927
1005
|
});
|
|
928
|
-
|
|
929
|
-
|
|
1006
|
+
const voiceConfig = {
|
|
1007
|
+
provider: selectedModel.value,
|
|
1008
|
+
voice_id: providerVoiceId,
|
|
1009
|
+
style: combinedStyle,
|
|
1010
|
+
tone_id: selectedToneId.value,
|
|
1011
|
+
style_id: selectedStyleId.value
|
|
1012
|
+
};
|
|
1013
|
+
if (result.job_id) {
|
|
1014
|
+
processingMessage.value = "Processing in background...";
|
|
1015
|
+
await startProgressPolling(result.job_id, voiceConfig);
|
|
1016
|
+
} else if (result.audio_file_id) {
|
|
930
1017
|
generatedAudioId.value = result.audio_file_id;
|
|
931
1018
|
generatedAudioUrl.value = getAudioUrl(result.audio_file_id);
|
|
932
1019
|
progressPercent.value = 100;
|
|
1020
|
+
await createVoiceVariant(
|
|
1021
|
+
props.primaryKey,
|
|
1022
|
+
result.audio_file_id,
|
|
1023
|
+
voiceConfig
|
|
1024
|
+
);
|
|
1025
|
+
await refreshVariants();
|
|
933
1026
|
currentMode.value = "result";
|
|
934
1027
|
} else if (result.status === "processing" && result.callback_data) {
|
|
935
1028
|
processingMessage.value = "Processing in background...";
|
|
936
|
-
await pollForCompletion(result.callback_data);
|
|
1029
|
+
await pollForCompletion(result.callback_data, voiceConfig);
|
|
937
1030
|
}
|
|
938
1031
|
} catch (error) {
|
|
939
1032
|
errorMessage.value = error.message || "Failed to generate voiceover";
|
|
940
1033
|
progressPercent.value = 0;
|
|
941
1034
|
}
|
|
942
1035
|
}
|
|
943
|
-
async function pollForCompletion(callbackData) {
|
|
1036
|
+
async function pollForCompletion(callbackData, voiceConfig) {
|
|
944
1037
|
const maxAttempts = 60;
|
|
945
1038
|
const pollInterval = 5e3;
|
|
946
1039
|
for (let i = 0; i < maxAttempts; i++) {
|
|
@@ -970,19 +1063,77 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
970
1063
|
currentMode.value = "selection";
|
|
971
1064
|
errorMessage.value = null;
|
|
972
1065
|
progressPercent.value = 0;
|
|
1066
|
+
progressStatus.value = "";
|
|
1067
|
+
isPollingProgress.value = false;
|
|
973
1068
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1069
|
+
function selectVariant(index) {
|
|
1070
|
+
currentVariantIndex.value = index;
|
|
1071
|
+
loadVariantAtIndex(index);
|
|
1072
|
+
}
|
|
1073
|
+
async function deleteVariant(variantId) {
|
|
1074
|
+
if (!confirm("Delete this voiceover?")) return;
|
|
1075
|
+
try {
|
|
1076
|
+
await deleteVoiceVariant(variantId);
|
|
1077
|
+
allVariants.value = allVariants.value.filter((v) => v.id !== variantId);
|
|
1078
|
+
if (currentVariantIndex.value >= allVariants.value.length) {
|
|
1079
|
+
currentVariantIndex.value = Math.max(0, allVariants.value.length - 1);
|
|
1080
|
+
}
|
|
1081
|
+
if (allVariants.value.length === 0) {
|
|
1082
|
+
hasExistingVoices.value = false;
|
|
1083
|
+
goBackToSelection();
|
|
1084
|
+
}
|
|
1085
|
+
} catch (error) {
|
|
1086
|
+
console.error("Failed to delete variant:", error);
|
|
978
1087
|
}
|
|
979
1088
|
}
|
|
980
|
-
async function
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1089
|
+
async function startProgressPolling(jobId, voiceConfig) {
|
|
1090
|
+
currentJobId.value = jobId;
|
|
1091
|
+
isPollingProgress.value = true;
|
|
1092
|
+
while (isPollingProgress.value) {
|
|
1093
|
+
const job = await pollVoicingJob(jobId);
|
|
1094
|
+
if (job) {
|
|
1095
|
+
progressPercent.value = job.progress;
|
|
1096
|
+
processingMessage.value = job.message;
|
|
1097
|
+
progressStatus.value = job.status;
|
|
1098
|
+
if (job.status === "completed") {
|
|
1099
|
+
isPollingProgress.value = false;
|
|
1100
|
+
if (job.audio_file_id) {
|
|
1101
|
+
await createVoiceVariant(
|
|
1102
|
+
props.primaryKey,
|
|
1103
|
+
job.audio_file_id,
|
|
1104
|
+
voiceConfig
|
|
1105
|
+
);
|
|
1106
|
+
}
|
|
1107
|
+
await refreshVariants();
|
|
1108
|
+
currentMode.value = "result";
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
if (job.status.startsWith("failed")) {
|
|
1112
|
+
isPollingProgress.value = false;
|
|
1113
|
+
errorMessage.value = job.message || "Generation failed";
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
984
1118
|
}
|
|
985
1119
|
}
|
|
1120
|
+
async function refreshVariants() {
|
|
1121
|
+
const variants = await fetchVoiceVariants(props.primaryKey);
|
|
1122
|
+
allVariants.value = variants;
|
|
1123
|
+
for (const v of allVariants.value) {
|
|
1124
|
+
const isUuid = v.audio_file_id?.includes("-");
|
|
1125
|
+
v.audioUrl = isUuid ? getAudioUrl(v.audio_file_id) : await resolveAudioFileUrl(v.audio_file_id);
|
|
1126
|
+
}
|
|
1127
|
+
currentVariantIndex.value = 0;
|
|
1128
|
+
hasExistingVoices.value = variants.length > 0;
|
|
1129
|
+
}
|
|
1130
|
+
function formatVariantDate(dateStr) {
|
|
1131
|
+
if (!dateStr) return "";
|
|
1132
|
+
return new Date(dateStr).toLocaleString();
|
|
1133
|
+
}
|
|
1134
|
+
function getVoiceNameFromConfig(config) {
|
|
1135
|
+
return config?.voice_id || "Unknown";
|
|
1136
|
+
}
|
|
986
1137
|
async function loadVariantAtIndex(index) {
|
|
987
1138
|
const variant = allVariants.value[index];
|
|
988
1139
|
if (!variant) return;
|
|
@@ -1015,25 +1166,41 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1015
1166
|
function regenerateVoiceover() {
|
|
1016
1167
|
generateVoiceover();
|
|
1017
1168
|
}
|
|
1018
|
-
function confirmVoiceover() {
|
|
1019
|
-
const
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1169
|
+
async function confirmVoiceover() {
|
|
1170
|
+
const variant = selectedVariant.value;
|
|
1171
|
+
if (!variant) return;
|
|
1172
|
+
try {
|
|
1173
|
+
await linkAudioToLesson(
|
|
1174
|
+
props.primaryKey,
|
|
1175
|
+
variant.audio_file_id,
|
|
1176
|
+
props.collection || "SM_Lessons"
|
|
1177
|
+
);
|
|
1178
|
+
const value = {
|
|
1179
|
+
audio_file_id: variant.audio_file_id,
|
|
1180
|
+
model: variant.voice_config?.provider || selectedModel.value,
|
|
1181
|
+
voice_id: variant.voice_config?.voice_id || selectedVoiceId.value,
|
|
1182
|
+
tone_id: variant.voice_config?.tone_id || selectedToneId.value,
|
|
1183
|
+
style_id: variant.voice_config?.style_id || selectedStyleId.value,
|
|
1184
|
+
custom_tone: customTone.value,
|
|
1185
|
+
custom_style: customStyle.value,
|
|
1186
|
+
preprocessing: variant.voice_config?.preprocessing ?? preprocessingEnabled.value,
|
|
1187
|
+
confirmed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1188
|
+
};
|
|
1189
|
+
emit("input", value);
|
|
1190
|
+
goBackToSelection();
|
|
1191
|
+
} catch (error) {
|
|
1192
|
+
console.error("Failed to link audio:", error);
|
|
1193
|
+
}
|
|
1031
1194
|
}
|
|
1032
1195
|
async function viewGeneratedVoices() {
|
|
1033
1196
|
try {
|
|
1034
1197
|
const variants = await fetchVoiceVariants(props.primaryKey);
|
|
1035
1198
|
if (variants.length > 0) {
|
|
1036
1199
|
allVariants.value = variants;
|
|
1200
|
+
for (const v of allVariants.value) {
|
|
1201
|
+
const isUuid = v.audio_file_id?.includes("-");
|
|
1202
|
+
v.audioUrl = isUuid ? getAudioUrl(v.audio_file_id) : await resolveAudioFileUrl(v.audio_file_id);
|
|
1203
|
+
}
|
|
1037
1204
|
currentVariantIndex.value = 0;
|
|
1038
1205
|
await loadVariantAtIndex(0);
|
|
1039
1206
|
currentMode.value = "result";
|
|
@@ -1042,27 +1209,6 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1042
1209
|
console.error("Failed to fetch voice variants:", error);
|
|
1043
1210
|
}
|
|
1044
1211
|
}
|
|
1045
|
-
function getModelName(modelId) {
|
|
1046
|
-
const model = VOICE_MODELS.find((m) => m.id === modelId);
|
|
1047
|
-
return model?.name || modelId;
|
|
1048
|
-
}
|
|
1049
|
-
function getVoiceName(voiceId) {
|
|
1050
|
-
if (!voiceId) return "Not selected";
|
|
1051
|
-
const voice = voices.value.find((v) => v.id === voiceId);
|
|
1052
|
-
return voice?.name || voiceId;
|
|
1053
|
-
}
|
|
1054
|
-
function getToneName(toneId) {
|
|
1055
|
-
if (!toneId) return "Not selected";
|
|
1056
|
-
if (toneId === "other") return customTone.value || "Custom";
|
|
1057
|
-
const tone = tones.value.find((t) => t.id === toneId);
|
|
1058
|
-
return tone?.name || toneId;
|
|
1059
|
-
}
|
|
1060
|
-
function getStyleName(styleId) {
|
|
1061
|
-
if (!styleId) return "Not selected";
|
|
1062
|
-
if (styleId === "other") return customStyle.value || "Custom";
|
|
1063
|
-
const style = styles.value.find((s) => s.id === styleId);
|
|
1064
|
-
return style?.name || styleId;
|
|
1065
|
-
}
|
|
1066
1212
|
async function initialize() {
|
|
1067
1213
|
loading.value = true;
|
|
1068
1214
|
initError.value = null;
|
|
@@ -1172,7 +1318,14 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1172
1318
|
/* STYLE */
|
|
1173
1319
|
)
|
|
1174
1320
|
]),
|
|
1175
|
-
errorMessage.value ? (openBlock(), createElementBlock(
|
|
1321
|
+
progressStatus.value && !errorMessage.value ? (openBlock(), createElementBlock(
|
|
1322
|
+
"p",
|
|
1323
|
+
_hoisted_5,
|
|
1324
|
+
" Status: " + toDisplayString(progressStatus.value),
|
|
1325
|
+
1
|
|
1326
|
+
/* TEXT */
|
|
1327
|
+
)) : createCommentVNode("v-if", true),
|
|
1328
|
+
errorMessage.value ? (openBlock(), createElementBlock("div", _hoisted_6, [
|
|
1176
1329
|
createVNode(_component_v_icon, { name: "error" }),
|
|
1177
1330
|
createElementVNode(
|
|
1178
1331
|
"span",
|
|
@@ -1197,7 +1350,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1197
1350
|
{ key: 1 },
|
|
1198
1351
|
[
|
|
1199
1352
|
createCommentVNode(" Loading State "),
|
|
1200
|
-
createElementVNode("div",
|
|
1353
|
+
createElementVNode("div", _hoisted_7, [
|
|
1201
1354
|
createVNode(_component_v_icon, {
|
|
1202
1355
|
name: "refresh",
|
|
1203
1356
|
class: "spinning"
|
|
@@ -1218,7 +1371,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1218
1371
|
{ key: 2 },
|
|
1219
1372
|
[
|
|
1220
1373
|
createCommentVNode(" Error State "),
|
|
1221
|
-
createElementVNode("div",
|
|
1374
|
+
createElementVNode("div", _hoisted_8, [
|
|
1222
1375
|
createVNode(_component_v_icon, { name: "error" }),
|
|
1223
1376
|
createElementVNode(
|
|
1224
1377
|
"span",
|
|
@@ -1240,10 +1393,10 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1240
1393
|
{ key: 3 },
|
|
1241
1394
|
[
|
|
1242
1395
|
createCommentVNode(" Page 1: Selection Mode "),
|
|
1243
|
-
createElementVNode("div",
|
|
1244
|
-
createElementVNode("div",
|
|
1245
|
-
createElementVNode("div",
|
|
1246
|
-
createElementVNode("h2",
|
|
1396
|
+
createElementVNode("div", _hoisted_9, [
|
|
1397
|
+
createElementVNode("div", _hoisted_10, [
|
|
1398
|
+
createElementVNode("div", _hoisted_11, [
|
|
1399
|
+
createElementVNode("h2", _hoisted_12, [
|
|
1247
1400
|
createVNode(_component_v_icon, { name: "mic" }),
|
|
1248
1401
|
_cache[4] || (_cache[4] = createTextVNode(
|
|
1249
1402
|
" Voice Generation ",
|
|
@@ -1260,7 +1413,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1260
1413
|
name: headerExpanded.value ? "expand_less" : "expand_more",
|
|
1261
1414
|
small: ""
|
|
1262
1415
|
}, null, 8, ["name"])
|
|
1263
|
-
], 8,
|
|
1416
|
+
], 8, _hoisted_13)
|
|
1264
1417
|
]),
|
|
1265
1418
|
_cache[5] || (_cache[5] = createElementVNode(
|
|
1266
1419
|
"p",
|
|
@@ -1272,9 +1425,9 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1272
1425
|
]),
|
|
1273
1426
|
withDirectives(createElementVNode(
|
|
1274
1427
|
"div",
|
|
1275
|
-
|
|
1428
|
+
_hoisted_14,
|
|
1276
1429
|
[
|
|
1277
|
-
createElementVNode("div",
|
|
1430
|
+
createElementVNode("div", _hoisted_15, [
|
|
1278
1431
|
_cache[6] || (_cache[6] = createElementVNode(
|
|
1279
1432
|
"label",
|
|
1280
1433
|
{ class: "widget__url-label" },
|
|
@@ -1287,7 +1440,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1287
1440
|
class: "widget__url-field",
|
|
1288
1441
|
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => flowId.value = $event),
|
|
1289
1442
|
disabled: savingUrl.value
|
|
1290
|
-
}, null, 8,
|
|
1443
|
+
}, null, 8, _hoisted_16), [
|
|
1291
1444
|
[vModelText, flowId.value]
|
|
1292
1445
|
])
|
|
1293
1446
|
])
|
|
@@ -1300,7 +1453,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1300
1453
|
])
|
|
1301
1454
|
]),
|
|
1302
1455
|
createCommentVNode(" Model Selection "),
|
|
1303
|
-
createElementVNode("div",
|
|
1456
|
+
createElementVNode("div", _hoisted_17, [
|
|
1304
1457
|
_cache[7] || (_cache[7] = createElementVNode(
|
|
1305
1458
|
"label",
|
|
1306
1459
|
{ class: "widget__section-label" },
|
|
@@ -1308,7 +1461,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1308
1461
|
-1
|
|
1309
1462
|
/* CACHED */
|
|
1310
1463
|
)),
|
|
1311
|
-
createElementVNode("div",
|
|
1464
|
+
createElementVNode("div", _hoisted_18, [
|
|
1312
1465
|
(openBlock(true), createElementBlock(
|
|
1313
1466
|
Fragment,
|
|
1314
1467
|
null,
|
|
@@ -1317,7 +1470,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1317
1470
|
key: model.id,
|
|
1318
1471
|
class: normalizeClass(["widget__model-btn", { "widget__model-btn--active": selectedModel.value === model.id }]),
|
|
1319
1472
|
onClick: ($event) => selectModel(model.id)
|
|
1320
|
-
}, toDisplayString(model.name), 11,
|
|
1473
|
+
}, toDisplayString(model.name), 11, _hoisted_19);
|
|
1321
1474
|
}),
|
|
1322
1475
|
128
|
|
1323
1476
|
/* KEYED_FRAGMENT */
|
|
@@ -1325,7 +1478,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1325
1478
|
])
|
|
1326
1479
|
]),
|
|
1327
1480
|
createCommentVNode(" Voice Selection "),
|
|
1328
|
-
createElementVNode("div",
|
|
1481
|
+
createElementVNode("div", _hoisted_20, [
|
|
1329
1482
|
_cache[8] || (_cache[8] = createElementVNode(
|
|
1330
1483
|
"label",
|
|
1331
1484
|
{ class: "widget__section-label" },
|
|
@@ -1333,7 +1486,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1333
1486
|
-1
|
|
1334
1487
|
/* CACHED */
|
|
1335
1488
|
)),
|
|
1336
|
-
createElementVNode("div",
|
|
1489
|
+
createElementVNode("div", _hoisted_21, [
|
|
1337
1490
|
(openBlock(true), createElementBlock(
|
|
1338
1491
|
Fragment,
|
|
1339
1492
|
null,
|
|
@@ -1355,7 +1508,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1355
1508
|
])
|
|
1356
1509
|
]),
|
|
1357
1510
|
createCommentVNode(" Tone Selection "),
|
|
1358
|
-
createElementVNode("div",
|
|
1511
|
+
createElementVNode("div", _hoisted_22, [
|
|
1359
1512
|
_cache[9] || (_cache[9] = createElementVNode(
|
|
1360
1513
|
"label",
|
|
1361
1514
|
{ class: "widget__section-label" },
|
|
@@ -1373,7 +1526,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1373
1526
|
}, null, 8, ["items", "selected-id", "custom-value"])
|
|
1374
1527
|
]),
|
|
1375
1528
|
createCommentVNode(" Style Selection "),
|
|
1376
|
-
createElementVNode("div",
|
|
1529
|
+
createElementVNode("div", _hoisted_23, [
|
|
1377
1530
|
_cache[10] || (_cache[10] = createElementVNode(
|
|
1378
1531
|
"label",
|
|
1379
1532
|
{ class: "widget__section-label" },
|
|
@@ -1391,8 +1544,8 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1391
1544
|
}, null, 8, ["items", "selected-id", "custom-value"])
|
|
1392
1545
|
]),
|
|
1393
1546
|
createCommentVNode(" Preprocessing Toggle "),
|
|
1394
|
-
createElementVNode("div",
|
|
1395
|
-
createElementVNode("label",
|
|
1547
|
+
createElementVNode("div", _hoisted_24, [
|
|
1548
|
+
createElementVNode("label", _hoisted_25, [
|
|
1396
1549
|
withDirectives(createElementVNode(
|
|
1397
1550
|
"input",
|
|
1398
1551
|
{
|
|
@@ -1422,7 +1575,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1422
1575
|
))
|
|
1423
1576
|
]),
|
|
1424
1577
|
createCommentVNode(" Footer Actions "),
|
|
1425
|
-
createElementVNode("div",
|
|
1578
|
+
createElementVNode("div", _hoisted_26, [
|
|
1426
1579
|
_cache[13] || (_cache[13] = createElementVNode(
|
|
1427
1580
|
"div",
|
|
1428
1581
|
{ class: "widget__footer-left" },
|
|
@@ -1430,17 +1583,17 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1430
1583
|
-1
|
|
1431
1584
|
/* CACHED */
|
|
1432
1585
|
)),
|
|
1433
|
-
createElementVNode("div",
|
|
1586
|
+
createElementVNode("div", _hoisted_27, [
|
|
1434
1587
|
createElementVNode("button", {
|
|
1435
1588
|
class: "widget__btn widget__btn--secondary",
|
|
1436
1589
|
onClick: viewGeneratedVoices,
|
|
1437
1590
|
disabled: !hasExistingVoices.value
|
|
1438
|
-
}, " View Generated Voices ", 8,
|
|
1591
|
+
}, " View Generated Voices ", 8, _hoisted_28),
|
|
1439
1592
|
createElementVNode("button", {
|
|
1440
1593
|
class: "widget__btn widget__btn--primary",
|
|
1441
1594
|
onClick: generateVoiceover,
|
|
1442
1595
|
disabled: !canGenerate.value
|
|
1443
|
-
}, " Generate Voiceover ", 8,
|
|
1596
|
+
}, " Generate Voiceover ", 8, _hoisted_29)
|
|
1444
1597
|
])
|
|
1445
1598
|
])
|
|
1446
1599
|
],
|
|
@@ -1450,163 +1603,147 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1450
1603
|
Fragment,
|
|
1451
1604
|
{ key: 4 },
|
|
1452
1605
|
[
|
|
1453
|
-
createCommentVNode(" Page 3: Result Mode "),
|
|
1454
|
-
createElementVNode("div",
|
|
1455
|
-
createElementVNode("div",
|
|
1456
|
-
createElementVNode("div",
|
|
1457
|
-
createElementVNode("h2",
|
|
1606
|
+
createCommentVNode(" Page 3: Result Mode - List View "),
|
|
1607
|
+
createElementVNode("div", _hoisted_30, [
|
|
1608
|
+
createElementVNode("div", _hoisted_31, [
|
|
1609
|
+
createElementVNode("div", _hoisted_32, [
|
|
1610
|
+
createElementVNode("h2", _hoisted_33, [
|
|
1458
1611
|
createVNode(_component_v_icon, { name: "check_circle" }),
|
|
1459
1612
|
_cache[14] || (_cache[14] = createTextVNode(
|
|
1460
|
-
"
|
|
1613
|
+
" Generated Voiceovers ",
|
|
1461
1614
|
-1
|
|
1462
1615
|
/* CACHED */
|
|
1463
1616
|
))
|
|
1464
1617
|
]),
|
|
1465
|
-
createElementVNode(
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
[
|
|
1470
|
-
createTextVNode(
|
|
1471
|
-
" Viewing " + toDisplayString(currentVariantIndex.value + 1) + " of " + toDisplayString(allVariants.value.length) + " generated voiceovers ",
|
|
1472
|
-
1
|
|
1473
|
-
/* TEXT */
|
|
1474
|
-
)
|
|
1475
|
-
],
|
|
1476
|
-
64
|
|
1477
|
-
/* STABLE_FRAGMENT */
|
|
1478
|
-
)) : (openBlock(), createElementBlock(
|
|
1479
|
-
Fragment,
|
|
1480
|
-
{ key: 1 },
|
|
1481
|
-
[
|
|
1482
|
-
createTextVNode(" Listen to your generated voiceover and confirm or regenerate ")
|
|
1483
|
-
],
|
|
1484
|
-
64
|
|
1485
|
-
/* STABLE_FRAGMENT */
|
|
1486
|
-
))
|
|
1487
|
-
])
|
|
1488
|
-
])
|
|
1489
|
-
])
|
|
1490
|
-
]),
|
|
1491
|
-
createCommentVNode(" Navigation for multiple variants "),
|
|
1492
|
-
allVariants.value.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_34, [
|
|
1493
|
-
createElementVNode("button", {
|
|
1494
|
-
class: "widget__btn widget__btn--icon",
|
|
1495
|
-
onClick: prevVariant,
|
|
1496
|
-
disabled: currentVariantIndex.value === 0
|
|
1497
|
-
}, [
|
|
1498
|
-
createVNode(_component_v_icon, { name: "chevron_left" })
|
|
1499
|
-
], 8, _hoisted_35),
|
|
1500
|
-
createElementVNode(
|
|
1501
|
-
"span",
|
|
1502
|
-
_hoisted_36,
|
|
1503
|
-
toDisplayString(currentVariantIndex.value + 1) + " / " + toDisplayString(allVariants.value.length),
|
|
1504
|
-
1
|
|
1505
|
-
/* TEXT */
|
|
1506
|
-
),
|
|
1507
|
-
createElementVNode("button", {
|
|
1508
|
-
class: "widget__btn widget__btn--icon",
|
|
1509
|
-
onClick: nextVariant,
|
|
1510
|
-
disabled: currentVariantIndex.value === allVariants.value.length - 1
|
|
1511
|
-
}, [
|
|
1512
|
-
createVNode(_component_v_icon, { name: "chevron_right" })
|
|
1513
|
-
], 8, _hoisted_37)
|
|
1514
|
-
])) : createCommentVNode("v-if", true),
|
|
1515
|
-
createElementVNode("div", _hoisted_38, [
|
|
1516
|
-
createVNode(AudioPlayer, {
|
|
1517
|
-
src: generatedAudioUrl.value,
|
|
1518
|
-
loading: false,
|
|
1519
|
-
size: "large"
|
|
1520
|
-
}, null, 8, ["src"]),
|
|
1521
|
-
createElementVNode("div", _hoisted_39, [
|
|
1522
|
-
createElementVNode("p", null, [
|
|
1523
|
-
_cache[15] || (_cache[15] = createElementVNode(
|
|
1524
|
-
"strong",
|
|
1525
|
-
null,
|
|
1526
|
-
"Model:",
|
|
1527
|
-
-1
|
|
1528
|
-
/* CACHED */
|
|
1529
|
-
)),
|
|
1530
|
-
createTextVNode(
|
|
1531
|
-
" " + toDisplayString(getModelName(selectedModel.value)),
|
|
1532
|
-
1
|
|
1533
|
-
/* TEXT */
|
|
1534
|
-
)
|
|
1535
|
-
]),
|
|
1536
|
-
createElementVNode("p", null, [
|
|
1537
|
-
_cache[16] || (_cache[16] = createElementVNode(
|
|
1538
|
-
"strong",
|
|
1539
|
-
null,
|
|
1540
|
-
"Voice:",
|
|
1541
|
-
-1
|
|
1542
|
-
/* CACHED */
|
|
1543
|
-
)),
|
|
1544
|
-
createTextVNode(
|
|
1545
|
-
" " + toDisplayString(getVoiceName(selectedVoiceId.value)),
|
|
1546
|
-
1
|
|
1547
|
-
/* TEXT */
|
|
1548
|
-
)
|
|
1549
|
-
]),
|
|
1550
|
-
createElementVNode("p", null, [
|
|
1551
|
-
_cache[17] || (_cache[17] = createElementVNode(
|
|
1552
|
-
"strong",
|
|
1553
|
-
null,
|
|
1554
|
-
"Tone:",
|
|
1555
|
-
-1
|
|
1556
|
-
/* CACHED */
|
|
1557
|
-
)),
|
|
1558
|
-
createTextVNode(
|
|
1559
|
-
" " + toDisplayString(getToneName(selectedToneId.value)),
|
|
1560
|
-
1
|
|
1561
|
-
/* TEXT */
|
|
1562
|
-
)
|
|
1563
|
-
]),
|
|
1564
|
-
createElementVNode("p", null, [
|
|
1565
|
-
_cache[18] || (_cache[18] = createElementVNode(
|
|
1566
|
-
"strong",
|
|
1567
|
-
null,
|
|
1568
|
-
"Style:",
|
|
1569
|
-
-1
|
|
1570
|
-
/* CACHED */
|
|
1571
|
-
)),
|
|
1572
|
-
createTextVNode(
|
|
1573
|
-
" " + toDisplayString(getStyleName(selectedStyleId.value)),
|
|
1574
|
-
1
|
|
1575
|
-
/* TEXT */
|
|
1576
|
-
)
|
|
1577
|
-
]),
|
|
1578
|
-
currentVariantDate.value ? (openBlock(), createElementBlock("p", _hoisted_40, [
|
|
1579
|
-
_cache[19] || (_cache[19] = createElementVNode(
|
|
1580
|
-
"strong",
|
|
1581
|
-
null,
|
|
1582
|
-
"Generated:",
|
|
1583
|
-
-1
|
|
1584
|
-
/* CACHED */
|
|
1585
|
-
)),
|
|
1586
|
-
createTextVNode(
|
|
1587
|
-
" " + toDisplayString(currentVariantDate.value),
|
|
1618
|
+
createElementVNode(
|
|
1619
|
+
"p",
|
|
1620
|
+
_hoisted_34,
|
|
1621
|
+
toDisplayString(allVariants.value.length) + " voiceover(s) available. Select one to preview and confirm. ",
|
|
1588
1622
|
1
|
|
1589
1623
|
/* TEXT */
|
|
1590
1624
|
)
|
|
1591
|
-
])
|
|
1625
|
+
])
|
|
1592
1626
|
])
|
|
1593
1627
|
]),
|
|
1594
|
-
|
|
1628
|
+
createCommentVNode(" Variants List "),
|
|
1629
|
+
createElementVNode("div", _hoisted_35, [
|
|
1630
|
+
(openBlock(true), createElementBlock(
|
|
1631
|
+
Fragment,
|
|
1632
|
+
null,
|
|
1633
|
+
renderList(allVariants.value, (variant, index) => {
|
|
1634
|
+
return openBlock(), createElementBlock("div", {
|
|
1635
|
+
key: variant.id,
|
|
1636
|
+
class: normalizeClass(["widget__variant-item", { "widget__variant-item--selected": currentVariantIndex.value === index }]),
|
|
1637
|
+
onClick: ($event) => selectVariant(index)
|
|
1638
|
+
}, [
|
|
1639
|
+
createElementVNode("div", _hoisted_37, [
|
|
1640
|
+
createElementVNode("input", {
|
|
1641
|
+
type: "radio",
|
|
1642
|
+
checked: currentVariantIndex.value === index,
|
|
1643
|
+
onChange: ($event) => selectVariant(index)
|
|
1644
|
+
}, null, 40, _hoisted_38)
|
|
1645
|
+
]),
|
|
1646
|
+
createElementVNode("div", _hoisted_39, [
|
|
1647
|
+
createVNode(AudioPlayer, {
|
|
1648
|
+
src: variant.audioUrl,
|
|
1649
|
+
loading: false,
|
|
1650
|
+
size: "small"
|
|
1651
|
+
}, null, 8, ["src"])
|
|
1652
|
+
]),
|
|
1653
|
+
createElementVNode("div", _hoisted_40, [
|
|
1654
|
+
createElementVNode(
|
|
1655
|
+
"span",
|
|
1656
|
+
_hoisted_41,
|
|
1657
|
+
toDisplayString(variant.voice_config?.provider) + " - " + toDisplayString(getVoiceNameFromConfig(variant.voice_config)),
|
|
1658
|
+
1
|
|
1659
|
+
/* TEXT */
|
|
1660
|
+
),
|
|
1661
|
+
createElementVNode(
|
|
1662
|
+
"span",
|
|
1663
|
+
_hoisted_42,
|
|
1664
|
+
toDisplayString(formatVariantDate(variant.date_created)),
|
|
1665
|
+
1
|
|
1666
|
+
/* TEXT */
|
|
1667
|
+
)
|
|
1668
|
+
]),
|
|
1669
|
+
createElementVNode("button", {
|
|
1670
|
+
class: "widget__btn widget__btn--icon widget__btn--danger",
|
|
1671
|
+
onClick: withModifiers(($event) => deleteVariant(variant.id), ["stop"]),
|
|
1672
|
+
title: "Delete this voiceover"
|
|
1673
|
+
}, [
|
|
1674
|
+
createVNode(_component_v_icon, {
|
|
1675
|
+
name: "delete",
|
|
1676
|
+
small: ""
|
|
1677
|
+
})
|
|
1678
|
+
], 8, _hoisted_43)
|
|
1679
|
+
], 10, _hoisted_36);
|
|
1680
|
+
}),
|
|
1681
|
+
128
|
|
1682
|
+
/* KEYED_FRAGMENT */
|
|
1683
|
+
))
|
|
1684
|
+
]),
|
|
1685
|
+
createCommentVNode(" Selected Variant Details "),
|
|
1686
|
+
selectedVariant.value ? (openBlock(), createElementBlock("div", _hoisted_44, [
|
|
1687
|
+
createElementVNode("p", null, [
|
|
1688
|
+
_cache[15] || (_cache[15] = createElementVNode(
|
|
1689
|
+
"strong",
|
|
1690
|
+
null,
|
|
1691
|
+
"Model:",
|
|
1692
|
+
-1
|
|
1693
|
+
/* CACHED */
|
|
1694
|
+
)),
|
|
1695
|
+
createTextVNode(
|
|
1696
|
+
" " + toDisplayString(selectedVariant.value.voice_config?.provider),
|
|
1697
|
+
1
|
|
1698
|
+
/* TEXT */
|
|
1699
|
+
)
|
|
1700
|
+
]),
|
|
1701
|
+
createElementVNode("p", null, [
|
|
1702
|
+
_cache[16] || (_cache[16] = createElementVNode(
|
|
1703
|
+
"strong",
|
|
1704
|
+
null,
|
|
1705
|
+
"Voice:",
|
|
1706
|
+
-1
|
|
1707
|
+
/* CACHED */
|
|
1708
|
+
)),
|
|
1709
|
+
createTextVNode(
|
|
1710
|
+
" " + toDisplayString(getVoiceNameFromConfig(selectedVariant.value.voice_config)),
|
|
1711
|
+
1
|
|
1712
|
+
/* TEXT */
|
|
1713
|
+
)
|
|
1714
|
+
]),
|
|
1715
|
+
createElementVNode("p", null, [
|
|
1716
|
+
_cache[17] || (_cache[17] = createElementVNode(
|
|
1717
|
+
"strong",
|
|
1718
|
+
null,
|
|
1719
|
+
"Style:",
|
|
1720
|
+
-1
|
|
1721
|
+
/* CACHED */
|
|
1722
|
+
)),
|
|
1723
|
+
createTextVNode(
|
|
1724
|
+
" " + toDisplayString(selectedVariant.value.voice_config?.style),
|
|
1725
|
+
1
|
|
1726
|
+
/* TEXT */
|
|
1727
|
+
)
|
|
1728
|
+
])
|
|
1729
|
+
])) : createCommentVNode("v-if", true),
|
|
1730
|
+
createElementVNode("div", _hoisted_45, [
|
|
1595
1731
|
createElementVNode("div", { class: "widget__footer-left" }, [
|
|
1596
1732
|
createElementVNode("button", {
|
|
1597
1733
|
class: "widget__btn widget__btn--secondary",
|
|
1598
1734
|
onClick: goBackToSelection
|
|
1599
|
-
}, "
|
|
1735
|
+
}, " Back ")
|
|
1600
1736
|
]),
|
|
1601
|
-
createElementVNode("div",
|
|
1737
|
+
createElementVNode("div", _hoisted_46, [
|
|
1602
1738
|
createElementVNode("button", {
|
|
1603
1739
|
class: "widget__btn widget__btn--secondary",
|
|
1604
1740
|
onClick: regenerateVoiceover
|
|
1605
1741
|
}, " Regenerate "),
|
|
1606
1742
|
createElementVNode("button", {
|
|
1607
1743
|
class: "widget__btn widget__btn--primary",
|
|
1608
|
-
onClick: confirmVoiceover
|
|
1609
|
-
|
|
1744
|
+
onClick: confirmVoiceover,
|
|
1745
|
+
disabled: !selectedVariant.value
|
|
1746
|
+
}, " Confirm ", 8, _hoisted_47)
|
|
1610
1747
|
])
|
|
1611
1748
|
])
|
|
1612
1749
|
],
|
|
@@ -1618,10 +1755,10 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1618
1755
|
}
|
|
1619
1756
|
});
|
|
1620
1757
|
|
|
1621
|
-
var css = "\n.voice-widget[data-v-
|
|
1758
|
+
var css = "\n.voice-widget[data-v-10fc7a16] {\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-10fc7a16] {\n margin-bottom: 20px;\n}\n.widget__header-row[data-v-10fc7a16] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 16px;\n}\n.widget__header-text[data-v-10fc7a16] {\n flex: 1;\n}\n.widget__title[data-v-10fc7a16] {\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-10fc7a16] {\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-10fc7a16]:hover {\n background: var(--theme--background-accent);\n}\n.widget__subtitle[data-v-10fc7a16] {\n margin: 0;\n font-size: 14px;\n color: var(--theme--foreground-subdued);\n}\n.widget__header-controls[data-v-10fc7a16] {\n display: flex;\n gap: 16px;\n align-items: center;\n}\n.widget__url-input[data-v-10fc7a16] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.widget__url-label[data-v-10fc7a16] {\n font-size: 12px;\n color: var(--theme--foreground-subdued);\n white-space: nowrap;\n}\n.widget__url-field[data-v-10fc7a16] {\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-10fc7a16] {\n margin-bottom: 20px;\n}\n.widget__section-label[data-v-10fc7a16] {\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-10fc7a16] {\n display: flex;\n gap: 8px;\n}\n.widget__model-btn[data-v-10fc7a16] {\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-10fc7a16]:hover {\n border-color: var(--theme--primary);\n}\n.widget__model-btn--active[data-v-10fc7a16] {\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-10fc7a16] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.widget__section--toggle[data-v-10fc7a16] {\n padding: 12px;\n background: var(--theme--background-subdued);\n border-radius: var(--theme--border-radius);\n}\n.widget__toggle[data-v-10fc7a16] {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n}\n.widget__toggle input[data-v-10fc7a16] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n}\n.widget__toggle-label[data-v-10fc7a16] {\n font-size: 14px;\n font-weight: 500;\n color: var(--theme--foreground);\n}\n.widget__toggle-note[data-v-10fc7a16] {\n margin: 4px 0 0 24px;\n font-size: 12px;\n color: var(--theme--foreground-subdued);\n}\n.widget__footer[data-v-10fc7a16] {\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-10fc7a16],\n.widget__footer-right[data-v-10fc7a16] {\n display: flex;\n gap: 8px;\n}\n.widget__variant-nav[data-v-10fc7a16] {\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-10fc7a16] {\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-10fc7a16] {\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-10fc7a16] {\n margin-top: 8px;\n font-size: 12px;\n color: var(--theme--foreground-subdued);\n}\n.widget__btn[data-v-10fc7a16] {\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-10fc7a16]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.widget__btn--primary[data-v-10fc7a16] {\n background: var(--theme--primary);\n color: var(--theme--primary-foreground, #fff);\n}\n.widget__btn--primary[data-v-10fc7a16]:hover:not(:disabled) {\n background: var(--theme--primary-accent);\n}\n.widget__btn--secondary[data-v-10fc7a16] {\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-10fc7a16]:hover:not(:disabled) {\n background: var(--theme--background-normal);\n}\n\n/* Processing State */\n.widget__processing[data-v-10fc7a16] {\n padding: 40px 20px;\n text-align: center;\n}\n.widget__progress[data-v-10fc7a16] {\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-10fc7a16] {\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-10fc7a16] {\n height: 100%;\n background: var(--theme--primary);\n transition: width 0.3s ease;\n}\n\n/* Error State */\n.widget__error[data-v-10fc7a16] {\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-10fc7a16] {\n display: flex;\n gap: 8px;\n margin-top: 8px;\n}\n.widget__retry[data-v-10fc7a16] {\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-10fc7a16] {\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-10fc7a16] {\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-10fc7a16] {\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-10fc7a16] {\n margin: 4px 0;\n font-size: 14px;\n color: var(--theme--foreground-subdued);\n}\n.widget__result-info strong[data-v-10fc7a16] {\n color: var(--theme--foreground);\n}\n\n/* Variants List View */\n.widget__variants-list[data-v-10fc7a16] {\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-10fc7a16] {\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-10fc7a16]:hover {\n border-color: var(--theme--primary);\n}\n.widget__variant-item--selected[data-v-10fc7a16] {\n border-color: var(--theme--primary);\n background: var(--theme--primary-background);\n}\n.widget__variant-radio[data-v-10fc7a16] {\n flex-shrink: 0;\n}\n.widget__variant-radio input[data-v-10fc7a16] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n}\n.widget__variant-player[data-v-10fc7a16] {\n flex: 1;\n min-width: 200px;\n}\n.widget__variant-meta[data-v-10fc7a16] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 120px;\n}\n.widget__variant-voice[data-v-10fc7a16] {\n font-size: 13px;\n font-weight: 500;\n color: var(--theme--foreground);\n}\n.widget__variant-date[data-v-10fc7a16] {\n font-size: 11px;\n color: var(--theme--foreground-subdued);\n}\n.widget__btn--danger[data-v-10fc7a16] {\n color: var(--theme--danger);\n background: transparent;\n border: none;\n}\n.widget__btn--danger[data-v-10fc7a16]:hover {\n background: var(--theme--danger-background);\n}\n.widget__selected-info[data-v-10fc7a16] {\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-10fc7a16] {\n margin: 4px 0;\n font-size: 14px;\n color: var(--theme--foreground-subdued);\n}\n.widget__selected-info strong[data-v-10fc7a16] {\n color: var(--theme--foreground);\n}\n.widget__progress-status[data-v-10fc7a16] {\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-10fc7a16] {\n animation: spin-10fc7a16 1s linear infinite;\n}\n@keyframes spin-10fc7a16 {\nfrom { transform: rotate(0deg);\n}\nto { transform: rotate(360deg);\n}\n}\n";
|
|
1622
1759
|
n(css,{});
|
|
1623
1760
|
|
|
1624
|
-
var InterfaceComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
1761
|
+
var InterfaceComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-10fc7a16"], ["__file", "interface.vue"]]);
|
|
1625
1762
|
|
|
1626
1763
|
var index = defineInterface({
|
|
1627
1764
|
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.2",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"readme": "README.md",
|
|
8
8
|
"repository": {
|