@dataclouder/ngx-agent-cards 0.0.84 → 0.0.85

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.
@@ -1,42 +1,44 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Injectable, Inject, Component, Input, Pipe, ChangeDetectionStrategy, EventEmitter, Output, ViewChild, Optional, ViewChildren } from '@angular/core';
3
- import * as i2 from '@angular/common';
2
+ import { InjectionToken, Injectable, Inject, Component, Input, signal, inject, DestroyRef, EventEmitter, effect, ChangeDetectionStrategy, Output, Pipe, ViewChild, Optional, ViewChildren } from '@angular/core';
3
+ import * as i1$1 from '@angular/common';
4
4
  import { CommonModule, NgComponentOutlet } from '@angular/common';
5
5
  import * as i1 from '@angular/platform-browser';
6
- import * as i1$1 from '@angular/forms';
7
- import { ReactiveFormsModule, FormControl, FormsModule } from '@angular/forms';
8
- import * as i1$2 from 'primeng/dynamicdialog';
6
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
7
+ import { BehaviorSubject, Subject, fromEvent, filter } from 'rxjs';
8
+ import { takeUntil, map } from 'rxjs/operators';
9
+ import * as i1$2 from '@angular/forms';
10
+ import { FormControl, ReactiveFormsModule, FormsModule } from '@angular/forms';
11
+ import * as i1$3 from 'primeng/dynamicdialog';
9
12
  import { DialogService, DynamicDialogModule } from 'primeng/dynamicdialog';
10
- import * as i6 from 'primeng/skeleton';
13
+ import * as i4$1 from 'primeng/skeleton';
11
14
  import { SkeletonModule } from 'primeng/skeleton';
12
- import * as i6$1 from 'primeng/dialog';
15
+ import * as i5$1 from 'primeng/dialog';
13
16
  import { DialogModule } from 'primeng/dialog';
14
- import * as i6$2 from '@dataclouder/ngx-core';
15
- import { TOAST_ALERTS_TOKEN, PaginationBase, DCFilterBarComponent, QuickTableComponent } from '@dataclouder/ngx-core';
16
- import { DCMicComponent } from '@dataclouder/ngx-mic';
17
- import * as i7$2 from 'primeng/progressbar';
17
+ import * as i2 from 'primeng/progressbar';
18
18
  import { ProgressBarModule } from 'primeng/progressbar';
19
- import * as i4$1 from 'primeng/checkbox';
19
+ import { DCMicComponent } from '@dataclouder/ngx-mic';
20
+ import * as i3 from 'primeng/textarea';
21
+ import { TextareaModule } from 'primeng/textarea';
22
+ import * as i7 from 'primeng/button';
23
+ import { ButtonModule } from 'primeng/button';
24
+ import * as i6 from '@dataclouder/ngx-core';
25
+ import { TOAST_ALERTS_TOKEN, AudioSpeed as AudioSpeed$1, PaginationBase, DCFilterBarComponent, QuickTableComponent } from '@dataclouder/ngx-core';
26
+ import * as i4$2 from 'primeng/checkbox';
20
27
  import { CheckboxModule } from 'primeng/checkbox';
21
28
  import { SliderModule } from 'primeng/slider';
22
- import * as i3 from 'primeng/radiobutton';
29
+ import * as i3$1 from 'primeng/radiobutton';
23
30
  import { RadioButtonModule } from 'primeng/radiobutton';
24
- import * as i7$1 from 'primeng/button';
25
- import { ButtonModule } from 'primeng/button';
26
31
  import * as i8 from 'primeng/rating';
27
32
  import { RatingModule } from 'primeng/rating';
28
33
  import * as i5 from 'primeng/table';
29
34
  import { TableModule } from 'primeng/table';
30
35
  import { BadgeModule } from 'primeng/badge';
31
- import * as i7 from 'primeng/tooltip';
36
+ import * as i7$1 from 'primeng/tooltip';
32
37
  import { TooltipModule } from 'primeng/tooltip';
33
- import { filter } from 'rxjs';
34
38
  import * as i4 from 'primeng/api';
35
39
  import { OverlayModule } from '@angular/cdk/overlay';
36
40
  import { PortalModule } from '@angular/cdk/portal';
37
- import * as i8$1 from 'primeng/textarea';
38
- import { TextareaModule } from 'primeng/textarea';
39
- import * as i5$1 from 'primeng/inputtext';
41
+ import * as i5$2 from 'primeng/inputtext';
40
42
  import { InputTextModule } from 'primeng/inputtext';
41
43
  import * as i11 from 'primeng/togglebutton';
42
44
  import { ToggleButtonModule } from 'primeng/togglebutton';
@@ -50,13 +52,13 @@ import * as i14 from 'primeng/select';
50
52
  import { SelectModule } from 'primeng/select';
51
53
  import * as i15 from 'primeng/popover';
52
54
  import { PopoverModule } from 'primeng/popover';
53
- import * as i3$1 from 'primeng/card';
55
+ import * as i3$2 from 'primeng/card';
54
56
  import { CardModule } from 'primeng/card';
55
- import * as i4$2 from 'primeng/dropdown';
57
+ import * as i4$3 from 'primeng/dropdown';
56
58
  import { DropdownModule } from 'primeng/dropdown';
57
59
  import { ChipModule } from 'primeng/chip';
58
- import * as i1$3 from '@angular/router';
59
- import * as i3$2 from 'primeng/paginator';
60
+ import * as i1$4 from '@angular/router';
61
+ import * as i3$3 from 'primeng/paginator';
60
62
  import { PaginatorModule } from 'primeng/paginator';
61
63
  import * as i2$3 from 'primeng/speeddial';
62
64
  import { SpeedDialModule } from 'primeng/speeddial';
@@ -79,6 +81,9 @@ var EAccountsPlatform;
79
81
  EAccountsPlatform["Youtube"] = "youtube";
80
82
  })(EAccountsPlatform || (EAccountsPlatform = {}));
81
83
  class WordTimestamps {
84
+ constructor() {
85
+ this.highlighted = false; // Initialize with false and use proper boolean type
86
+ }
82
87
  }
83
88
  class ChatMultiMessage {
84
89
  }
@@ -119,6 +124,20 @@ const LangCodeDescriptionEs = {
119
124
  pt: 'Portugués',
120
125
  fr: 'Frances',
121
126
  };
127
+ // TODO: use the default settings when the user is not set
128
+ const defaultconvUserSettings = {
129
+ realTime: false,
130
+ repeatRecording: false,
131
+ fixGrammar: false,
132
+ superHearing: false,
133
+ voice: '',
134
+ autoTranslate: false,
135
+ highlightWords: true,
136
+ synthVoice: true,
137
+ model: { modelName: null, provider: 'google' },
138
+ speed: null,
139
+ speedRate: null, // temporal
140
+ };
122
141
  class VoiceTTSOption {
123
142
  }
124
143
  const VoiceTTSOptions = [
@@ -531,17 +550,25 @@ class DCConversationPromptBuilderService {
531
550
  this.parseConversation(initialConversation, parseDict);
532
551
  return initialConversation;
533
552
  }
534
- getDefaultParseDict(parseDict, conversation) {
553
+ getDefaultParseDict(parseDict, card) {
554
+ // Example of return { char: 'AI Bot', user: 'jordan', ... custom params, base: 'spanish' };
555
+ // conversation will parse values with curren value in parseDcit:
556
+ // Hello {{user}} im {{char}} your are talking {{base}} -> hello jordan im AI bot your are talking spanish
557
+ // important you have to implement userDataExchange to return what you want in parseDict that have sense for your app.
535
558
  if (parseDict) {
536
559
  return parseDict;
537
560
  }
538
- if (!parseDict) {
561
+ else {
539
562
  parseDict = this.userDataExchange.getParseDict();
540
- if (!parseDict) {
541
- parseDict = { char: conversation.characterCard.data.name || 'Bot' };
542
- }
563
+ const cardParseDict = this.getDefaultCardParseDict(card);
564
+ parseDict = { ...parseDict, ...cardParseDict };
565
+ return parseDict;
543
566
  }
544
- return parseDict;
567
+ }
568
+ getDefaultCardParseDict(card) {
569
+ // bot so far i don't use more than the character name.
570
+ // this is what silly tavern call macros https://docs.sillytavern.app/usage/core-concepts/macros/#general-macros
571
+ return { char: card.characterCard.data.name || 'Bot' };
545
572
  }
546
573
  convertConversationToHtml(messages, jailBrake = '') {
547
574
  let finalPrompt = '';
@@ -643,8 +670,8 @@ class DCConversationPromptBuilderService {
643
670
  last_prompt: jailBrakePrompt,
644
671
  textEngine: agent.conversationSettings.textEngine,
645
672
  conversationType: ConversationType.Scenario,
646
- voice: agent.tts.voice,
647
- secondaryVoice: agent.tts.secondaryVoice,
673
+ voice: agent.conversationSettings.tts.voice,
674
+ secondaryVoice: agent.conversationSettings.tts.secondaryVoice,
648
675
  // overrideConversationSettings: { autoTranslate: false, highlightWords: false, realTime: false, provider: 'google' },
649
676
  };
650
677
  return settings;
@@ -662,129 +689,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImpor
662
689
  args: [USER_DATA_EXCHANGE]
663
690
  }] }] });
664
691
 
665
- const ICONS = {
666
- gear: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
667
- <path d="M12 1.75a1.25 1.25 0 0 1 1.25 1.25v.917a8.456 8.456 0 0 1 2.334.98l.645-.647a1.25 1.25 0 1 1 1.768 1.768l-.646.645c.389.69.729 1.437.98 2.334h.917a1.25 1.25 0 0 1 0 2.5h-.917a8.456 8.456 0 0 1-.98 2.334l.646.645a1.25 1.25 0 1 1-1.768 1.768l-.645-.646a8.456 8.456 0 0 1-2.334.98v.917a1.25 1.25 0 0 1-2.5 0v-.917a8.456 8.456 0 0 1-2.334-.98l-.645.646a1.25 1.25 0 1 1-1.768-1.768l.646-.645a8.456 8.456 0 0 1-.98-2.334H1.75a1.25 1.25 0 0 1 0-2.5h.917a8.456 8.456 0 0 1 .98-2.334l-.646-.645a1.25 1.25 0 1 1 1.768-1.768l.645.647c.69-.389 1.437-.729 2.334-.98V3a1.25 1.25 0 0 1 1.25-1.25h.083ZM12 7.5a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9Z"/>
668
- </svg>
669
- `,
670
- chat: `<svg viewBox="0 0 24 24" fill="currentColor">
671
- <path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c..." />
672
- </svg>`,
673
- play: `<svg
674
- xmlns="http://www.w3.org/2000/svg"
675
- width="16"
676
- height="16"
677
- viewBox="0 0 24 24"
678
- fill="none"
679
- stroke="#263042"
680
- stroke-width="2"
681
- stroke-linecap="round"
682
- stroke-linejoin="round">
683
- <circle cx="12" cy="12" r="10"></circle>
684
- <polygon points="10 8 16 12 10 16 10 8"></polygon>
685
- </svg>`,
686
- loading: `<svg
687
- xmlns="http://www.w3.org/2000/svg"
688
- width="16"
689
- height="16"
690
- viewBox="0 0 24 24"
691
- fill="none"
692
- stroke="#263042"
693
- stroke-width="2"
694
- stroke-linecap="round"
695
- stroke-linejoin="round">
696
- <line x1="12" y1="2" x2="12" y2="6"></line>
697
- <line x1="12" y1="18" x2="12" y2="22"></line>
698
- <line x1="4.93" y1="4.93" x2="7.76" y2="7.76"></line>
699
- <line x1="16.24" y1="16.24" x2="19.07" y2="19.07"></line>
700
- <line x1="2" y1="12" x2="6" y2="12"></line>
701
- <line x1="18" y1="12" x2="22" y2="12"></line>
702
- <line x1="4.93" y1="19.07" x2="7.76" y2="16.24"></line>
703
- <line x1="16.24" y1="7.76" x2="19.07" y2="4.93"></line>
704
- </svg>`,
705
- user: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
706
- <!-- Head circle -->
707
- <circle cx="12" cy="8" r="4" fill="currentColor"/>
708
-
709
- <!-- Body shape -->
710
- <path d="M20 19v1a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-1c0-3.87 3.13-7 7-7h2c3.87 0 7 3.13 7 7z" fill="currentColor"/>
711
- </svg>`,
712
- ai: `<svg
713
- xmlns="http://www.w3.org/2000/svg"
714
- viewBox="0 0 100 100"
715
- width="100"
716
- height="100"
717
- fill="none"
718
- stroke="black"
719
- stroke-width="2"
720
- >
721
- <!-- Brain outline -->
722
- <path
723
- d="M50 10
724
- C60 10, 70 20, 70 30
725
- S60 50, 50 50
726
- S30 40, 30 30
727
- S40 10, 50 10Z"
728
- fill="#B3E5FC"
729
- />
730
-
731
- <!-- Circuit lines -->
732
- <line x1="50" y1="50" x2="50" y2="70" stroke="#0288D1" stroke-width="2" />
733
- <line x1="50" y1="70" x2="40" y2="80" stroke="#0288D1" stroke-width="2" />
734
- <line x1="50" y1="70" x2="60" y2="80" stroke="#0288D1" stroke-width="2" />
735
-
736
- <!-- Nodes -->
737
- <circle cx="50" cy="70" r="2" fill="#0288D1" />
738
- <circle cx="40" cy="80" r="3" fill="#0288D1" />
739
- <circle cx="60" cy="80" r="3" fill="#0288D1" />
740
- </svg>
741
- `,
742
- };
743
-
744
- class IconsComponent {
745
- constructor(sanitizer) {
746
- this.sanitizer = sanitizer;
747
- this.size = 14;
748
- this.color = 'currentColor';
749
- }
750
- ngOnChanges(changes) {
751
- if (changes['name']) {
752
- const svg = ICONS[this.name] || '';
753
- this.sanitizedIcon = this.sanitizer.bypassSecurityTrustHtml(svg);
754
- }
755
- }
756
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: IconsComponent, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
757
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.1", type: IconsComponent, isStandalone: true, selector: "dc-icon", inputs: { name: "name", size: "size", color: "color" }, usesOnChanges: true, ngImport: i0, template: `
758
- <span
759
- [innerHTML]="sanitizedIcon"
760
- [style.display]="'inline-flex'"
761
- [style.alignItems]="'center'"
762
- [style.justifyContent]="'center'"
763
- [style.width.px]="size"
764
- [style.height.px]="size"
765
- [style.color]="color"></span>
766
- `, isInline: true, styles: [":host{display:inline-flex;align-items:center;line-height:0}span{line-height:0}:host ::ng-deep svg{width:100%;height:100%}\n"] }); }
767
- }
768
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: IconsComponent, decorators: [{
769
- type: Component,
770
- args: [{ selector: 'dc-icon', template: `
771
- <span
772
- [innerHTML]="sanitizedIcon"
773
- [style.display]="'inline-flex'"
774
- [style.alignItems]="'center'"
775
- [style.justifyContent]="'center'"
776
- [style.width.px]="size"
777
- [style.height.px]="size"
778
- [style.color]="color"></span>
779
- `, standalone: true, styles: [":host{display:inline-flex;align-items:center;line-height:0}span{line-height:0}:host ::ng-deep svg{width:100%;height:100%}\n"] }]
780
- }], ctorParameters: () => [{ type: i1.DomSanitizer }], propDecorators: { name: [{
781
- type: Input
782
- }], size: [{
783
- type: Input
784
- }], color: [{
785
- type: Input
786
- }] } });
787
-
788
692
  function markdownToHtml(markdown) {
789
693
  const htmlArray = [];
790
694
  const lines = markdown.split('\n');
@@ -968,23 +872,307 @@ function markdownToHTML2(markdown) {
968
872
  result.push({ content: `<q>${quoteText}</q>`, tag: 'q', text: quoteText });
969
873
  }
970
874
  }
971
- return result;
972
- }
973
- function removeEmojis(text) {
974
- // This regex pattern matches emoji characters
975
- return text.replace(/[\u{1F000}-\u{1F6FF}|\u{1F900}-\u{1F9FF}|\u{2600}-\u{26FF}|\u{2700}-\u{27BF}|\u{1F300}-\u{1F5FF}|\u{1F680}-\u{1F6FF}|\u{1F1E0}-\u{1F1FF}|\u{1F900}-\u{1F9FF}|\u{1F100}-\u{1F1FF}|\u{1F200}-\u{1F2FF}|\u{2100}-\u{26FF}]/gu, '');
875
+ return result;
876
+ }
877
+ function removeEmojis(text) {
878
+ // This regex pattern matches emoji characters
879
+ return text.replace(/[\u{1F000}-\u{1F6FF}|\u{1F900}-\u{1F9FF}|\u{2600}-\u{26FF}|\u{2700}-\u{27BF}|\u{1F300}-\u{1F5FF}|\u{1F680}-\u{1F6FF}|\u{1F1E0}-\u{1F1FF}|\u{1F900}-\u{1F9FF}|\u{1F100}-\u{1F1FF}|\u{1F200}-\u{1F2FF}|\u{2100}-\u{26FF}]/gu, '');
880
+ }
881
+ function removeAllEmojis(text) {
882
+ // More comprehensive regex that catches:
883
+ // 1. Standard emojis
884
+ // 2. Emoji variations and modifiers
885
+ // 3. Symbol characters
886
+ // 4. Pictographs
887
+ // 5. Emoticons
888
+ // 6. Regional indicators
889
+ // 7. Flags
890
+ return text.replace(/[\p{Emoji_Presentation}\p{Extended_Pictographic}\u{1F3FB}-\u{1F3FF}\u{E0020}-\u{E007F}\u{FE00}-\u{FE0F}\u{1F900}-\u{1F9FF}\u{1F1E6}-\u{1F1FF}]/gu, '');
891
+ }
892
+
893
+ const ICONS = {
894
+ gear: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
895
+ <path d="M12 1.75a1.25 1.25 0 0 1 1.25 1.25v.917a8.456 8.456 0 0 1 2.334.98l.645-.647a1.25 1.25 0 1 1 1.768 1.768l-.646.645c.389.69.729 1.437.98 2.334h.917a1.25 1.25 0 0 1 0 2.5h-.917a8.456 8.456 0 0 1-.98 2.334l.646.645a1.25 1.25 0 1 1-1.768 1.768l-.645-.646a8.456 8.456 0 0 1-2.334.98v.917a1.25 1.25 0 0 1-2.5 0v-.917a8.456 8.456 0 0 1-2.334-.98l-.645.646a1.25 1.25 0 1 1-1.768-1.768l.646-.645a8.456 8.456 0 0 1-.98-2.334H1.75a1.25 1.25 0 0 1 0-2.5h.917a8.456 8.456 0 0 1 .98-2.334l-.646-.645a1.25 1.25 0 1 1 1.768-1.768l.645.647c.69-.389 1.437-.729 2.334-.98V3a1.25 1.25 0 0 1 1.25-1.25h.083ZM12 7.5a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9Z"/>
896
+ </svg>
897
+ `,
898
+ chat: `<svg viewBox="0 0 24 24" fill="currentColor">
899
+ <path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c..." />
900
+ </svg>`,
901
+ play: `<svg
902
+ xmlns="http://www.w3.org/2000/svg"
903
+ width="16"
904
+ height="16"
905
+ viewBox="0 0 24 24"
906
+ fill="none"
907
+ stroke="#263042"
908
+ stroke-width="2"
909
+ stroke-linecap="round"
910
+ stroke-linejoin="round">
911
+ <circle cx="12" cy="12" r="10"></circle>
912
+ <polygon points="10 8 16 12 10 16 10 8"></polygon>
913
+ </svg>`,
914
+ loading: `<svg
915
+ xmlns="http://www.w3.org/2000/svg"
916
+ width="16"
917
+ height="16"
918
+ viewBox="0 0 24 24"
919
+ fill="none"
920
+ stroke="#263042"
921
+ stroke-width="2"
922
+ stroke-linecap="round"
923
+ stroke-linejoin="round">
924
+ <line x1="12" y1="2" x2="12" y2="6"></line>
925
+ <line x1="12" y1="18" x2="12" y2="22"></line>
926
+ <line x1="4.93" y1="4.93" x2="7.76" y2="7.76"></line>
927
+ <line x1="16.24" y1="16.24" x2="19.07" y2="19.07"></line>
928
+ <line x1="2" y1="12" x2="6" y2="12"></line>
929
+ <line x1="18" y1="12" x2="22" y2="12"></line>
930
+ <line x1="4.93" y1="19.07" x2="7.76" y2="16.24"></line>
931
+ <line x1="16.24" y1="7.76" x2="19.07" y2="4.93"></line>
932
+ </svg>`,
933
+ user: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
934
+ <!-- Head circle -->
935
+ <circle cx="12" cy="8" r="4" fill="currentColor"/>
936
+
937
+ <!-- Body shape -->
938
+ <path d="M20 19v1a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-1c0-3.87 3.13-7 7-7h2c3.87 0 7 3.13 7 7z" fill="currentColor"/>
939
+ </svg>`,
940
+ ai: `<svg
941
+ xmlns="http://www.w3.org/2000/svg"
942
+ viewBox="0 0 100 100"
943
+ width="100"
944
+ height="100"
945
+ fill="none"
946
+ stroke="black"
947
+ stroke-width="2"
948
+ >
949
+ <!-- Brain outline -->
950
+ <path
951
+ d="M50 10
952
+ C60 10, 70 20, 70 30
953
+ S60 50, 50 50
954
+ S30 40, 30 30
955
+ S40 10, 50 10Z"
956
+ fill="#B3E5FC"
957
+ />
958
+
959
+ <!-- Circuit lines -->
960
+ <line x1="50" y1="50" x2="50" y2="70" stroke="#0288D1" stroke-width="2" />
961
+ <line x1="50" y1="70" x2="40" y2="80" stroke="#0288D1" stroke-width="2" />
962
+ <line x1="50" y1="70" x2="60" y2="80" stroke="#0288D1" stroke-width="2" />
963
+
964
+ <!-- Nodes -->
965
+ <circle cx="50" cy="70" r="2" fill="#0288D1" />
966
+ <circle cx="40" cy="80" r="3" fill="#0288D1" />
967
+ <circle cx="60" cy="80" r="3" fill="#0288D1" />
968
+ </svg>
969
+ `,
970
+ };
971
+
972
+ class IconsComponent {
973
+ constructor(sanitizer) {
974
+ this.sanitizer = sanitizer;
975
+ this.size = 14;
976
+ this.color = 'currentColor';
977
+ }
978
+ ngOnChanges(changes) {
979
+ if (changes['name']) {
980
+ const svg = ICONS[this.name] || '';
981
+ this.sanitizedIcon = this.sanitizer.bypassSecurityTrustHtml(svg);
982
+ }
983
+ }
984
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: IconsComponent, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
985
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.1", type: IconsComponent, isStandalone: true, selector: "dc-icon", inputs: { name: "name", size: "size", color: "color" }, usesOnChanges: true, ngImport: i0, template: `
986
+ <span
987
+ [innerHTML]="sanitizedIcon"
988
+ [style.display]="'inline-flex'"
989
+ [style.alignItems]="'center'"
990
+ [style.justifyContent]="'center'"
991
+ [style.width.px]="size"
992
+ [style.height.px]="size"
993
+ [style.color]="color"></span>
994
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;line-height:0}span{line-height:0}:host ::ng-deep svg{width:100%;height:100%}\n"] }); }
995
+ }
996
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: IconsComponent, decorators: [{
997
+ type: Component,
998
+ args: [{ selector: 'dc-icon', template: `
999
+ <span
1000
+ [innerHTML]="sanitizedIcon"
1001
+ [style.display]="'inline-flex'"
1002
+ [style.alignItems]="'center'"
1003
+ [style.justifyContent]="'center'"
1004
+ [style.width.px]="size"
1005
+ [style.height.px]="size"
1006
+ [style.color]="color"></span>
1007
+ `, standalone: true, styles: [":host{display:inline-flex;align-items:center;line-height:0}span{line-height:0}:host ::ng-deep svg{width:100%;height:100%}\n"] }]
1008
+ }], ctorParameters: () => [{ type: i1.DomSanitizer }], propDecorators: { name: [{
1009
+ type: Input
1010
+ }], size: [{
1011
+ type: Input
1012
+ }], color: [{
1013
+ type: Input
1014
+ }] } });
1015
+
1016
+ class AudioTextSyncService {
1017
+ constructor() {
1018
+ // Signal-based API
1019
+ this.highlightedWordsSignal = signal([]);
1020
+ // Observable-based API
1021
+ this.highlightedWords$ = new BehaviorSubject([]);
1022
+ this.cleanup$ = new Subject();
1023
+ this.activeAudio = null;
1024
+ this.destroyRef = inject(DestroyRef);
1025
+ // Ensure cleanup when service is destroyed
1026
+ this.destroyRef.onDestroy(() => {
1027
+ this.stopSync();
1028
+ });
1029
+ }
1030
+ /**
1031
+ * Synchronizes audio playback with text transcription
1032
+ * @param audioElement The audio element to sync with
1033
+ * @param transcriptionTimestamps Array of word timestamps
1034
+ */
1035
+ syncAudioWithText(audioElement, transcriptionTimestamps) {
1036
+ // Stop any existing sync
1037
+ this.stopSync();
1038
+ this.activeAudio = audioElement;
1039
+ // Initialize the highlighted words state
1040
+ const initialWords = transcriptionTimestamps.map((word, index) => ({
1041
+ word: word.word,
1042
+ index,
1043
+ isHighlighted: false,
1044
+ }));
1045
+ this.highlightedWordsSignal.set(initialWords);
1046
+ this.highlightedWords$.next(initialWords);
1047
+ // Listen to timeupdate events
1048
+ fromEvent(audioElement, 'timeupdate')
1049
+ .pipe(takeUntilDestroyed(this.destroyRef), takeUntil(this.cleanup$), map(() => audioElement.currentTime))
1050
+ .subscribe((currentTime) => {
1051
+ const updatedWords = transcriptionTimestamps.map((word, index) => {
1052
+ const isHighlighted = currentTime >= word.start - 0.15 && currentTime < word.end + 0.15;
1053
+ return {
1054
+ word: word.word,
1055
+ index,
1056
+ isHighlighted,
1057
+ };
1058
+ });
1059
+ // Update both signal and observable
1060
+ this.highlightedWordsSignal.set(updatedWords);
1061
+ this.highlightedWords$.next(updatedWords);
1062
+ });
1063
+ // Listen to ended event for cleanup
1064
+ fromEvent(audioElement, 'ended')
1065
+ .pipe(takeUntilDestroyed(this.destroyRef), takeUntil(this.cleanup$))
1066
+ .subscribe(() => {
1067
+ // Reset highlighting when audio ends
1068
+ const resetWords = initialWords.map((word) => ({
1069
+ ...word,
1070
+ isHighlighted: false,
1071
+ }));
1072
+ this.highlightedWordsSignal.set(resetWords);
1073
+ this.highlightedWords$.next(resetWords);
1074
+ });
1075
+ }
1076
+ /**
1077
+ * Stops the current sync and cleans up resources
1078
+ */
1079
+ stopSync() {
1080
+ if (this.activeAudio) {
1081
+ this.cleanup$.next();
1082
+ this.activeAudio = null;
1083
+ // Reset state
1084
+ this.highlightedWordsSignal.set([]);
1085
+ this.highlightedWords$.next([]);
1086
+ }
1087
+ }
1088
+ /**
1089
+ * Returns the current highlighted words as a signal
1090
+ */
1091
+ getHighlightedWordsSignal() {
1092
+ return this.highlightedWordsSignal;
1093
+ }
1094
+ /**
1095
+ * Returns the current highlighted words as an observable
1096
+ */
1097
+ getHighlightedWords$() {
1098
+ return this.highlightedWords$.asObservable();
1099
+ }
1100
+ /**
1101
+ * Checks if a word at a specific index is currently highlighted
1102
+ * @param index The index of the word to check
1103
+ */
1104
+ isWordHighlighted(index) {
1105
+ return this.highlightedWordsSignal().some((word) => word.index === index && word.isHighlighted);
1106
+ }
1107
+ /**
1108
+ * Returns an observable that emits true when a word at a specific index is highlighted
1109
+ * @param index The index of the word to observe
1110
+ */
1111
+ isWordHighlighted$(index) {
1112
+ return this.highlightedWords$.pipe(map((words) => words.some((word) => word.index === index && word.isHighlighted)));
1113
+ }
1114
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: AudioTextSyncService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1115
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: AudioTextSyncService, providedIn: 'root' }); }
976
1116
  }
977
- function removeAllEmojis(text) {
978
- // More comprehensive regex that catches:
979
- // 1. Standard emojis
980
- // 2. Emoji variations and modifiers
981
- // 3. Symbol characters
982
- // 4. Pictographs
983
- // 5. Emoticons
984
- // 6. Regional indicators
985
- // 7. Flags
986
- return text.replace(/[\p{Emoji_Presentation}\p{Extended_Pictographic}\u{1F3FB}-\u{1F3FF}\u{E0020}-\u{E007F}\u{FE00}-\u{FE0F}\u{1F900}-\u{1F9FF}\u{1F1E6}-\u{1F1FF}]/gu, '');
1117
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: AudioTextSyncService, decorators: [{
1118
+ type: Injectable,
1119
+ args: [{
1120
+ providedIn: 'root',
1121
+ }]
1122
+ }], ctorParameters: () => [] });
1123
+
1124
+ class MessageContentComponent {
1125
+ constructor(cdr, audioTextSyncService) {
1126
+ this.cdr = cdr;
1127
+ this.audioTextSyncService = audioTextSyncService;
1128
+ this.isLoading = false;
1129
+ this.playAudio = new EventEmitter();
1130
+ // Get the highlighted words signal from the service
1131
+ this.highlightedWords = this.audioTextSyncService.getHighlightedWordsSignal();
1132
+ // Setup effect to mark for check when highlighted words change
1133
+ effect(() => {
1134
+ // Just accessing the signal in an effect will re-run the effect when the signal changes
1135
+ this.highlightedWords();
1136
+ // Mark for check to ensure the component updates
1137
+ this.cdr.markForCheck();
1138
+ });
1139
+ }
1140
+ get hasTranscription() {
1141
+ return !!this.message.transcriptionTimestamps;
1142
+ }
1143
+ get messageText() {
1144
+ return this.message.content || this.message.text;
1145
+ }
1146
+ get messageTag() {
1147
+ return this.message.tag || null;
1148
+ }
1149
+ onPlayMessage() {
1150
+ this.playAudio.emit(this.message);
1151
+ }
1152
+ /**
1153
+ * Track function for ngFor to improve performance
1154
+ * @param index The current item's index
1155
+ * @param item The current item
1156
+ */
1157
+ trackByIndex(index, item) {
1158
+ return index;
1159
+ }
1160
+ ngOnInit() {
1161
+ console.log(this.message);
1162
+ }
1163
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: MessageContentComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: AudioTextSyncService }], target: i0.ɵɵFactoryTarget.Component }); }
1164
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: MessageContentComponent, isStandalone: true, selector: "dc-message-content", inputs: { message: "message", isLoading: "isLoading" }, outputs: { playAudio: "playAudio" }, ngImport: i0, template: "<!-- Message with transcription -->\n@if (hasTranscription) {\n<div style=\"display: flex\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: isLoading, message: message }\"></ng-container>\n @for (wordState of highlightedWords(); track trackByIndex($index, wordState)) {\n <span [class.highlight]=\"wordState.isHighlighted\">{{ wordState.word }}&nbsp;</span>\n }\n</div>\n}@else {\n<!-- Message without transcription -->\n\n<div style=\"display: flex\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: isLoading, message: message }\"></ng-container>\n <span style=\"margin-left: 2px\" [ngClass]=\"messageTag\" [innerHtml]=\"message.text || message.content\"></span>\n</div>\n}\n\n<!-- Icon template for play/loading status -->\n<ng-template #iconTemplate let-isLoading=\"isLoading\" let-message=\"message\">\n <i (click)=\"onPlayMessage()\">\n <dc-icon *ngIf=\"isLoading\" class=\"spin-animation\" name=\"loading\"></dc-icon>\n <dc-icon *ngIf=\"!isLoading\" name=\"play\"></dc-icon>\n </i>\n</ng-template>\n", styles: [".highlight{background-color:#ffff004d}i{cursor:pointer;display:inline-flex;align-items:center;margin-right:4px}.spin-animation{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconsComponent, selector: "dc-icon", inputs: ["name", "size", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
987
1165
  }
1166
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: MessageContentComponent, decorators: [{
1167
+ type: Component,
1168
+ args: [{ selector: 'dc-message-content', standalone: true, imports: [CommonModule, IconsComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Message with transcription -->\n@if (hasTranscription) {\n<div style=\"display: flex\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: isLoading, message: message }\"></ng-container>\n @for (wordState of highlightedWords(); track trackByIndex($index, wordState)) {\n <span [class.highlight]=\"wordState.isHighlighted\">{{ wordState.word }}&nbsp;</span>\n }\n</div>\n}@else {\n<!-- Message without transcription -->\n\n<div style=\"display: flex\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: isLoading, message: message }\"></ng-container>\n <span style=\"margin-left: 2px\" [ngClass]=\"messageTag\" [innerHtml]=\"message.text || message.content\"></span>\n</div>\n}\n\n<!-- Icon template for play/loading status -->\n<ng-template #iconTemplate let-isLoading=\"isLoading\" let-message=\"message\">\n <i (click)=\"onPlayMessage()\">\n <dc-icon *ngIf=\"isLoading\" class=\"spin-animation\" name=\"loading\"></dc-icon>\n <dc-icon *ngIf=\"!isLoading\" name=\"play\"></dc-icon>\n </i>\n</ng-template>\n", styles: [".highlight{background-color:#ffff004d}i{cursor:pointer;display:inline-flex;align-items:center;margin-right:4px}.spin-animation{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
1169
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: AudioTextSyncService }], propDecorators: { message: [{
1170
+ type: Input
1171
+ }], isLoading: [{
1172
+ type: Input
1173
+ }], playAudio: [{
1174
+ type: Output
1175
+ }] } });
988
1176
 
989
1177
  function markdownToHTML(markdownText) {
990
1178
  // Convert italics-bold (***text***)
@@ -1045,45 +1233,100 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImpor
1045
1233
  }]
1046
1234
  }] });
1047
1235
 
1236
+ class MultiMessageContentComponent {
1237
+ constructor() {
1238
+ this.isLoading = false;
1239
+ this.playAudio = new EventEmitter();
1240
+ }
1241
+ onPlayMessage(message) {
1242
+ this.playAudio.emit(message);
1243
+ }
1244
+ ngOnInit() {
1245
+ console.log(this.messages);
1246
+ debugger;
1247
+ }
1248
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: MultiMessageContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1249
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: MultiMessageContentComponent, isStandalone: true, selector: "dc-multi-message-content", inputs: { messages: "messages", isLoading: "isLoading" }, outputs: { playAudio: "playAudio" }, ngImport: i0, template: "@for (message of messages; track message) {\n<!-- Message with transcription -->\n@if (!!message.transcriptionTimestamps) {\n<div style=\"display: flex\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: isLoading, message: message }\"></ng-container>\n <span *ngFor=\"let word of message.transcriptionTimestamps\" [class.highlight]=\"word.highlighted\">{{ word.word }}</span>\n</div>\n}@else {\n<!-- Message without transcription -->\n\n<div style=\"display: flex\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: isLoading, message: message }\"></ng-container>\n <span style=\"margin-left: 2px\" [ngClass]=\"message.tag\" [innerHtml]=\"message.text || message.content\"></span>\n</div>\n} }\n\n<!-- Icon template for play/loading status -->\n<ng-template #iconTemplate let-isLoading=\"isLoading\" let-message=\"message\">\n <i (click)=\"onPlayMessage(message)\">\n <dc-icon *ngIf=\"isLoading\" class=\"spin-animation\" name=\"loading\"></dc-icon>\n <dc-icon *ngIf=\"!isLoading\" name=\"play\"></dc-icon>\n </i>\n</ng-template>\n", styles: [".highlight{background-color:#ffff004d}i{cursor:pointer;display:inline-flex;align-items:center;margin-right:4px}.spin-animation{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconsComponent, selector: "dc-icon", inputs: ["name", "size", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1250
+ }
1251
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: MultiMessageContentComponent, decorators: [{
1252
+ type: Component,
1253
+ args: [{ selector: 'dc-multi-message-content', standalone: true, imports: [CommonModule, IconsComponent, SimpleMdToHtmlPipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "@for (message of messages; track message) {\n<!-- Message with transcription -->\n@if (!!message.transcriptionTimestamps) {\n<div style=\"display: flex\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: isLoading, message: message }\"></ng-container>\n <span *ngFor=\"let word of message.transcriptionTimestamps\" [class.highlight]=\"word.highlighted\">{{ word.word }}</span>\n</div>\n}@else {\n<!-- Message without transcription -->\n\n<div style=\"display: flex\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: isLoading, message: message }\"></ng-container>\n <span style=\"margin-left: 2px\" [ngClass]=\"message.tag\" [innerHtml]=\"message.text || message.content\"></span>\n</div>\n} }\n\n<!-- Icon template for play/loading status -->\n<ng-template #iconTemplate let-isLoading=\"isLoading\" let-message=\"message\">\n <i (click)=\"onPlayMessage(message)\">\n <dc-icon *ngIf=\"isLoading\" class=\"spin-animation\" name=\"loading\"></dc-icon>\n <dc-icon *ngIf=\"!isLoading\" name=\"play\"></dc-icon>\n </i>\n</ng-template>\n", styles: [".highlight{background-color:#ffff004d}i{cursor:pointer;display:inline-flex;align-items:center;margin-right:4px}.spin-animation{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
1254
+ }], propDecorators: { messages: [{
1255
+ type: Input
1256
+ }], isLoading: [{
1257
+ type: Input
1258
+ }], playAudio: [{
1259
+ type: Output
1260
+ }] } });
1261
+
1262
+ function matchTranscription(originalText, transcription) {
1263
+ const result = [];
1264
+ const transcriptionMap = new Map();
1265
+ // Create a map of lowercase words to an array of their corresponding objects in transcription
1266
+ for (const obj of transcription) {
1267
+ const lowercaseWord = obj.word.trim().toLowerCase();
1268
+ if (transcriptionMap.has(lowercaseWord)) {
1269
+ transcriptionMap.get(lowercaseWord).push(obj);
1270
+ }
1271
+ else {
1272
+ transcriptionMap.set(lowercaseWord, [obj]);
1273
+ }
1274
+ }
1275
+ // Split the original text into an array of words
1276
+ const words = originalText.split(' ');
1277
+ let currentTime = 0;
1278
+ for (const word of words) {
1279
+ const lowercaseWord = word.toLowerCase();
1280
+ const matchedObjs = transcriptionMap.get(lowercaseWord);
1281
+ if (matchedObjs && matchedObjs.length > 0) {
1282
+ const matchedObj = matchedObjs.shift();
1283
+ result.push({
1284
+ word: word,
1285
+ start: Number(matchedObj.start.toFixed(3)),
1286
+ end: Number(matchedObj.end.toFixed(3)),
1287
+ });
1288
+ currentTime = matchedObj.end;
1289
+ }
1290
+ else {
1291
+ result.push({
1292
+ word: word,
1293
+ start: Number(currentTime.toFixed(3)),
1294
+ end: Number(currentTime.toFixed(3)),
1295
+ });
1296
+ }
1297
+ }
1298
+ return result;
1299
+ }
1300
+ function extractAudioAndTranscription(message, audio) {
1301
+ message.audioUrl = audio.blobUrl;
1302
+ message.transcription = audio.transcription;
1303
+ if (message.transcription) {
1304
+ message.transcriptionTimestamps = matchTranscription(message.text || message.content, message.transcription.words);
1305
+ }
1306
+ }
1307
+
1048
1308
  class ChatMessageComponent {
1049
- constructor(audioService, agentCardService, cdr) {
1309
+ constructor(audioService, agentCardService, audioTextSyncService) {
1050
1310
  this.audioService = audioService;
1051
1311
  this.agentCardService = agentCardService;
1052
- this.cdr = cdr;
1053
- this.isDestroyed = false;
1054
- // TODO: use the default settings when the user is not set
1055
- this.defaultconvUserSettings = {
1056
- realTime: false,
1057
- repeatRecording: false,
1058
- fixGrammar: false,
1059
- superHearing: false,
1060
- voice: '',
1061
- autoTranslate: false,
1062
- highlightWords: true,
1063
- synthVoice: true,
1064
- model: { modelName: null, provider: 'google' },
1065
- speed: null,
1066
- speedRate: null, // temporal
1067
- };
1312
+ this.audioTextSyncService = audioTextSyncService;
1313
+ this.destroyRef = inject(DestroyRef);
1314
+ this.conversationChatSettings = signal(null);
1315
+ this.isLoading = signal(false);
1068
1316
  }
1069
1317
  async ngOnInit() {
1070
- // this.conversationSettings = { ...this.conversationSettings, ...settings };
1071
- this.conversationChatSettings = await this.agentCardService.getConversationUserChatSettings();
1072
- if (this.chatMessage.role == ChatRole.AssistantHelper) {
1318
+ const settings = await this.agentCardService.getConversationUserChatSettings();
1319
+ this.conversationChatSettings.set(settings);
1320
+ if (this.chatMessage.role === ChatRole.AssistantHelper) {
1073
1321
  return;
1074
1322
  }
1075
- if (this.chatMessage.role == ChatRole.User) {
1076
- if (this.conversationChatSettings?.repeatRecording && this.conversationChatSettings?.synthVoice) {
1323
+ const settings$ = this.conversationChatSettings();
1324
+ if (this.chatMessage.role === ChatRole.User) {
1325
+ if (settings$?.repeatRecording && settings$?.synthVoice) {
1077
1326
  this.playMessage(this.chatMessage);
1078
1327
  }
1079
1328
  }
1080
- else {
1081
- if (!this.conversationChatSettings?.synthVoice) {
1082
- return;
1083
- }
1084
- console.log(this.chatMessage.multiMessages);
1085
- this.cdr.markForCheck();
1086
- // this is an assistant message
1329
+ else if (settings$?.synthVoice) {
1087
1330
  if (this.chatMessage.multiMessages) {
1088
1331
  this.generateAndPlayAllAudios(this.chatMessage.multiMessages);
1089
1332
  }
@@ -1092,173 +1335,244 @@ class ChatMessageComponent {
1092
1335
  }
1093
1336
  }
1094
1337
  }
1095
- ngOnDestroy() {
1096
- this.isDestroyed = true;
1097
- }
1098
- async generateAndPlayAudio(message, overwritetext = null) {
1099
- const text = overwritetext || message.content;
1100
- const ttsObject = this.getTTSRequest({ ...this.chatMessage, text });
1101
- if (message.ssml) {
1102
- ttsObject.ssml = message.ssml;
1103
- }
1104
- const speechAudio = await this.agentCardService.getTextAudioFile(ttsObject);
1105
- this.extractAudioAndTranscription(message, speechAudio);
1106
- this.playMessage(message);
1107
- // TODO: cuando no sirve el server utilizar esta voz del navegador
1108
- // else if (this.selectedAudioType === 'default') {
1109
- // await this.speechService.speach(message.content, { speed: 1, tone: 0.9 });
1110
- // }
1111
- }
1112
- extractAudioAndTranscription(message, audio) {
1113
- message.audioUrl = audio.blobUrl;
1114
- message.transcription = audio.transcription;
1115
- if (message.transcription) {
1116
- message.transcriptionTimestamps = this.matchTranscription(message.text || message.content, message.transcription.words);
1338
+ async generateAndPlayAudio(message, overwriteText = null) {
1339
+ this.isLoading.set(true);
1340
+ try {
1341
+ const text = overwriteText || message.content;
1342
+ const ttsObject = this.buildObjectTTSRequest({ ...this.chatMessage, text });
1343
+ if (message.ssml) {
1344
+ ttsObject.ssml = message.ssml;
1345
+ }
1346
+ const speechAudio = await this.agentCardService.getTextAudioFile(ttsObject);
1347
+ extractAudioAndTranscription(message, speechAudio);
1348
+ this.playMessage(message);
1349
+ }
1350
+ finally {
1351
+ this.isLoading.set(false);
1117
1352
  }
1118
1353
  }
1119
1354
  playMessage(message) {
1120
- console.log('playMessage', message);
1121
- if (message.audioUrl) {
1122
- const audioHtml = this.audioService.playAudio(message.audioUrl);
1123
- message['audioHtml'] = audioHtml;
1124
- this.subscribeToTimeUpdate(audioHtml, message.transcriptionTimestamps);
1125
- return audioHtml;
1355
+ if (!message.audioUrl) {
1356
+ return null;
1126
1357
  }
1127
- else {
1128
- // this.speechService.speach(message.content);
1358
+ const audioElement = this.audioService.playAudio(message.audioUrl);
1359
+ message['audioHtml'] = audioElement;
1360
+ if (message.transcriptionTimestamps) {
1361
+ // Use the audio-text sync service instead of direct manipulation
1362
+ this.audioTextSyncService.syncAudioWithText(audioElement, message.transcriptionTimestamps);
1129
1363
  }
1130
- return null;
1364
+ return audioElement;
1131
1365
  }
1132
- subscribeToTimeUpdate(audioHtml, transcriptionTimestamps = null) {
1133
- console.log('subscribing to time updates', audioHtml, transcriptionTimestamps);
1134
- if (transcriptionTimestamps) {
1135
- audioHtml.ontimeupdate = (time) => {
1136
- transcriptionTimestamps.forEach((word) => {
1137
- word.highlighted = audioHtml.currentTime >= word.start - 0.15 && audioHtml.currentTime < word.end + 0.15;
1138
- console.log('highliting word', word, 'enable detecting');
1139
- this.cdr.detectChanges();
1140
- });
1141
- };
1142
- }
1143
- audioHtml.onended = () => {
1144
- audioHtml.ontimeupdate = null;
1145
- audioHtml = null;
1146
- // this.chatBroker.currentMessagePlayed$.next(true);
1147
- };
1366
+ // This method is no longer needed as we're using the AudioTextSyncService
1367
+ // It's kept here as a reference but can be removed
1368
+ /*
1369
+ private setupTranscriptionHighlighting(audioElement: HTMLAudioElement, transcriptionTimestamps: WordTimestamps[]): void {
1370
+ // This functionality has been moved to AudioTextSyncService
1148
1371
  }
1372
+ */
1149
1373
  generateAndPlayAllAudios(multiMessages) {
1374
+ if (!multiMessages.length)
1375
+ return;
1150
1376
  let currentIndex = 0;
1151
1377
  const playAudioSequentially = async () => {
1152
- if (this.isDestroyed)
1153
- return;
1154
1378
  if (currentIndex >= multiMessages.length) {
1155
- console.log('All audio files have been played.');
1156
1379
  return;
1157
1380
  }
1158
- const msn = multiMessages[currentIndex];
1159
- // Audio is processed in ahead at last, first time will wait for audio, the rest is only wait,
1160
- if (!msn.audioUrl) {
1161
- if (msn.audioPromise) {
1162
- await msn.audioPromise;
1381
+ const currentMessage = multiMessages[currentIndex];
1382
+ currentMessage.isLoading = true;
1383
+ try {
1384
+ debugger;
1385
+ // Process current message audio if needed
1386
+ if (!currentMessage.audioUrl) {
1387
+ if (currentMessage.audioPromise) {
1388
+ await currentMessage.audioPromise;
1389
+ }
1390
+ else {
1391
+ const request = this.buildObjectTTSRequest(currentMessage);
1392
+ currentMessage.audioPromise = this.agentCardService.getTextAudioFile(request);
1393
+ const audio = await currentMessage.audioPromise;
1394
+ extractAudioAndTranscription(currentMessage, audio);
1395
+ }
1396
+ }
1397
+ // Play the current message
1398
+ const audioElement = this.playMessage(currentMessage);
1399
+ if (audioElement) {
1400
+ audioElement.addEventListener('ended', () => {
1401
+ currentIndex++;
1402
+ playAudioSequentially();
1403
+ });
1163
1404
  }
1164
1405
  else {
1165
- const request = this.getTTSRequest(msn);
1166
- msn.isLoading = true;
1167
- this.cdr.detectChanges();
1168
- msn.audioPromise = this.agentCardService.getTextAudioFile(request);
1169
- const audio = await msn.audioPromise;
1170
- this.extractAudioAndTranscription(msn, audio);
1171
- msn.isLoading = false;
1172
- this.cdr.detectChanges();
1406
+ // If playback failed, move to next message
1407
+ currentIndex++;
1408
+ playAudioSequentially();
1173
1409
  }
1410
+ // Preload next message audio
1411
+ this.preloadNextMessageAudio(multiMessages, currentIndex);
1174
1412
  }
1175
- const audioHtml = this.playMessage(msn);
1176
- audioHtml.onended = () => {
1177
- currentIndex++;
1178
- playAudioSequentially();
1179
- };
1180
- // Load the next audio file in advance
1181
- if (currentIndex + 1 < multiMessages.length) {
1182
- const nextMessage = multiMessages[currentIndex + 1];
1183
- const request = this.getTTSRequest(nextMessage);
1413
+ finally {
1414
+ currentMessage.isLoading = false;
1415
+ }
1416
+ };
1417
+ // Start the sequential playback
1418
+ playAudioSequentially();
1419
+ }
1420
+ preloadNextMessageAudio(messages, currentIndex) {
1421
+ if (currentIndex + 1 < messages.length) {
1422
+ const nextMessage = messages[currentIndex + 1];
1423
+ if (!nextMessage.audioUrl && !nextMessage.audioPromise) {
1424
+ const request = this.buildObjectTTSRequest(nextMessage);
1184
1425
  nextMessage.isLoading = true;
1185
1426
  nextMessage.audioPromise = this.agentCardService.getTextAudioFile(request);
1186
1427
  nextMessage.audioPromise.then((audio) => {
1187
- this.extractAudioAndTranscription(nextMessage, audio);
1428
+ extractAudioAndTranscription(nextMessage, audio);
1188
1429
  nextMessage.isLoading = false;
1189
1430
  });
1190
1431
  }
1191
- };
1192
- playAudioSequentially();
1432
+ }
1193
1433
  }
1194
- getTTSRequest(nextMessage) {
1195
- // const settingsConv = this.userService.getUserSnapshot().settings.conversation;
1196
- const generateTranscription = this.conversationChatSettings?.highlightWords ?? false;
1197
- const speedRate = this.conversationChatSettings?.speedRate || 0;
1198
- const speed = typeof this.conversationChatSettings?.speed === 'string' ? this.conversationChatSettings.speed : AudioSpeed.Regular;
1199
- const text = removeEmojis(nextMessage.text);
1200
- const data = {
1201
- text: text,
1202
- voice: nextMessage.voice || this.chatMessage.voice,
1434
+ buildObjectTTSRequest(message) {
1435
+ const settings = this.conversationChatSettings();
1436
+ const generateTranscription = settings?.highlightWords ?? false;
1437
+ const speedRate = settings?.speedRate || 0;
1438
+ const speed = typeof settings?.speed === 'string' ? settings.speed : AudioSpeed.Regular;
1439
+ const text = removeEmojis(message.text || message.content);
1440
+ return {
1441
+ text,
1442
+ voice: message.voice || this.chatMessage.voice,
1203
1443
  generateTranscription,
1204
1444
  speedRate,
1205
1445
  speed,
1206
1446
  };
1207
- return data;
1208
- }
1209
- matchTranscription(originalText, transcription) {
1210
- const result = [];
1211
- const transcriptionMap = new Map();
1212
- // Create a map of lowercase words to an array of their corresponding objects in transcription
1213
- for (const obj of transcription) {
1214
- const lowercaseWord = obj.word.trim().toLowerCase();
1215
- if (transcriptionMap.has(lowercaseWord)) {
1216
- transcriptionMap.get(lowercaseWord).push(obj);
1217
- }
1218
- else {
1219
- transcriptionMap.set(lowercaseWord, [obj]);
1220
- }
1221
- }
1222
- // Split the original text into an array of words
1223
- const words = originalText.split(' ');
1224
- let currentTime = 0;
1225
- for (const word of words) {
1226
- const lowercaseWord = word.toLowerCase();
1227
- const matchedObjs = transcriptionMap.get(lowercaseWord);
1228
- if (matchedObjs && matchedObjs.length > 0) {
1229
- const matchedObj = matchedObjs.shift();
1230
- result.push({
1231
- word: word,
1232
- start: matchedObj.start,
1233
- end: matchedObj.end,
1234
- });
1235
- currentTime = matchedObj.end;
1236
- }
1237
- else {
1238
- result.push({
1239
- word: word,
1240
- start: currentTime,
1241
- end: currentTime,
1242
- });
1243
- }
1244
- }
1245
- return result;
1246
1447
  }
1247
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: ChatMessageComponent, deps: [{ token: AudioService }, { token: CONVERSATION_AI_TOKEN }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
1248
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: ChatMessageComponent, isStandalone: true, selector: "dc-chat-message", inputs: { chatMessage: "chatMessage", chatUserSettings: "chatUserSettings" }, ngImport: i0, template: "@if (chatMessage?.multiMessages) {\n<h5>Multi message</h5>\n<span style=\"line-height: 1.5\" *ngFor=\"let message of chatMessage.multiMessages\">\n <div [ngClass]=\"message.tag\" *ngIf=\"message.transcriptionTimestamps\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: message.isLoading, message: message }\"></ng-container>\n <span *ngFor=\"let word of message.transcriptionTimestamps\" [class.highlight]=\"word.highlighted\">\n {{ word.word }}\n </span>\n </div>\n\n <div *ngIf=\"!message.transcriptionTimestamps\">\n <div (click)=\"playMessage(message)\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: message.isLoading, message: message }\"></ng-container>\n <span style=\"margin-left: 2px\" [ngClass]=\"message.tag\" [innerHtml]=\"message.text\"> </span>\n </div>\n </div>\n</span>\n}@else {\n\n<span>\n @if (chatMessage.transcriptionTimestamps) {\n <div>\n <span *ngFor=\"let word of chatMessage.transcriptionTimestamps\" [class.highlight]=\"word.highlighted\">\n {{ word.word }}\n </span>\n </div>\n } @else {\n <div>\n <span (click)=\"playMessage(chatMessage)\" [innerHTML]=\"chatMessage.content | simpleMdToHtml\"></span>\n </div>\n }\n</span>\n}\n\n<div class=\"small\" *ngIf=\"chatMessage.translation\">\n <hr class=\"divider\" />\n {{ chatMessage.translation }}\n</div>\n\n<ng-template #iconTemplate let-isLoading=\"isLoading\" let-message=\"message\">\n <i *ngIf=\"isLoading\" (click)=\"playMessage(message)\">\n <dc-icon class=\"spin-animation\" name=\"loading\"></dc-icon>\n </i>\n\n <i *ngIf=\"!isLoading\" (click)=\"playMessage(message)\">\n <dc-icon name=\"play\"></dc-icon>\n </i>\n</ng-template>\n", styles: [":host{display:block}.highlight{background-color:#fff8a7;color:#011630;text-decoration:underline #59a4ff solid 3px}::ng-deep .em{color:#0d5878;font-style:italic}::ng-deep .strong{font-weight:700;color:#515151}::ng-deep .em_strong{font-weight:700;font-style:italic;color:#0d5878}.small{margin-top:8x;font-size:small;line-height:1.6;color:#393744;font-style:italic}.divider{margin:.5rem 40px;border-top:1px solid #ffa77e}.spin-animation{display:inline-block;animation:spin 2s linear infinite;transform-origin:center center;transform-box:fill-box;vertical-align:middle}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconsComponent, selector: "dc-icon", inputs: ["name", "size", "color"] }, { kind: "pipe", type: SimpleMdToHtmlPipe, name: "simpleMdToHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1448
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: ChatMessageComponent, deps: [{ token: AudioService }, { token: CONVERSATION_AI_TOKEN }, { token: AudioTextSyncService }], target: i0.ɵɵFactoryTarget.Component }); }
1449
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: ChatMessageComponent, isStandalone: true, selector: "dc-chat-message", inputs: { chatMessage: "chatMessage", chatUserSettings: "chatUserSettings" }, ngImport: i0, template: "<!-- Multi-message display -->\n<span class=\"message-container\">\n @if (chatMessage?.multiMessages) {\n <!-- Single message display -->\n <dc-multi-message-content [messages]=\"chatMessage.multiMessages\" (playAudio)=\"playMessage($event)\"> </dc-multi-message-content>\n } @else {\n <dc-message-content [message]=\"chatMessage\" [isLoading]=\"isLoading()\" (playAudio)=\"playMessage($event)\"> </dc-message-content>\n }\n</span>\n\n@if (chatMessage.translation) {\n<!-- Translation display if available -->\n\n<div class=\"translation\">\n <hr class=\"divider\" />\n {{ chatMessage.translation }}\n</div>\n}\n", styles: [":host{display:block}.message-container{display:block;line-height:1.5}::ng-deep .em{color:#0d5878;font-style:italic}::ng-deep .strong{font-weight:700;color:#515151}::ng-deep .em_strong{font-weight:700;font-style:italic;color:#0d5878}.translation{margin-top:8px;font-size:small;line-height:1.6;color:#393744;font-style:italic}.divider{margin:.5rem 40px;border-top:1px solid #ffa77e}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: MessageContentComponent, selector: "dc-message-content", inputs: ["message", "isLoading"], outputs: ["playAudio"] }, { kind: "component", type: MultiMessageContentComponent, selector: "dc-multi-message-content", inputs: ["messages", "isLoading"], outputs: ["playAudio"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1249
1450
  }
1250
1451
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: ChatMessageComponent, decorators: [{
1251
1452
  type: Component,
1252
- args: [{ selector: 'dc-chat-message', standalone: true, imports: [CommonModule, IconsComponent, SimpleMdToHtmlPipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (chatMessage?.multiMessages) {\n<h5>Multi message</h5>\n<span style=\"line-height: 1.5\" *ngFor=\"let message of chatMessage.multiMessages\">\n <div [ngClass]=\"message.tag\" *ngIf=\"message.transcriptionTimestamps\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: message.isLoading, message: message }\"></ng-container>\n <span *ngFor=\"let word of message.transcriptionTimestamps\" [class.highlight]=\"word.highlighted\">\n {{ word.word }}\n </span>\n </div>\n\n <div *ngIf=\"!message.transcriptionTimestamps\">\n <div (click)=\"playMessage(message)\">\n <ng-container *ngTemplateOutlet=\"iconTemplate; context: { isLoading: message.isLoading, message: message }\"></ng-container>\n <span style=\"margin-left: 2px\" [ngClass]=\"message.tag\" [innerHtml]=\"message.text\"> </span>\n </div>\n </div>\n</span>\n}@else {\n\n<span>\n @if (chatMessage.transcriptionTimestamps) {\n <div>\n <span *ngFor=\"let word of chatMessage.transcriptionTimestamps\" [class.highlight]=\"word.highlighted\">\n {{ word.word }}\n </span>\n </div>\n } @else {\n <div>\n <span (click)=\"playMessage(chatMessage)\" [innerHTML]=\"chatMessage.content | simpleMdToHtml\"></span>\n </div>\n }\n</span>\n}\n\n<div class=\"small\" *ngIf=\"chatMessage.translation\">\n <hr class=\"divider\" />\n {{ chatMessage.translation }}\n</div>\n\n<ng-template #iconTemplate let-isLoading=\"isLoading\" let-message=\"message\">\n <i *ngIf=\"isLoading\" (click)=\"playMessage(message)\">\n <dc-icon class=\"spin-animation\" name=\"loading\"></dc-icon>\n </i>\n\n <i *ngIf=\"!isLoading\" (click)=\"playMessage(message)\">\n <dc-icon name=\"play\"></dc-icon>\n </i>\n</ng-template>\n", styles: [":host{display:block}.highlight{background-color:#fff8a7;color:#011630;text-decoration:underline #59a4ff solid 3px}::ng-deep .em{color:#0d5878;font-style:italic}::ng-deep .strong{font-weight:700;color:#515151}::ng-deep .em_strong{font-weight:700;font-style:italic;color:#0d5878}.small{margin-top:8x;font-size:small;line-height:1.6;color:#393744;font-style:italic}.divider{margin:.5rem 40px;border-top:1px solid #ffa77e}.spin-animation{display:inline-block;animation:spin 2s linear infinite;transform-origin:center center;transform-box:fill-box;vertical-align:middle}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
1453
+ args: [{ selector: 'dc-chat-message', standalone: true, imports: [CommonModule, MessageContentComponent, MultiMessageContentComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Multi-message display -->\n<span class=\"message-container\">\n @if (chatMessage?.multiMessages) {\n <!-- Single message display -->\n <dc-multi-message-content [messages]=\"chatMessage.multiMessages\" (playAudio)=\"playMessage($event)\"> </dc-multi-message-content>\n } @else {\n <dc-message-content [message]=\"chatMessage\" [isLoading]=\"isLoading()\" (playAudio)=\"playMessage($event)\"> </dc-message-content>\n }\n</span>\n\n@if (chatMessage.translation) {\n<!-- Translation display if available -->\n\n<div class=\"translation\">\n <hr class=\"divider\" />\n {{ chatMessage.translation }}\n</div>\n}\n", styles: [":host{display:block}.message-container{display:block;line-height:1.5}::ng-deep .em{color:#0d5878;font-style:italic}::ng-deep .strong{font-weight:700;color:#515151}::ng-deep .em_strong{font-weight:700;font-style:italic;color:#0d5878}.translation{margin-top:8px;font-size:small;line-height:1.6;color:#393744;font-style:italic}.divider{margin:.5rem 40px;border-top:1px solid #ffa77e}\n"] }]
1253
1454
  }], ctorParameters: () => [{ type: AudioService }, { type: AgentCardsAbstractService, decorators: [{
1254
1455
  type: Inject,
1255
1456
  args: [CONVERSATION_AI_TOKEN]
1256
- }] }, { type: i0.ChangeDetectorRef }], propDecorators: { chatMessage: [{
1457
+ }] }, { type: AudioTextSyncService }], propDecorators: { chatMessage: [{
1257
1458
  type: Input
1258
1459
  }], chatUserSettings: [{
1259
1460
  type: Input
1260
1461
  }] } });
1261
1462
 
1463
+ class ChatHeaderComponent {
1464
+ constructor(agentCardService) {
1465
+ this.agentCardService = agentCardService;
1466
+ this.isAdmin = false;
1467
+ this.alternativeConversation = [];
1468
+ this.restartConversationEvent = new EventEmitter();
1469
+ this.showInfoEvent = new EventEmitter();
1470
+ this.settingsClickEvent = new EventEmitter();
1471
+ }
1472
+ restartConversation(conversation = null) {
1473
+ this.restartConversationEvent.emit(conversation);
1474
+ }
1475
+ showInfo() {
1476
+ this.showInfoEvent.emit();
1477
+ }
1478
+ settingsClick() {
1479
+ this.settingsClickEvent.emit();
1480
+ }
1481
+ async changeConversationCard() {
1482
+ const response = prompt('¿Qué conversación quieres usar? Escribe el titulo ejemplo: word_reflection_level_1_base_es');
1483
+ if (response) {
1484
+ const filters = {
1485
+ filters: {
1486
+ title: { $regex: response },
1487
+ },
1488
+ };
1489
+ console.log('filters', filters);
1490
+ const conversationCards = await this.agentCardService.filterConversationCards(filters);
1491
+ console.log('conversationCards', conversationCards);
1492
+ this.alternativeConversation = conversationCards.rows;
1493
+ }
1494
+ }
1495
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: ChatHeaderComponent, deps: [{ token: CONVERSATION_AI_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
1496
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: ChatHeaderComponent, isStandalone: true, selector: "dc-chat-header", inputs: { isAdmin: "isAdmin", alternativeConversation: "alternativeConversation" }, outputs: { restartConversationEvent: "restartConversationEvent", showInfoEvent: "showInfoEvent", settingsClickEvent: "settingsClickEvent" }, ngImport: i0, template: "<div class=\"chat-header\">\n <span class=\"pointer\" (click)=\"restartConversation()\">Reiniciar conversaci\u00F3n</span>\n\n @for (conversation of alternativeConversation; track conversation._id) {\n <span class=\"pointer\" (click)=\"restartConversation(conversation)\"> {{ conversation.title }} </span>\n }\n\n <div class=\"header-controls\">\n @if (isAdmin){\n <div class=\"admin-controls\">\n <span class=\"pointer\" (click)=\"changeConversationCard()\"> \uD83D\uDD04 </span>\n <span class=\"pointer\" (click)=\"showInfo()\"> \u26A1\uFE0F </span>\n </div>\n }\n\n <div>\n <span class=\"pointer\" (click)=\"settingsClick()\"> \u2699\uFE0F </span>\n </div>\n </div>\n</div>\n", styles: [".chat-header{display:flex;justify-content:space-between;align-items:center;width:100%}.pointer{cursor:pointer}.header-controls{font-size:large;display:flex;justify-content:space-between;gap:10px}.admin-controls{background-color:bisque;padding:2px 5px;border-radius:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
1497
+ }
1498
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: ChatHeaderComponent, decorators: [{
1499
+ type: Component,
1500
+ args: [{ selector: 'dc-chat-header', standalone: true, imports: [CommonModule], template: "<div class=\"chat-header\">\n <span class=\"pointer\" (click)=\"restartConversation()\">Reiniciar conversaci\u00F3n</span>\n\n @for (conversation of alternativeConversation; track conversation._id) {\n <span class=\"pointer\" (click)=\"restartConversation(conversation)\"> {{ conversation.title }} </span>\n }\n\n <div class=\"header-controls\">\n @if (isAdmin){\n <div class=\"admin-controls\">\n <span class=\"pointer\" (click)=\"changeConversationCard()\"> \uD83D\uDD04 </span>\n <span class=\"pointer\" (click)=\"showInfo()\"> \u26A1\uFE0F </span>\n </div>\n }\n\n <div>\n <span class=\"pointer\" (click)=\"settingsClick()\"> \u2699\uFE0F </span>\n </div>\n </div>\n</div>\n", styles: [".chat-header{display:flex;justify-content:space-between;align-items:center;width:100%}.pointer{cursor:pointer}.header-controls{font-size:large;display:flex;justify-content:space-between;gap:10px}.admin-controls{background-color:bisque;padding:2px 5px;border-radius:4px}\n"] }]
1501
+ }], ctorParameters: () => [{ type: AgentCardsAbstractService, decorators: [{
1502
+ type: Inject,
1503
+ args: [CONVERSATION_AI_TOKEN]
1504
+ }] }], propDecorators: { isAdmin: [{
1505
+ type: Input
1506
+ }], alternativeConversation: [{
1507
+ type: Input
1508
+ }], restartConversationEvent: [{
1509
+ type: Output
1510
+ }], showInfoEvent: [{
1511
+ type: Output
1512
+ }], settingsClickEvent: [{
1513
+ type: Output
1514
+ }] } });
1515
+
1516
+ class ChatFooterComponent {
1517
+ constructor() {
1518
+ this.isAIThinking = false;
1519
+ this.score = 0;
1520
+ this.micSettings = { useWhisper: true, lang: 'en' };
1521
+ this.sendMessage = new EventEmitter();
1522
+ this.textInputChanged = new EventEmitter();
1523
+ this.micFinishedEvent = new EventEmitter();
1524
+ this.chatInputControl = new FormControl();
1525
+ }
1526
+ /**
1527
+ * Sets the input text in the textarea
1528
+ * @param text The text to set
1529
+ */
1530
+ setInputText(text) {
1531
+ this.chatInputControl.setValue(text);
1532
+ this.textInputChanged.emit(text);
1533
+ }
1534
+ /**
1535
+ * Handles the mic finished event
1536
+ * @param eventBlob The blob event from the mic component
1537
+ */
1538
+ micFinished(eventBlob) {
1539
+ this.micFinishedEvent.emit(eventBlob);
1540
+ }
1541
+ /**
1542
+ * Sends the user message
1543
+ */
1544
+ sendUserMessage() {
1545
+ if (this.isAIThinking || !this.chatInputControl.value) {
1546
+ return;
1547
+ }
1548
+ const text = this.chatInputControl.value;
1549
+ const message = {
1550
+ content: text,
1551
+ role: ChatRole.User,
1552
+ };
1553
+ this.sendMessage.emit(message);
1554
+ this.chatInputControl.setValue('');
1555
+ }
1556
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: ChatFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1557
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.1", type: ChatFooterComponent, isStandalone: true, selector: "dc-chat-footer", inputs: { isAIThinking: "isAIThinking", score: "score", micSettings: "micSettings" }, outputs: { sendMessage: "sendMessage", textInputChanged: "textInputChanged", micFinishedEvent: "micFinishedEvent" }, ngImport: i0, template: "<div class=\"progress-input\">\n <div class=\"input-container\">\n <dc-mic\n style=\"display: flex; align-items: center\"\n (onInterpretedText)=\"setInputText($event)\"\n (onFinished)=\"micFinished($event)\"\n [micSettings]=\"micSettings\"></dc-mic>\n\n <textarea pTextarea [formControl]=\"chatInputControl\" (keyup.enter)=\"sendUserMessage()\" rows=\"1\"></textarea>\n\n <p-button (click)=\"sendUserMessage()\" [disabled]=\"isAIThinking || !chatInputControl.value\" label=\"Enviar\" [rounded]=\"true\" />\n </div>\n\n <div>\n <p-progressbar showValue=\"false\" [value]=\"score\" [style]=\"{ height: '6px' }\" />\n </div>\n</div>\n", styles: [".progress-input{padding:10px;background-color:#f5f5f545;border-top:1px solid #b1a8a8}.progress-input .input-container{display:flex;align-items:center;margin-bottom:5px}.progress-input .input-container textarea{flex:1;resize:none;margin:0 10px}.progress-input .input-container .send-button{background-color:#007bff;color:#fff;border:none;border-radius:4px;padding:8px 15px;cursor:pointer}.progress-input .input-container .send-button:disabled{background-color:#ccc;cursor:not-allowed}.progress-input .input-container .send-button:hover:not(:disabled){background-color:#0069d9}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: ProgressBarModule }, { kind: "component", type: i2.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "style", "unit", "mode", "color"] }, { kind: "component", type: DCMicComponent, selector: "dc-mic", inputs: ["isDone", "useWhisper", "targetOrBase", "micSettings"], outputs: ["onInterpretedText", "onFinishedRecognition", "onFinished"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i3.Textarea, selector: "[pTextarea]", inputs: ["autoResize", "variant", "fluid", "pSize"], outputs: ["onResize"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i7.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }] }); }
1558
+ }
1559
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: ChatFooterComponent, decorators: [{
1560
+ type: Component,
1561
+ args: [{ selector: 'dc-chat-footer', standalone: true, imports: [CommonModule, ReactiveFormsModule, ProgressBarModule, DCMicComponent, TextareaModule, ButtonModule], template: "<div class=\"progress-input\">\n <div class=\"input-container\">\n <dc-mic\n style=\"display: flex; align-items: center\"\n (onInterpretedText)=\"setInputText($event)\"\n (onFinished)=\"micFinished($event)\"\n [micSettings]=\"micSettings\"></dc-mic>\n\n <textarea pTextarea [formControl]=\"chatInputControl\" (keyup.enter)=\"sendUserMessage()\" rows=\"1\"></textarea>\n\n <p-button (click)=\"sendUserMessage()\" [disabled]=\"isAIThinking || !chatInputControl.value\" label=\"Enviar\" [rounded]=\"true\" />\n </div>\n\n <div>\n <p-progressbar showValue=\"false\" [value]=\"score\" [style]=\"{ height: '6px' }\" />\n </div>\n</div>\n", styles: [".progress-input{padding:10px;background-color:#f5f5f545;border-top:1px solid #b1a8a8}.progress-input .input-container{display:flex;align-items:center;margin-bottom:5px}.progress-input .input-container textarea{flex:1;resize:none;margin:0 10px}.progress-input .input-container .send-button{background-color:#007bff;color:#fff;border:none;border-radius:4px;padding:8px 15px;cursor:pointer}.progress-input .input-container .send-button:disabled{background-color:#ccc;cursor:not-allowed}.progress-input .input-container .send-button:hover:not(:disabled){background-color:#0069d9}\n"] }]
1562
+ }], propDecorators: { isAIThinking: [{
1563
+ type: Input
1564
+ }], score: [{
1565
+ type: Input
1566
+ }], micSettings: [{
1567
+ type: Input
1568
+ }], sendMessage: [{
1569
+ type: Output
1570
+ }], textInputChanged: [{
1571
+ type: Output
1572
+ }], micFinishedEvent: [{
1573
+ type: Output
1574
+ }] } });
1575
+
1262
1576
  const SpeedDescription = {
1263
1577
  1: 'Muy Lento',
1264
1578
  2: 'Lento',
@@ -1349,7 +1663,7 @@ class ProviderSelectorComponent {
1349
1663
  }
1350
1664
  }
1351
1665
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: ProviderSelectorComponent, deps: [{ token: CONVERSATION_AI_TOKEN }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
1352
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: ProviderSelectorComponent, isStandalone: true, selector: "dc-provider-selector", inputs: { parentForm: "parentForm" }, ngImport: i0, template: "<div>\n <hr />\n <b>Admin Section</b>\n <br />\n\n <b>Providers:</b>\n <div style=\"display: flex; gap: 10px\" [formGroup]=\"parentForm\">\n <div class=\"space\">\n <p-radioButton value=\"groq\" formControlName=\"provider\"></p-radioButton>\n <label class=\"space\">Groq</label>\n </div>\n\n <div class=\"space\">\n <p-radioButton value=\"openai\" formControlName=\"provider\"></p-radioButton>\n <label>Open AI</label>\n </div>\n\n <div class=\"space\">\n <p-radioButton value=\"google\" formControlName=\"provider\"></p-radioButton>\n <label class=\"space\">Google</label>\n </div>\n\n <div class=\"space\">\n <p-radioButton value=\"openrouter\" formControlName=\"provider\"></p-radioButton>\n <label class=\"space\">Open Router</label>\n </div>\n </div>\n\n <b>Modelo: </b>\n <span pTooltip=\"Modelo Seleccionado\">{{ parentForm.controls.modelName.value }}</span>\n @if (parentForm.controls.provider.value) { @if(isLoadingModels) {\n <p-skeleton height=\"200px\" width=\"100%\"></p-skeleton>\n } @else {\n <p-table [value]=\"modelnames\" stripedRows [size]=\"'small'\" [paginator]=\"true\" [rows]=\"12\" [formGroup]=\"parentForm\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th></th>\n <th>Name</th>\n <th>$$Prompt M</th>\n <th>$$Completion M</th>\n <th>$$Cost 90/10 M</th>\n <th>Created</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-model>\n <tr [pTooltip]=\"model.description | truncate : 200\" tooltipPosition=\"top\">\n <td><p-radioButton [value]=\"model.id\" formControlName=\"modelName\"></p-radioButton></td>\n <td>{{ model.name }}</td>\n <td>${{ +model.pricing?.prompt * 1000000 | number : '1.2-2' }}</td>\n <td>${{ +model.pricing?.completion * 1000000 | number : '1.2-2' }}</td>\n <td>${{ +model.pricing?.prompt * 1000000 * 0.9 + +model.pricing?.completion * 1000000 * 0.1 | number : '1.2-2' }}</td>\n <td>{{ model.created * 1000 | date : 'dd/MM/yyyy' }}</td>\n </tr>\n </ng-template>\n </p-table>\n } }\n</div>\n", styles: [":host{display:block}.space{display:flex;gap:2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i2.DecimalPipe, name: "number" }, { kind: "pipe", type: i2.DatePipe, name: "date" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: RadioButtonModule }, { kind: "component", type: i3.RadioButton, selector: "p-radioButton, p-radiobutton, p-radio-button", inputs: ["value", "formControlName", "name", "disabled", "variant", "size", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "style", "styleClass", "autofocus", "binary"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i5.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "style", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "scrollDirection", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "responsive", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "autoLayout", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "virtualRowHeight", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i6.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "style", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "pipe", type: TruncatePipe, name: "truncate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1666
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: ProviderSelectorComponent, isStandalone: true, selector: "dc-provider-selector", inputs: { parentForm: "parentForm" }, ngImport: i0, template: "<div>\n <hr />\n <b>Admin Section</b>\n <br />\n\n <b>Providers:</b>\n <div style=\"display: flex; gap: 10px\" [formGroup]=\"parentForm\">\n <div class=\"space\">\n <p-radioButton value=\"groq\" formControlName=\"provider\"></p-radioButton>\n <label class=\"space\">Groq</label>\n </div>\n\n <div class=\"space\">\n <p-radioButton value=\"openai\" formControlName=\"provider\"></p-radioButton>\n <label>Open AI</label>\n </div>\n\n <div class=\"space\">\n <p-radioButton value=\"google\" formControlName=\"provider\"></p-radioButton>\n <label class=\"space\">Google</label>\n </div>\n\n <div class=\"space\">\n <p-radioButton value=\"openrouter\" formControlName=\"provider\"></p-radioButton>\n <label class=\"space\">Open Router</label>\n </div>\n </div>\n\n <b>Modelo: </b>\n <span pTooltip=\"Modelo Seleccionado\">{{ parentForm.controls.modelName.value }}</span>\n @if (parentForm.controls.provider.value) { @if(isLoadingModels) {\n <p-skeleton height=\"200px\" width=\"100%\"></p-skeleton>\n } @else {\n <p-table [value]=\"modelnames\" stripedRows [size]=\"'small'\" [paginator]=\"true\" [rows]=\"12\" [formGroup]=\"parentForm\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th></th>\n <th>Name</th>\n <th>$$Prompt M</th>\n <th>$$Completion M</th>\n <th>$$Cost 90/10 M</th>\n <th>Created</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-model>\n <tr [pTooltip]=\"model.description | truncate : 200\" tooltipPosition=\"top\">\n <td><p-radioButton [value]=\"model.id\" formControlName=\"modelName\"></p-radioButton></td>\n <td>{{ model.name }}</td>\n <td>${{ +model.pricing?.prompt * 1000000 | number : '1.2-2' }}</td>\n <td>${{ +model.pricing?.completion * 1000000 | number : '1.2-2' }}</td>\n <td>${{ +model.pricing?.prompt * 1000000 * 0.9 + +model.pricing?.completion * 1000000 * 0.1 | number : '1.2-2' }}</td>\n <td>{{ model.created * 1000 | date : 'dd/MM/yyyy' }}</td>\n </tr>\n </ng-template>\n </p-table>\n } }\n</div>\n", styles: [":host{display:block}.space{display:flex;gap:2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$1.DecimalPipe, name: "number" }, { kind: "pipe", type: i1$1.DatePipe, name: "date" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: RadioButtonModule }, { kind: "component", type: i3$1.RadioButton, selector: "p-radioButton, p-radiobutton, p-radio-button", inputs: ["value", "formControlName", "name", "disabled", "variant", "size", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "style", "styleClass", "autofocus", "binary"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i5.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "style", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "scrollDirection", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "responsive", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "autoLayout", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "virtualRowHeight", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i4$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "style", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7$1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "pipe", type: TruncatePipe, name: "truncate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1353
1667
  }
1354
1668
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: ProviderSelectorComponent, decorators: [{
1355
1669
  type: Component,
@@ -1421,8 +1735,8 @@ class DCConversationUserChatSettingsComponent {
1421
1735
  this.dialogRef.close(this.form.value);
1422
1736
  }
1423
1737
  }
1424
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCConversationUserChatSettingsComponent, deps: [{ token: i1$2.DynamicDialogRef }, { token: i1$1.FormBuilder }, { token: CONVERSATION_AI_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
1425
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: DCConversationUserChatSettingsComponent, isStandalone: true, selector: "dc-chat-settings-dialog", inputs: { showFeature: "showFeature" }, outputs: { onSettingsChange: "onSettingsChange" }, viewQueries: [{ propertyName: "tooltipRef", first: true, predicate: ["tooltipRef"], descendants: true }], ngImport: i0, template: "<div class=\"dialog-container\">\n <form [formGroup]=\"form\">\n <div class=\"settings-section\" *ngIf=\"showFeature.synthVoice\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"synthVoice\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.synthVoice.disabled\">Escuchar Voz</span>\n <br />\n <small>Desmarca si solo quieres leer texto</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.highlightWords\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"highlightWords\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span>Narraci\u00F3n de texto</span>\n <br />\n <small>Remarca las palabras como se van pronuncionando</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.speed\">\n <p>\n Velocidad ({{ form.controls.speed.value | speedDisplay }})\n <br />\n <p-rating formControlName=\"speed\">\n <ng-template pTemplate=\"onicon\">\n <i class=\"pi pi-caret-right\"></i>\n </ng-template>\n <ng-template pTemplate=\"officon\">\n <i class=\"pi pi-circle\"></i>\n </ng-template>\n </p-rating>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.realTime\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"realTime\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.realTime.disabled\">Tiempo real</span>\n <br />\n <small>No tienes que presionar el microphono, comenzar\u00E1 a grabar en cuanto la AI termine de hablar, cierra el chat para finalizar conversaci\u00F3n.</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.realTime\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"repeatRecording\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span>Reproducir mi grabaci\u00F3n</span>\n <br />\n <small>Escucha tu dialogo, despu\u00E9s de grabar, te ayudar\u00E1 a notar tus errores.</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.superHearing\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"superHearing\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span>Super O\u00EDdo \uD83E\uDDBE</span>\n <br />\n <small>Tu audio se procesa en el servidor para mejor efectividad, si no usa el navegador.</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.fixGrammar\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"fixGrammar\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.fixGrammar.disabled\">Corregir gram\u00E1tica</span>\n <br />\n <small>La ai corrige tu forma de hablar/escribir y te retrolimenta de tus errores</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.autoTranslate\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"autoTranslate\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.autoTranslate.disabled\">Mostrar Traducciones</span>\n <br />\n <small>Texto adicional con la traducci\u00F3n</small>\n </p>\n </div>\n\n <div class=\"voice-selection\" *ngIf=\"showFeature.autoTranslate\">\n <span>Voz Preferencial:</span>\n <br />\n <p-radioButton value=\"random\" formControlName=\"voice\"></p-radioButton>\n <label class=\"space\">Aleatorio</label>\n\n <p-radioButton value=\"randomMan\" formControlName=\"voice\"></p-radioButton>\n <label class=\"space\">Hombre</label>\n\n <p-radioButton value=\"randomWoman\" formControlName=\"voice\"></p-radioButton>\n <label class=\"space\">Mujer</label>\n </div>\n\n @if(isAdmin) {\n <div>\n <hr />\n <b>Admin Section</b>\n <br />\n\n <b>Modelo:</b>\n\n <dc-provider-selector [parentForm]=\"form.controls.model\"></dc-provider-selector>\n </div>\n }\n\n <div class=\"button-group\">\n <p-button (click)=\"saveSettings()\" label=\"Guardar cambios\"></p-button>\n <p-button (click)=\"close()\" label=\"Cancelar\" styleClass=\"p-button-secondary\"></p-button>\n </div>\n </form>\n</div>\n", styles: [".dialog-container{padding:20px;background:#fff;border-radius:8px;min-width:300px;max-width:500px}.dialog-content{margin:20px 0}.dialog-actions{display:flex;justify-content:flex-end}.settings-section{margin-bottom:20px}.settings-section label{display:block;margin-bottom:5px;font-weight:700}.settings-section small{display:block;color:#666;margin-top:2px}.voice-selection{margin:15px 0}.voice-selection label{margin-right:15px}.button-group{margin-top:20px;display:flex;gap:10px;justify-content:flex-end}button{padding:8px 16px;border-radius:4px;border:none;cursor:pointer}button:first-child{background-color:#007bff;color:#fff}button:last-child{background-color:#6c757d;color:#fff}.space{margin-left:3px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$1.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: SliderModule }, { kind: "ngmodule", type: RadioButtonModule }, { kind: "component", type: i3.RadioButton, selector: "p-radioButton, p-radiobutton, p-radio-button", inputs: ["value", "formControlName", "name", "disabled", "variant", "size", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "style", "styleClass", "autofocus", "binary"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i7$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: SpeedDescPipe, name: "speedDisplay" }, { kind: "ngmodule", type: RatingModule }, { kind: "component", type: i8.Rating, selector: "p-rating", inputs: ["disabled", "readonly", "stars", "iconOnClass", "iconOnStyle", "iconOffClass", "iconOffStyle", "autofocus"], outputs: ["onRate", "onCancel", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TableModule }, { kind: "ngmodule", type: BadgeModule }, { kind: "ngmodule", type: SkeletonModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "component", type: ProviderSelectorComponent, selector: "dc-provider-selector", inputs: ["parentForm"] }] }); }
1738
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCConversationUserChatSettingsComponent, deps: [{ token: i1$3.DynamicDialogRef }, { token: i1$2.FormBuilder }, { token: CONVERSATION_AI_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
1739
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: DCConversationUserChatSettingsComponent, isStandalone: true, selector: "dc-chat-settings-dialog", inputs: { showFeature: "showFeature" }, outputs: { onSettingsChange: "onSettingsChange" }, viewQueries: [{ propertyName: "tooltipRef", first: true, predicate: ["tooltipRef"], descendants: true }], ngImport: i0, template: "<div class=\"dialog-container\">\n <form [formGroup]=\"form\">\n <div class=\"settings-section\" *ngIf=\"showFeature.synthVoice\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"synthVoice\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.synthVoice.disabled\">Escuchar Voz</span>\n <br />\n <small>Desmarca si solo quieres leer texto</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.highlightWords\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"highlightWords\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span>Narraci\u00F3n de texto</span>\n <br />\n <small>Remarca las palabras como se van pronuncionando</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.speed\">\n <p>\n Velocidad ({{ form.controls.speed.value | speedDisplay }})\n <br />\n <p-rating formControlName=\"speed\">\n <ng-template pTemplate=\"onicon\">\n <i class=\"pi pi-caret-right\"></i>\n </ng-template>\n <ng-template pTemplate=\"officon\">\n <i class=\"pi pi-circle\"></i>\n </ng-template>\n </p-rating>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.realTime\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"realTime\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.realTime.disabled\">Tiempo real</span>\n <br />\n <small>No tienes que presionar el microphono, comenzar\u00E1 a grabar en cuanto la AI termine de hablar, cierra el chat para finalizar conversaci\u00F3n.</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.realTime\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"repeatRecording\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span>Reproducir mi grabaci\u00F3n</span>\n <br />\n <small>Escucha tu dialogo, despu\u00E9s de grabar, te ayudar\u00E1 a notar tus errores.</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.superHearing\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"superHearing\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span>Super O\u00EDdo \uD83E\uDDBE</span>\n <br />\n <small>Tu audio se procesa en el servidor para mejor efectividad, si no usa el navegador.</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.fixGrammar\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"fixGrammar\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.fixGrammar.disabled\">Corregir gram\u00E1tica</span>\n <br />\n <small>La ai corrige tu forma de hablar/escribir y te retrolimenta de tus errores</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.autoTranslate\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"autoTranslate\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.autoTranslate.disabled\">Mostrar Traducciones</span>\n <br />\n <small>Texto adicional con la traducci\u00F3n</small>\n </p>\n </div>\n\n <div class=\"voice-selection\" *ngIf=\"showFeature.autoTranslate\">\n <span>Voz Preferencial:</span>\n <br />\n <p-radioButton value=\"random\" formControlName=\"voice\"></p-radioButton>\n <label class=\"space\">Aleatorio</label>\n\n <p-radioButton value=\"randomMan\" formControlName=\"voice\"></p-radioButton>\n <label class=\"space\">Hombre</label>\n\n <p-radioButton value=\"randomWoman\" formControlName=\"voice\"></p-radioButton>\n <label class=\"space\">Mujer</label>\n </div>\n\n @if(isAdmin) {\n <div>\n <hr />\n <b>Admin Section</b>\n <br />\n\n <b>Modelo:</b>\n\n <dc-provider-selector [parentForm]=\"form.controls.model\"></dc-provider-selector>\n </div>\n }\n\n <div class=\"button-group\">\n <p-button (click)=\"saveSettings()\" label=\"Guardar cambios\"></p-button>\n <p-button (click)=\"close()\" label=\"Cancelar\" styleClass=\"p-button-secondary\"></p-button>\n </div>\n </form>\n</div>\n", styles: [".dialog-container{padding:20px;background:#fff;border-radius:8px;min-width:300px;max-width:500px}.dialog-content{margin:20px 0}.dialog-actions{display:flex;justify-content:flex-end}.settings-section{margin-bottom:20px}.settings-section label{display:block;margin-bottom:5px;font-weight:700}.settings-section small{display:block;color:#666;margin-top:2px}.voice-selection{margin:15px 0}.voice-selection label{margin-right:15px}.button-group{margin-top:20px;display:flex;gap:10px;justify-content:flex-end}button{padding:8px 16px;border-radius:4px;border:none;cursor:pointer}button:first-child{background-color:#007bff;color:#fff}button:last-child{background-color:#6c757d;color:#fff}.space{margin-left:3px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$2.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: SliderModule }, { kind: "ngmodule", type: RadioButtonModule }, { kind: "component", type: i3$1.RadioButton, selector: "p-radioButton, p-radiobutton, p-radio-button", inputs: ["value", "formControlName", "name", "disabled", "variant", "size", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "style", "styleClass", "autofocus", "binary"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i7.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: SpeedDescPipe, name: "speedDisplay" }, { kind: "ngmodule", type: RatingModule }, { kind: "component", type: i8.Rating, selector: "p-rating", inputs: ["disabled", "readonly", "stars", "iconOnClass", "iconOnStyle", "iconOffClass", "iconOffStyle", "autofocus"], outputs: ["onRate", "onCancel", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TableModule }, { kind: "ngmodule", type: BadgeModule }, { kind: "ngmodule", type: SkeletonModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "component", type: ProviderSelectorComponent, selector: "dc-provider-selector", inputs: ["parentForm"] }] }); }
1426
1740
  }
1427
1741
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCConversationUserChatSettingsComponent, decorators: [{
1428
1742
  type: Component,
@@ -1441,7 +1755,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImpor
1441
1755
  TooltipModule,
1442
1756
  ProviderSelectorComponent,
1443
1757
  ], template: "<div class=\"dialog-container\">\n <form [formGroup]=\"form\">\n <div class=\"settings-section\" *ngIf=\"showFeature.synthVoice\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"synthVoice\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.synthVoice.disabled\">Escuchar Voz</span>\n <br />\n <small>Desmarca si solo quieres leer texto</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.highlightWords\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"highlightWords\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span>Narraci\u00F3n de texto</span>\n <br />\n <small>Remarca las palabras como se van pronuncionando</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.speed\">\n <p>\n Velocidad ({{ form.controls.speed.value | speedDisplay }})\n <br />\n <p-rating formControlName=\"speed\">\n <ng-template pTemplate=\"onicon\">\n <i class=\"pi pi-caret-right\"></i>\n </ng-template>\n <ng-template pTemplate=\"officon\">\n <i class=\"pi pi-circle\"></i>\n </ng-template>\n </p-rating>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.realTime\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"realTime\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.realTime.disabled\">Tiempo real</span>\n <br />\n <small>No tienes que presionar el microphono, comenzar\u00E1 a grabar en cuanto la AI termine de hablar, cierra el chat para finalizar conversaci\u00F3n.</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.realTime\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"repeatRecording\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span>Reproducir mi grabaci\u00F3n</span>\n <br />\n <small>Escucha tu dialogo, despu\u00E9s de grabar, te ayudar\u00E1 a notar tus errores.</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.superHearing\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"superHearing\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span>Super O\u00EDdo \uD83E\uDDBE</span>\n <br />\n <small>Tu audio se procesa en el servidor para mejor efectividad, si no usa el navegador.</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.fixGrammar\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"fixGrammar\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.fixGrammar.disabled\">Corregir gram\u00E1tica</span>\n <br />\n <small>La ai corrige tu forma de hablar/escribir y te retrolimenta de tus errores</small>\n </p>\n </div>\n\n <div class=\"settings-section\" *ngIf=\"showFeature.autoTranslate\">\n <p>\n <p-checkbox class=\"mr-2\" formControlName=\"autoTranslate\" [binary]=\"true\" inputId=\"binary\"></p-checkbox>\n <span [class.cross]=\"form.controls.autoTranslate.disabled\">Mostrar Traducciones</span>\n <br />\n <small>Texto adicional con la traducci\u00F3n</small>\n </p>\n </div>\n\n <div class=\"voice-selection\" *ngIf=\"showFeature.autoTranslate\">\n <span>Voz Preferencial:</span>\n <br />\n <p-radioButton value=\"random\" formControlName=\"voice\"></p-radioButton>\n <label class=\"space\">Aleatorio</label>\n\n <p-radioButton value=\"randomMan\" formControlName=\"voice\"></p-radioButton>\n <label class=\"space\">Hombre</label>\n\n <p-radioButton value=\"randomWoman\" formControlName=\"voice\"></p-radioButton>\n <label class=\"space\">Mujer</label>\n </div>\n\n @if(isAdmin) {\n <div>\n <hr />\n <b>Admin Section</b>\n <br />\n\n <b>Modelo:</b>\n\n <dc-provider-selector [parentForm]=\"form.controls.model\"></dc-provider-selector>\n </div>\n }\n\n <div class=\"button-group\">\n <p-button (click)=\"saveSettings()\" label=\"Guardar cambios\"></p-button>\n <p-button (click)=\"close()\" label=\"Cancelar\" styleClass=\"p-button-secondary\"></p-button>\n </div>\n </form>\n</div>\n", styles: [".dialog-container{padding:20px;background:#fff;border-radius:8px;min-width:300px;max-width:500px}.dialog-content{margin:20px 0}.dialog-actions{display:flex;justify-content:flex-end}.settings-section{margin-bottom:20px}.settings-section label{display:block;margin-bottom:5px;font-weight:700}.settings-section small{display:block;color:#666;margin-top:2px}.voice-selection{margin:15px 0}.voice-selection label{margin-right:15px}.button-group{margin-top:20px;display:flex;gap:10px;justify-content:flex-end}button{padding:8px 16px;border-radius:4px;border:none;cursor:pointer}button:first-child{background-color:#007bff;color:#fff}button:last-child{background-color:#6c757d;color:#fff}.space{margin-left:3px}\n"] }]
1444
- }], ctorParameters: () => [{ type: i1$2.DynamicDialogRef }, { type: i1$1.FormBuilder }, { type: AgentCardsAbstractService, decorators: [{
1758
+ }], ctorParameters: () => [{ type: i1$3.DynamicDialogRef }, { type: i1$2.FormBuilder }, { type: AgentCardsAbstractService, decorators: [{
1445
1759
  type: Inject,
1446
1760
  args: [CONVERSATION_AI_TOKEN]
1447
1761
  }] }], propDecorators: { showFeature: [{
@@ -1478,6 +1792,7 @@ const DefaultEvaluatorAgentCard = {
1478
1792
  model: { id: 'gpt-4o-mini', provider: 'openai' },
1479
1793
  sources: [],
1480
1794
  };
1795
+
1481
1796
  class DCChatComponent {
1482
1797
  constructor(agentCardService, toastService, conversationBuilder, dialogService, cdr) {
1483
1798
  this.agentCardService = agentCardService;
@@ -1492,11 +1807,9 @@ class DCChatComponent {
1492
1807
  this.thinkingImg = `data:image/svg+xml;base64,${btoa(decodeURIComponent(ICONS.gear))}`;
1493
1808
  this.isDestroyed = false;
1494
1809
  this.score = 10;
1495
- // @ViewChild('textSelectedDiv') textSelectedDiv!: ElementRef;
1496
- // get viewChild to the app-mic
1497
- // @ViewChild(MicComponent) micComponent: MicComponent;
1810
+ this.isAdmin = true;
1498
1811
  this.isChatSettingsVisible = false;
1499
- this.chatInputControl = new FormControl();
1812
+ // chatInputControl moved to ChatFooterComponent
1500
1813
  this.isAIThinking = false;
1501
1814
  this.isUserTalking = false;
1502
1815
  this.aiIcon = `data:image/svg+xml;base64,${btoa(decodeURIComponent(ICONS.ai))}`;
@@ -1579,7 +1892,7 @@ class DCChatComponent {
1579
1892
  }
1580
1893
  return message;
1581
1894
  }
1582
- settingsClick() {
1895
+ changeUserChatSettings() {
1583
1896
  this.dialogService
1584
1897
  .open(DCConversationUserChatSettingsComponent, {
1585
1898
  width: '90vw',
@@ -1612,12 +1925,8 @@ class DCChatComponent {
1612
1925
  if (this.isAIThinking) {
1613
1926
  return;
1614
1927
  }
1615
- if (!message || !message.content) {
1616
- const text = this.chatInputControl.value;
1617
- if (!text) {
1618
- return;
1619
- }
1620
- message = { content: text, role: ChatRole.User };
1928
+ if (!message) {
1929
+ return;
1621
1930
  }
1622
1931
  this.messages.push(message); // This activates the render of the message
1623
1932
  // ESTO debe ser una especie de plugin.
@@ -1627,7 +1936,7 @@ class DCChatComponent {
1627
1936
  // this.messages.push({ content: res.text, role: ChatRole.AssistantHelper });
1628
1937
  // });
1629
1938
  // }
1630
- this.chatInputControl.setValue('');
1939
+ // Input clearing is now handled by the chat-footer component
1631
1940
  this.setAIthinking();
1632
1941
  try {
1633
1942
  // if (this.chatboxService.fakeConversations.length > 0) {
@@ -1729,7 +2038,8 @@ class DCChatComponent {
1729
2038
  }
1730
2039
  }
1731
2040
  setInputText(text) {
1732
- this.chatInputControl.setValue(text);
2041
+ // Method now receives text from the chat-footer component
2042
+ // No need to set the value as it's handled in the child component
1733
2043
  }
1734
2044
  async micFinished(eventBlob) {
1735
2045
  if (eventBlob instanceof Blob) {
@@ -1765,10 +2075,6 @@ class DCChatComponent {
1765
2075
  // this.speechService.speach(message.content);
1766
2076
  // }
1767
2077
  }
1768
- // public restartConversation() {
1769
- // this.messages = [];
1770
- // this.messages.length;
1771
- // }
1772
2078
  // public someTextSelected(event) {
1773
2079
  // console.log('someTextSelected', event);
1774
2080
  // this.wordMenuService.showMenu(event.position, event.text);
@@ -1803,24 +2109,9 @@ class DCChatComponent {
1803
2109
  console.log('chatUserSettings', this.chatUserSettings);
1804
2110
  this.isInfoVisible = true;
1805
2111
  }
1806
- async changeConversationCard() {
1807
- const response = prompt('¿Qué conversación quieres usar? Escribe el titulo ejemplo: word_reflection_level_1_base_es');
1808
- if (response) {
1809
- const filters = {
1810
- filters: {
1811
- title: { $regex: response },
1812
- },
1813
- };
1814
- console.log('filters', filters);
1815
- const conversationCards = await this.agentCardService.filterConversationCards(filters);
1816
- console.log('conversationCards', conversationCards);
1817
- this.alternativeConversation = conversationCards.rows;
1818
- }
1819
- }
1820
2112
  async restartConversation(conversation = null) {
1821
2113
  if (conversation) {
1822
2114
  this.agentCard = conversation;
1823
- // this.conversationSettings = this.promptBuilder.buildConversationSettings(this.conversationCard, this.parseDict);
1824
2115
  }
1825
2116
  await this.ngOnInit();
1826
2117
  }
@@ -1867,19 +2158,29 @@ and give the response in next JSON format.
1867
2158
  }
1868
2159
  console.log('response', response);
1869
2160
  }
1870
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCChatComponent, deps: [{ token: CONVERSATION_AI_TOKEN }, { token: TOAST_ALERTS_TOKEN }, { token: DCConversationPromptBuilderService }, { token: i1$2.DialogService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
1871
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: DCChatComponent, isStandalone: true, selector: "dc-chat", inputs: { chatUserSettings: "chatUserSettings", agentCard: "agentCard", evaluatorAgentCard: "evaluatorAgentCard", parseDict: "parseDict" }, outputs: { sendMessage: "sendMessage" }, providers: [DialogService], ngImport: i0, template: "<div style=\"display: flex; justify-content: space-between\">\n <span class=\"pointer\" (click)=\"restartConversation()\">Reiniciar conversaci\u00F3n</span>\n\n @for (conversation of alternativeConversation; track conversation._id) {\n <span class=\"pointer\" (click)=\"restartConversation(conversation)\"> {{ conversation.title }} </span>\n }\n\n <div style=\"font-size: large\">\n <span class=\"pointer\" (click)=\"changeConversationCard()\"> \uD83D\uDD04 </span>\n\n <span class=\"pointer\" (click)=\"showInfo()\"> \u26A1\uFE0F </span>\n\n <span class=\"pointer\" (click)=\"settingsClick()\"> \u2699\uFE0F </span>\n </div>\n</div>\n<div class=\"chat-container\" (touchmove)=\"$event.stopPropagation()\">\n <ul class=\"chat\">\n <ng-container *ngFor=\"let msn of messages\">\n <li *ngIf=\"msn.role == 'assistant'\" class=\"message left\">\n <img (click)=\"playMessage(msn)\" class=\"logo fit-top-image\" [src]=\"agentCard?.assets?.image?.url ?? imageUser\" />\n\n <dc-chat-message [chatUserSettings]=\"chatUserSettings\" appTextSelectable [chatMessage]=\"msn\"></dc-chat-message>\n </li>\n\n <li *ngIf=\"msn.role == 'assistantHelper'\" class=\"message-helper right\">\n <dc-chat-message [chatUserSettings]=\"chatUserSettings\" appTextSelectable [chatMessage]=\"msn\"></dc-chat-message>\n </li>\n\n <li *ngIf=\"msn.role == 'user'\" class=\"message right\">\n <img (click)=\"playMessage(msn)\" class=\"logo\" [src]=\"user?.urlPicture || imageUser\" alt=\"\" style=\"object-fit: cover; object-position: top\" />\n <dc-chat-message appTextSelectable [chatMessage]=\"msn\"></dc-chat-message>\n </li>\n </ng-container>\n\n @if (isAIThinking) {\n <li class=\"message left\">\n <img class=\"logo fit-top-image\" [src]=\"agentCard?.assets?.image?.url ?? aiIcon\" />\n\n <span style=\"font-size: 1.5em; position: absolute; left: 20px; bottom: -5px\">\uD83E\uDD14</span>\n\n <div class=\"flex\">\n <!-- <p-skeleton shape=\"circle\" size=\"4rem\" styleClass=\"mr-2\" /> -->\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n </li>\n }\n\n <li *ngIf=\"isUserTalking || isGettingTranscription\" class=\"message right\">\n <img class=\"logo fit-top-image\" [src]=\"user?.urlPicture || imageUser\" alt=\"\" />\n @if (isUserTalking) {\n <p> ... </p>\n } @if (isGettingTranscription) {\n <i class=\"pi pi-spin pi-spinner-dotted\"></i>\n }\n </li>\n </ul>\n\n <div class=\"progress-input\">\n <div class=\"input-container\">\n <dc-mic\n style=\"display: flex; align-items: center\"\n (onInterpretedText)=\"setInputText($event)\"\n (onFinished)=\"micFinished($event)\"\n [micSettings]=\"micSettings\"></dc-mic>\n <textarea class=\"text-fix white-background\" [formControl]=\"chatInputControl\" (keyup.enter)=\"sendUserMessage()\" rows=\"1\"></textarea>\n <button [disabled]=\"isAIThinking || !chatInputControl.value\" (click)=\"sendUserMessage()\" class=\"send-button\"> Enviar </button>\n </div>\n\n <div>\n <p-progressbar showValue=\"false\" [value]=\"score\" [style]=\"{ height: '6px' }\" />\n </div>\n </div>\n</div>\n\n<p-dialog header=\"Informaci\u00F3n de la conversaci\u00F3n\" [(visible)]=\"isInfoVisible\" [modal]=\"true\">\n <p> <strong> Modelo: </strong> {{ this.chatUserSettings?.model?.provider }} - {{ this.chatUserSettings?.model?.modelName }} </p>\n\n <p>\n <strong> Tipo : </strong> {{ agentCard?.conversationSettings?.conversationType }} <strong> Text Engine: </strong>\n {{ agentCard?.conversationSettings?.textEngine }}\n </p>\n\n <p>\n <strong> Language: </strong> {{ agentCard?.lang }} <strong> TTS: </strong> {{ agentCard?.tts?.voice }} <strong> Secondary TTS: </strong>\n {{ agentCard?.tts?.secondaryVoice }}\n </p>\n\n <p> <strong> Parametros: </strong> {{ parseDict | json }} </p>\n <hr />\n <h5>Conversaci\u00F3n hasta ahora</h5>\n\n <div *ngFor=\"let message of conversationSettings.messages\">\n <p\n ><strong>{{ message.role }}: </strong> {{ message.content }}</p\n >\n </div>\n</p-dialog>\n", styles: [".top-5{margin-top:10px}.logo{width:30px;height:30px}.white-background{background-color:#fff}.selectable{z-index:1;position:fixed;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px);background:transparent;border-radius:20px;display:block;padding:3px}*{box-sizing:border-box}.background1{background:url(/assets/background/default-background.webp);background-size:cover;background-position:center center;display:flex;align-items:center;justify-content:center;flex-direction:column;min-height:0px;overflow:auto;max-height:500px}h2{text-shadow:1px 1px 2px rgb(0,0,0);color:#fff;letter-spacing:1px;text-transform:uppercase;text-align:center}.chat-container{border-radius:10px;overflow:hidden;padding:15px;position:relative;max-width:100%;height:100%;display:flex;flex-direction:column}.chat{display:flex;flex-direction:column;list-style-type:none;padding:0;margin:0;overflow-y:auto;flex:1}.message-helper{background-color:#ffffffe6;box-shadow:0 7px 5px #00000080;position:relative;margin-bottom:30px}.message-helper.right{align-self:flex-end;padding:4px 45px 4px 15px}.message{background-color:#f6f6f6e6;border-radius:50px;box-shadow:7px 11px 14px #00000080;position:relative;margin-bottom:30px}.message .logo{position:absolute;top:50%;transform:translateY(-50%);border-radius:50%}.message .fit-top-image{object-fit:cover;object-position:top}.message.left{padding:10px 15px 10px 45px}.message.left .logo{left:5px}.message.right{align-self:flex-end;padding:10px 45px 10px 15px}.message.right .logo{right:5px}.input-container{margin-top:auto;display:flex;gap:10px;padding-top:15px;background:inherit}.input-container textarea{flex:1;padding:8px;border-radius:20px;border:1px solid #ccc;resize:none}.input-container .send-button{padding:8px 15px;border-radius:20px;border:none;background:#007bff;color:#fff;cursor:pointer}.input-container .send-button:disabled{background:#ccc;cursor:not-allowed}::ng-deep .cdk-overlay-container{z-index:1400}::ng-deep .cdk-global-overlay-wrapper{z-index:1400}::ng-deep .dialog-backdrop{background:#00000080;z-index:1299}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.JsonPipe, name: "json" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: ChatMessageComponent, selector: "dc-chat-message", inputs: ["chatMessage", "chatUserSettings"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i6.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "style", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: DCMicComponent, selector: "dc-mic", inputs: ["isDone", "useWhisper", "targetOrBase", "micSettings"], outputs: ["onInterpretedText", "onFinishedRecognition", "onFinished"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i6$1.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: ProgressBarModule }, { kind: "component", type: i7$2.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "style", "unit", "mode", "color"] }] }); }
2161
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCChatComponent, deps: [{ token: CONVERSATION_AI_TOKEN }, { token: TOAST_ALERTS_TOKEN }, { token: DCConversationPromptBuilderService }, { token: i1$3.DialogService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2162
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: DCChatComponent, isStandalone: true, selector: "dc-chat", inputs: { chatUserSettings: "chatUserSettings", agentCard: "agentCard", evaluatorAgentCard: "evaluatorAgentCard", parseDict: "parseDict" }, outputs: { sendMessage: "sendMessage" }, providers: [DialogService], ngImport: i0, template: "<dc-chat-header\n [isAdmin]=\"isAdmin\"\n [alternativeConversation]=\"alternativeConversation\"\n (restartConversationEvent)=\"restartConversation($event || null)\"\n (showInfoEvent)=\"showInfo()\"\n (settingsClickEvent)=\"changeUserChatSettings()\">\n</dc-chat-header>\n\n<main class=\"chat-container\" (touchmove)=\"$event.stopPropagation()\">\n <div class=\"chat\" aria-live=\"polite\">\n @for (message of messages; track message) { @switch (message.role) { @case ('assistant') {\n <div class=\"message left\">\n <img class=\"logo fit-top-image\" [src]=\"agentCard?.assets?.image?.url ?? imageUser\" (click)=\"playMessage(message)\" />\n <dc-chat-message [chatUserSettings]=\"chatUserSettings\" [chatMessage]=\"message\" appTextSelectable> </dc-chat-message>\n </div>\n } @case ('assistantHelper') {\n <div class=\"message-helper right\">\n <dc-chat-message [chatUserSettings]=\"chatUserSettings\" [chatMessage]=\"message\" appTextSelectable> </dc-chat-message>\n </div>\n } @case ('user') {\n <div class=\"message right\">\n <img class=\"logo fit-top-image\" [src]=\"user?.urlPicture || 'assets/defaults/avatar.jpg'\" [alt]=\"'User avatar'\" (click)=\"playMessage(message)\" />\n <dc-chat-message [chatMessage]=\"message\" appTextSelectable> </dc-chat-message>\n </div>\n } } }\n\n <!-- AI thinking indicator -->\n @if (isAIThinking) {\n <div class=\"message message--assistant message--thinking\">\n <span class=\"thinking-emoji\" aria-hidden=\"true\">\uD83E\uDD14</span>\n <div class=\"thinking-indicator\">\n <div class=\"skeleton-container\">\n <p-skeleton width=\"100%\" />\n <br />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n </div>\n }\n\n <!-- User typing or transcribing indicator -->\n @if (isUserTalking || isGettingTranscription) {\n <div class=\"message message--user message--activity\">\n <img class=\"avatar avatar--user\" [src]=\"user?.urlPicture || imageUser\" [alt]=\"'User avatar'\" />\n @if (isUserTalking) {\n <p class=\"typing-indicator\" aria-label=\"User is speaking\">...</p>\n } @if (isGettingTranscription) {\n <i class=\"pi pi-spin pi-spinner-dotted\" aria-label=\"Transcribing speech\"></i>\n }\n </div>\n }\n </div>\n</main>\n\n<dc-chat-footer\n [isAIThinking]=\"isAIThinking\"\n [score]=\"score\"\n [micSettings]=\"micSettings\"\n (sendMessage)=\"sendUserMessage($event)\"\n (textInputChanged)=\"setInputText($event)\"\n (micFinishedEvent)=\"micFinished($event)\">\n</dc-chat-footer>\n\n<!-- Information dialog -->\n<p-dialog\n header=\"Informaci\u00F3n de la conversaci\u00F3n\"\n [(visible)]=\"isInfoVisible\"\n [modal]=\"true\"\n [responsive]=\"true\"\n styleClass=\"conversation-info-dialog\"\n aria-labelledby=\"conversation-info-title\">\n <div class=\"dialog-content\">\n <section class=\"model-info\">\n <h3 id=\"conversation-info-title\" class=\"sr-only\">Informaci\u00F3n de la conversaci\u00F3n</h3>\n <dl class=\"info-list\">\n <dt>Modelo:</dt>\n <dd>{{ chatUserSettings?.model?.provider }} - {{ chatUserSettings?.model?.modelName }}</dd>\n\n <dt>Tipo:</dt>\n <dd>{{ agentCard?.conversationSettings?.conversationType }}</dd>\n\n <dt>Text Engine:</dt>\n <dd>{{ agentCard?.conversationSettings?.textEngine }}</dd>\n\n <dt>Language:</dt>\n <dd>{{ agentCard?.lang }}</dd>\n\n <dt>TTS:</dt>\n <dd>{{ agentCard?.conversationSettings?.tts?.voice }}</dd>\n\n <dt>Secondary TTS:</dt>\n <dd>{{ agentCard?.conversationSettings?.tts?.secondaryVoice }}</dd>\n </dl>\n\n <div class=\"parameters\">\n <h4>Par\u00E1metros:</h4>\n <pre>{{ parseDict | json }}</pre>\n </div>\n </section>\n\n <section class=\"conversation-history\">\n <h4>Conversaci\u00F3n hasta ahora</h4>\n <div class=\"message-history-list\">\n @for (message of conversationSettings.messages; track message) {\n <div class=\"message-history-item\">\n <span class=\"message-role\">{{ message.role }}:</span>\n <span class=\"message-content\">{{ message.content }}</span>\n </div>\n }\n </div>\n </section>\n </div>\n</p-dialog>\n", styles: [":host{display:flex;flex-direction:column;height:100%}*{box-sizing:border-box}.chat-container{border-radius:10px;overflow:hidden;padding:15px;position:relative;max-width:100%;height:100%;display:flex;flex-direction:column}.chat{display:flex;flex-direction:column;list-style-type:none;padding:0;margin:0;overflow-y:auto;flex:1}.logo{width:30px;height:30px}.logo.fit-top-image{object-fit:cover;object-position:top;border-radius:50%}.message{background-color:#f6f6f6f2;border-radius:25px;box-shadow:0 5px 15px #0000001a;position:relative;margin-bottom:20px;transition:all .2s ease}.message .logo{position:absolute;top:50%;transform:translateY(-50%);border-radius:50%;cursor:pointer}.message .logo:hover{transform:translateY(-50%) scale(1.05)}.message.left{padding:12px 15px 12px 45px;margin-right:20%}.message.left .logo{left:5px}.message.right{align-self:flex-end;padding:12px 45px 12px 15px;margin-left:20%;background-color:#e6f0fff2}.message.right .logo{right:5px}.message--thinking,.message--activity{opacity:.7}.message-helper{background-color:#ffffffe6;box-shadow:0 3px 10px #0000001a;position:relative;margin-bottom:20px;border-radius:20px}.message-helper.right{align-self:flex-end;padding:8px 15px;margin-left:20%}.thinking-indicator{padding:5px}.thinking-indicator .skeleton-container{width:200px}::ng-deep .cdk-overlay-container,::ng-deep .cdk-global-overlay-wrapper{z-index:1400}::ng-deep .dialog-backdrop{background:#00000080;z-index:1299}::ng-deep .conversation-info-dialog .dialog-content{max-height:70vh;overflow-y:auto}::ng-deep .conversation-info-dialog .info-list{display:grid;grid-template-columns:auto 1fr;gap:8px;margin-bottom:20px}::ng-deep .conversation-info-dialog .info-list dt{font-weight:700}::ng-deep .conversation-info-dialog .message-history-list{max-height:300px;overflow-y:auto;border:1px solid #eee;border-radius:5px;padding:10px}::ng-deep .conversation-info-dialog .message-history-list .message-history-item{padding:5px 0;border-bottom:1px solid #f0f0f0}::ng-deep .conversation-info-dialog .message-history-list .message-history-item:last-child{border-bottom:none}::ng-deep .conversation-info-dialog .message-history-list .message-history-item .message-role{font-weight:700;margin-right:5px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: ChatMessageComponent, selector: "dc-chat-message", inputs: ["chatMessage", "chatUserSettings"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i4$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "style", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i5$1.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: ProgressBarModule }, { kind: "component", type: ChatHeaderComponent, selector: "dc-chat-header", inputs: ["isAdmin", "alternativeConversation"], outputs: ["restartConversationEvent", "showInfoEvent", "settingsClickEvent"] }, { kind: "component", type: ChatFooterComponent, selector: "dc-chat-footer", inputs: ["isAIThinking", "score", "micSettings"], outputs: ["sendMessage", "textInputChanged", "micFinishedEvent"] }] }); }
1872
2163
  }
1873
2164
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCChatComponent, decorators: [{
1874
2165
  type: Component,
1875
- args: [{ selector: 'dc-chat', standalone: true, imports: [CommonModule, FormsModule, ChatMessageComponent, ReactiveFormsModule, SkeletonModule, DCMicComponent, DialogModule, ProgressBarModule], providers: [DialogService], template: "<div style=\"display: flex; justify-content: space-between\">\n <span class=\"pointer\" (click)=\"restartConversation()\">Reiniciar conversaci\u00F3n</span>\n\n @for (conversation of alternativeConversation; track conversation._id) {\n <span class=\"pointer\" (click)=\"restartConversation(conversation)\"> {{ conversation.title }} </span>\n }\n\n <div style=\"font-size: large\">\n <span class=\"pointer\" (click)=\"changeConversationCard()\"> \uD83D\uDD04 </span>\n\n <span class=\"pointer\" (click)=\"showInfo()\"> \u26A1\uFE0F </span>\n\n <span class=\"pointer\" (click)=\"settingsClick()\"> \u2699\uFE0F </span>\n </div>\n</div>\n<div class=\"chat-container\" (touchmove)=\"$event.stopPropagation()\">\n <ul class=\"chat\">\n <ng-container *ngFor=\"let msn of messages\">\n <li *ngIf=\"msn.role == 'assistant'\" class=\"message left\">\n <img (click)=\"playMessage(msn)\" class=\"logo fit-top-image\" [src]=\"agentCard?.assets?.image?.url ?? imageUser\" />\n\n <dc-chat-message [chatUserSettings]=\"chatUserSettings\" appTextSelectable [chatMessage]=\"msn\"></dc-chat-message>\n </li>\n\n <li *ngIf=\"msn.role == 'assistantHelper'\" class=\"message-helper right\">\n <dc-chat-message [chatUserSettings]=\"chatUserSettings\" appTextSelectable [chatMessage]=\"msn\"></dc-chat-message>\n </li>\n\n <li *ngIf=\"msn.role == 'user'\" class=\"message right\">\n <img (click)=\"playMessage(msn)\" class=\"logo\" [src]=\"user?.urlPicture || imageUser\" alt=\"\" style=\"object-fit: cover; object-position: top\" />\n <dc-chat-message appTextSelectable [chatMessage]=\"msn\"></dc-chat-message>\n </li>\n </ng-container>\n\n @if (isAIThinking) {\n <li class=\"message left\">\n <img class=\"logo fit-top-image\" [src]=\"agentCard?.assets?.image?.url ?? aiIcon\" />\n\n <span style=\"font-size: 1.5em; position: absolute; left: 20px; bottom: -5px\">\uD83E\uDD14</span>\n\n <div class=\"flex\">\n <!-- <p-skeleton shape=\"circle\" size=\"4rem\" styleClass=\"mr-2\" /> -->\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n </li>\n }\n\n <li *ngIf=\"isUserTalking || isGettingTranscription\" class=\"message right\">\n <img class=\"logo fit-top-image\" [src]=\"user?.urlPicture || imageUser\" alt=\"\" />\n @if (isUserTalking) {\n <p> ... </p>\n } @if (isGettingTranscription) {\n <i class=\"pi pi-spin pi-spinner-dotted\"></i>\n }\n </li>\n </ul>\n\n <div class=\"progress-input\">\n <div class=\"input-container\">\n <dc-mic\n style=\"display: flex; align-items: center\"\n (onInterpretedText)=\"setInputText($event)\"\n (onFinished)=\"micFinished($event)\"\n [micSettings]=\"micSettings\"></dc-mic>\n <textarea class=\"text-fix white-background\" [formControl]=\"chatInputControl\" (keyup.enter)=\"sendUserMessage()\" rows=\"1\"></textarea>\n <button [disabled]=\"isAIThinking || !chatInputControl.value\" (click)=\"sendUserMessage()\" class=\"send-button\"> Enviar </button>\n </div>\n\n <div>\n <p-progressbar showValue=\"false\" [value]=\"score\" [style]=\"{ height: '6px' }\" />\n </div>\n </div>\n</div>\n\n<p-dialog header=\"Informaci\u00F3n de la conversaci\u00F3n\" [(visible)]=\"isInfoVisible\" [modal]=\"true\">\n <p> <strong> Modelo: </strong> {{ this.chatUserSettings?.model?.provider }} - {{ this.chatUserSettings?.model?.modelName }} </p>\n\n <p>\n <strong> Tipo : </strong> {{ agentCard?.conversationSettings?.conversationType }} <strong> Text Engine: </strong>\n {{ agentCard?.conversationSettings?.textEngine }}\n </p>\n\n <p>\n <strong> Language: </strong> {{ agentCard?.lang }} <strong> TTS: </strong> {{ agentCard?.tts?.voice }} <strong> Secondary TTS: </strong>\n {{ agentCard?.tts?.secondaryVoice }}\n </p>\n\n <p> <strong> Parametros: </strong> {{ parseDict | json }} </p>\n <hr />\n <h5>Conversaci\u00F3n hasta ahora</h5>\n\n <div *ngFor=\"let message of conversationSettings.messages\">\n <p\n ><strong>{{ message.role }}: </strong> {{ message.content }}</p\n >\n </div>\n</p-dialog>\n", styles: [".top-5{margin-top:10px}.logo{width:30px;height:30px}.white-background{background-color:#fff}.selectable{z-index:1;position:fixed;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px);background:transparent;border-radius:20px;display:block;padding:3px}*{box-sizing:border-box}.background1{background:url(/assets/background/default-background.webp);background-size:cover;background-position:center center;display:flex;align-items:center;justify-content:center;flex-direction:column;min-height:0px;overflow:auto;max-height:500px}h2{text-shadow:1px 1px 2px rgb(0,0,0);color:#fff;letter-spacing:1px;text-transform:uppercase;text-align:center}.chat-container{border-radius:10px;overflow:hidden;padding:15px;position:relative;max-width:100%;height:100%;display:flex;flex-direction:column}.chat{display:flex;flex-direction:column;list-style-type:none;padding:0;margin:0;overflow-y:auto;flex:1}.message-helper{background-color:#ffffffe6;box-shadow:0 7px 5px #00000080;position:relative;margin-bottom:30px}.message-helper.right{align-self:flex-end;padding:4px 45px 4px 15px}.message{background-color:#f6f6f6e6;border-radius:50px;box-shadow:7px 11px 14px #00000080;position:relative;margin-bottom:30px}.message .logo{position:absolute;top:50%;transform:translateY(-50%);border-radius:50%}.message .fit-top-image{object-fit:cover;object-position:top}.message.left{padding:10px 15px 10px 45px}.message.left .logo{left:5px}.message.right{align-self:flex-end;padding:10px 45px 10px 15px}.message.right .logo{right:5px}.input-container{margin-top:auto;display:flex;gap:10px;padding-top:15px;background:inherit}.input-container textarea{flex:1;padding:8px;border-radius:20px;border:1px solid #ccc;resize:none}.input-container .send-button{padding:8px 15px;border-radius:20px;border:none;background:#007bff;color:#fff;cursor:pointer}.input-container .send-button:disabled{background:#ccc;cursor:not-allowed}::ng-deep .cdk-overlay-container{z-index:1400}::ng-deep .cdk-global-overlay-wrapper{z-index:1400}::ng-deep .dialog-backdrop{background:#00000080;z-index:1299}\n"] }]
2166
+ args: [{ selector: 'dc-chat', standalone: true, imports: [
2167
+ CommonModule,
2168
+ FormsModule,
2169
+ ChatMessageComponent,
2170
+ ReactiveFormsModule,
2171
+ SkeletonModule,
2172
+ DialogModule,
2173
+ ProgressBarModule,
2174
+ ChatHeaderComponent,
2175
+ ChatFooterComponent,
2176
+ ], providers: [DialogService], template: "<dc-chat-header\n [isAdmin]=\"isAdmin\"\n [alternativeConversation]=\"alternativeConversation\"\n (restartConversationEvent)=\"restartConversation($event || null)\"\n (showInfoEvent)=\"showInfo()\"\n (settingsClickEvent)=\"changeUserChatSettings()\">\n</dc-chat-header>\n\n<main class=\"chat-container\" (touchmove)=\"$event.stopPropagation()\">\n <div class=\"chat\" aria-live=\"polite\">\n @for (message of messages; track message) { @switch (message.role) { @case ('assistant') {\n <div class=\"message left\">\n <img class=\"logo fit-top-image\" [src]=\"agentCard?.assets?.image?.url ?? imageUser\" (click)=\"playMessage(message)\" />\n <dc-chat-message [chatUserSettings]=\"chatUserSettings\" [chatMessage]=\"message\" appTextSelectable> </dc-chat-message>\n </div>\n } @case ('assistantHelper') {\n <div class=\"message-helper right\">\n <dc-chat-message [chatUserSettings]=\"chatUserSettings\" [chatMessage]=\"message\" appTextSelectable> </dc-chat-message>\n </div>\n } @case ('user') {\n <div class=\"message right\">\n <img class=\"logo fit-top-image\" [src]=\"user?.urlPicture || 'assets/defaults/avatar.jpg'\" [alt]=\"'User avatar'\" (click)=\"playMessage(message)\" />\n <dc-chat-message [chatMessage]=\"message\" appTextSelectable> </dc-chat-message>\n </div>\n } } }\n\n <!-- AI thinking indicator -->\n @if (isAIThinking) {\n <div class=\"message message--assistant message--thinking\">\n <span class=\"thinking-emoji\" aria-hidden=\"true\">\uD83E\uDD14</span>\n <div class=\"thinking-indicator\">\n <div class=\"skeleton-container\">\n <p-skeleton width=\"100%\" />\n <br />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n </div>\n }\n\n <!-- User typing or transcribing indicator -->\n @if (isUserTalking || isGettingTranscription) {\n <div class=\"message message--user message--activity\">\n <img class=\"avatar avatar--user\" [src]=\"user?.urlPicture || imageUser\" [alt]=\"'User avatar'\" />\n @if (isUserTalking) {\n <p class=\"typing-indicator\" aria-label=\"User is speaking\">...</p>\n } @if (isGettingTranscription) {\n <i class=\"pi pi-spin pi-spinner-dotted\" aria-label=\"Transcribing speech\"></i>\n }\n </div>\n }\n </div>\n</main>\n\n<dc-chat-footer\n [isAIThinking]=\"isAIThinking\"\n [score]=\"score\"\n [micSettings]=\"micSettings\"\n (sendMessage)=\"sendUserMessage($event)\"\n (textInputChanged)=\"setInputText($event)\"\n (micFinishedEvent)=\"micFinished($event)\">\n</dc-chat-footer>\n\n<!-- Information dialog -->\n<p-dialog\n header=\"Informaci\u00F3n de la conversaci\u00F3n\"\n [(visible)]=\"isInfoVisible\"\n [modal]=\"true\"\n [responsive]=\"true\"\n styleClass=\"conversation-info-dialog\"\n aria-labelledby=\"conversation-info-title\">\n <div class=\"dialog-content\">\n <section class=\"model-info\">\n <h3 id=\"conversation-info-title\" class=\"sr-only\">Informaci\u00F3n de la conversaci\u00F3n</h3>\n <dl class=\"info-list\">\n <dt>Modelo:</dt>\n <dd>{{ chatUserSettings?.model?.provider }} - {{ chatUserSettings?.model?.modelName }}</dd>\n\n <dt>Tipo:</dt>\n <dd>{{ agentCard?.conversationSettings?.conversationType }}</dd>\n\n <dt>Text Engine:</dt>\n <dd>{{ agentCard?.conversationSettings?.textEngine }}</dd>\n\n <dt>Language:</dt>\n <dd>{{ agentCard?.lang }}</dd>\n\n <dt>TTS:</dt>\n <dd>{{ agentCard?.conversationSettings?.tts?.voice }}</dd>\n\n <dt>Secondary TTS:</dt>\n <dd>{{ agentCard?.conversationSettings?.tts?.secondaryVoice }}</dd>\n </dl>\n\n <div class=\"parameters\">\n <h4>Par\u00E1metros:</h4>\n <pre>{{ parseDict | json }}</pre>\n </div>\n </section>\n\n <section class=\"conversation-history\">\n <h4>Conversaci\u00F3n hasta ahora</h4>\n <div class=\"message-history-list\">\n @for (message of conversationSettings.messages; track message) {\n <div class=\"message-history-item\">\n <span class=\"message-role\">{{ message.role }}:</span>\n <span class=\"message-content\">{{ message.content }}</span>\n </div>\n }\n </div>\n </section>\n </div>\n</p-dialog>\n", styles: [":host{display:flex;flex-direction:column;height:100%}*{box-sizing:border-box}.chat-container{border-radius:10px;overflow:hidden;padding:15px;position:relative;max-width:100%;height:100%;display:flex;flex-direction:column}.chat{display:flex;flex-direction:column;list-style-type:none;padding:0;margin:0;overflow-y:auto;flex:1}.logo{width:30px;height:30px}.logo.fit-top-image{object-fit:cover;object-position:top;border-radius:50%}.message{background-color:#f6f6f6f2;border-radius:25px;box-shadow:0 5px 15px #0000001a;position:relative;margin-bottom:20px;transition:all .2s ease}.message .logo{position:absolute;top:50%;transform:translateY(-50%);border-radius:50%;cursor:pointer}.message .logo:hover{transform:translateY(-50%) scale(1.05)}.message.left{padding:12px 15px 12px 45px;margin-right:20%}.message.left .logo{left:5px}.message.right{align-self:flex-end;padding:12px 45px 12px 15px;margin-left:20%;background-color:#e6f0fff2}.message.right .logo{right:5px}.message--thinking,.message--activity{opacity:.7}.message-helper{background-color:#ffffffe6;box-shadow:0 3px 10px #0000001a;position:relative;margin-bottom:20px;border-radius:20px}.message-helper.right{align-self:flex-end;padding:8px 15px;margin-left:20%}.thinking-indicator{padding:5px}.thinking-indicator .skeleton-container{width:200px}::ng-deep .cdk-overlay-container,::ng-deep .cdk-global-overlay-wrapper{z-index:1400}::ng-deep .dialog-backdrop{background:#00000080;z-index:1299}::ng-deep .conversation-info-dialog .dialog-content{max-height:70vh;overflow-y:auto}::ng-deep .conversation-info-dialog .info-list{display:grid;grid-template-columns:auto 1fr;gap:8px;margin-bottom:20px}::ng-deep .conversation-info-dialog .info-list dt{font-weight:700}::ng-deep .conversation-info-dialog .message-history-list{max-height:300px;overflow-y:auto;border:1px solid #eee;border-radius:5px;padding:10px}::ng-deep .conversation-info-dialog .message-history-list .message-history-item{padding:5px 0;border-bottom:1px solid #f0f0f0}::ng-deep .conversation-info-dialog .message-history-list .message-history-item:last-child{border-bottom:none}::ng-deep .conversation-info-dialog .message-history-list .message-history-item .message-role{font-weight:700;margin-right:5px}\n"] }]
1876
2177
  }], ctorParameters: () => [{ type: AgentCardsAbstractService, decorators: [{
1877
2178
  type: Inject,
1878
2179
  args: [CONVERSATION_AI_TOKEN]
1879
- }] }, { type: i6$2.ToastAlertsAbstractService, decorators: [{
2180
+ }] }, { type: i6.ToastAlertsAbstractService, decorators: [{
1880
2181
  type: Inject,
1881
2182
  args: [TOAST_ALERTS_TOKEN]
1882
- }] }, { type: DCConversationPromptBuilderService }, { type: i1$2.DialogService }, { type: i0.ChangeDetectorRef }], propDecorators: { chatUserSettings: [{
2183
+ }] }, { type: DCConversationPromptBuilderService }, { type: i1$3.DialogService }, { type: i0.ChangeDetectorRef }], propDecorators: { chatUserSettings: [{
1883
2184
  type: Input
1884
2185
  }], agentCard: [{
1885
2186
  type: Input
@@ -2030,7 +2331,7 @@ class PromptPreviewDialogComponent {
2030
2331
  close() {
2031
2332
  this.dialogRef.close();
2032
2333
  }
2033
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: PromptPreviewDialogComponent, deps: [{ token: i1$2.DynamicDialogConfig }, { token: i1$2.DynamicDialogRef }], target: i0.ɵɵFactoryTarget.Component }); }
2334
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: PromptPreviewDialogComponent, deps: [{ token: i1$3.DynamicDialogConfig }, { token: i1$3.DynamicDialogRef }], target: i0.ɵɵFactoryTarget.Component }); }
2034
2335
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.1", type: PromptPreviewDialogComponent, isStandalone: true, selector: "dc-prompt-preview-dialog", ngImport: i0, template: ` <div class="prompt-preview-content" [innerHTML]="data.html"></div> `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: DialogModule }] }); }
2035
2336
  }
2036
2337
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: PromptPreviewDialogComponent, decorators: [{
@@ -2041,7 +2342,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImpor
2041
2342
  imports: [CommonModule, DialogModule],
2042
2343
  template: ` <div class="prompt-preview-content" [innerHTML]="data.html"></div> `,
2043
2344
  }]
2044
- }], ctorParameters: () => [{ type: i1$2.DynamicDialogConfig }, { type: i1$2.DynamicDialogRef }] });
2345
+ }], ctorParameters: () => [{ type: i1$3.DynamicDialogConfig }, { type: i1$3.DynamicDialogRef }] });
2045
2346
 
2046
2347
  class TranslateDialogComponent {
2047
2348
  constructor(fb, dialogRef, data) {
@@ -2063,7 +2364,7 @@ class TranslateDialogComponent {
2063
2364
  onConfirm() {
2064
2365
  this.dialogRef.close(this.form.value.targetLang);
2065
2366
  }
2066
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: TranslateDialogComponent, deps: [{ token: i1$1.FormBuilder }, { token: i2$1.DialogRef }, { token: DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component }); }
2367
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: TranslateDialogComponent, deps: [{ token: i1$2.FormBuilder }, { token: i2$1.DialogRef }, { token: DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component }); }
2067
2368
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.1", type: TranslateDialogComponent, isStandalone: true, selector: "dc-translate-dialog", ngImport: i0, template: `
2068
2369
  <div class="translate-dialog">
2069
2370
  <h4>Tu idioma actual es: {{ data.currentLang }}</h4>
@@ -2081,7 +2382,7 @@ class TranslateDialogComponent {
2081
2382
  <button (click)="onConfirm()" [disabled]="!form.value.targetLang"> Translate </button>
2082
2383
  </div>
2083
2384
  </div>
2084
- `, isInline: true, styles: [".translate-dialog{padding:20px;background:#fff;border-radius:8px;box-shadow:0 2px 8px #00000026}.actions{margin-top:20px;display:flex;justify-content:flex-end;gap:10px}select{width:100%;padding:8px;margin-top:10px;border:1px solid #ccc;border-radius:4px}button{padding:8px 16px;border:none;border-radius:4px;cursor:pointer}button:first-child{background:#f0f0f0}button:last-child{background:#007bff;color:#fff}button:disabled{background:#ccc;cursor:not-allowed}h2{margin:0 0 16px;color:#333}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
2385
+ `, isInline: true, styles: [".translate-dialog{padding:20px;background:#fff;border-radius:8px;box-shadow:0 2px 8px #00000026}.actions{margin-top:20px;display:flex;justify-content:flex-end;gap:10px}select{width:100%;padding:8px;margin-top:10px;border:1px solid #ccc;border-radius:4px}button{padding:8px 16px;border:none;border-radius:4px;cursor:pointer}button:first-child{background:#f0f0f0}button:last-child{background:#007bff;color:#fff}button:disabled{background:#ccc;cursor:not-allowed}h2{margin:0 0 16px;color:#333}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
2085
2386
  }
2086
2387
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: TranslateDialogComponent, decorators: [{
2087
2388
  type: Component,
@@ -2103,7 +2404,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImpor
2103
2404
  </div>
2104
2405
  </div>
2105
2406
  `, styles: [".translate-dialog{padding:20px;background:#fff;border-radius:8px;box-shadow:0 2px 8px #00000026}.actions{margin-top:20px;display:flex;justify-content:flex-end;gap:10px}select{width:100%;padding:8px;margin-top:10px;border:1px solid #ccc;border-radius:4px}button{padding:8px 16px;border:none;border-radius:4px;cursor:pointer}button:first-child{background:#f0f0f0}button:last-child{background:#007bff;color:#fff}button:disabled{background:#ccc;cursor:not-allowed}h2{margin:0 0 16px;color:#333}\n"] }]
2106
- }], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: i2$1.DialogRef }, { type: undefined, decorators: [{
2407
+ }], ctorParameters: () => [{ type: i1$2.FormBuilder }, { type: i2$1.DialogRef }, { type: undefined, decorators: [{
2107
2408
  type: Inject,
2108
2409
  args: [DIALOG_DATA]
2109
2410
  }] }] });
@@ -2168,13 +2469,13 @@ class AccountPlatformForm {
2168
2469
  this.toastService.warn(infoToast);
2169
2470
  }
2170
2471
  }
2171
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: AccountPlatformForm, deps: [{ token: i1$3.ActivatedRoute }, { token: i1$1.FormBuilder }, { token: i1$3.Router }, { token: TOAST_ALERTS_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
2172
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: AccountPlatformForm, isStandalone: true, selector: "account-platform-form", inputs: { formArray: "formArray" }, ngImport: i0, template: "<div class=\"source-form-card\">\n <p-card header=\"Cuenta\">\n @for (formAccount of formArray.controls; track formAccount) {\n <form [formGroup]=\"$any(formAccount)\">\n <div class=\"form-field\">\n <label class=\"block\">Platform</label>\n <p-dropdown [options]=\"platformOptions\" formControlName=\"platform\" optionLabel=\"label\" optionValue=\"value\" placeholder=\"Select a platform\"></p-dropdown>\n </div>\n\n <div class=\"form-field\">\n <label for=\"name\" class=\"block\">Username</label>\n <input pInputText id=\"name\" type=\"text\" formControlName=\"name\" placeholder=\"Enter name\" class=\"w-full\" />\n </div>\n\n <div class=\"form-field\">\n <label class=\"block\">Email</label>\n <input pInputText type=\"text\" formControlName=\"email\" placeholder=\"Enter name\" class=\"w-full\" />\n </div>\n </form>\n }\n </p-card>\n</div>\n", styles: [":host{display:block;padding:1rem}.source-form-card{max-width:800px;margin:0 auto}.form-field{margin-bottom:1.5rem;display:flex;flex-direction:column}.form-field label{margin-bottom:.5rem;font-weight:500;color:#495057}.form-field input,.form-field textarea,.form-field ::ng-deep .p-element{margin-top:.25rem}:host ::ng-deep .p-card .p-card-content>div:last-child{margin-top:1.5rem;display:flex;justify-content:flex-end}:host ::ng-deep .p-card .p-card-header{background-color:#f8f9fa;padding:1rem;border-bottom:1px solid #dee2e6}h3{color:#495057;margin-bottom:1.5rem;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i3$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i4$2.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "ngmodule", type: SelectModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5$1.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "ngmodule", type: ChipModule }, { kind: "ngmodule", type: TooltipModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2472
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: AccountPlatformForm, deps: [{ token: i1$4.ActivatedRoute }, { token: i1$2.FormBuilder }, { token: i1$4.Router }, { token: TOAST_ALERTS_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
2473
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: AccountPlatformForm, isStandalone: true, selector: "account-platform-form", inputs: { formArray: "formArray" }, ngImport: i0, template: "<div class=\"source-form-card\">\n <p-card header=\"Cuenta\">\n @for (formAccount of formArray.controls; track formAccount) {\n <form [formGroup]=\"$any(formAccount)\">\n <div class=\"form-field\">\n <label class=\"block\">Platform</label>\n <p-dropdown [options]=\"platformOptions\" formControlName=\"platform\" optionLabel=\"label\" optionValue=\"value\" placeholder=\"Select a platform\"></p-dropdown>\n </div>\n\n <div class=\"form-field\">\n <label for=\"name\" class=\"block\">Username</label>\n <input pInputText id=\"name\" type=\"text\" formControlName=\"name\" placeholder=\"Enter name\" class=\"w-full\" />\n </div>\n\n <div class=\"form-field\">\n <label class=\"block\">Email</label>\n <input pInputText type=\"text\" formControlName=\"email\" placeholder=\"Enter name\" class=\"w-full\" />\n </div>\n </form>\n }\n </p-card>\n</div>\n", styles: [":host{display:block;padding:1rem}.source-form-card{max-width:800px;margin:0 auto}.form-field{margin-bottom:1.5rem;display:flex;flex-direction:column}.form-field label{margin-bottom:.5rem;font-weight:500;color:#495057}.form-field input,.form-field textarea,.form-field ::ng-deep .p-element{margin-top:.25rem}:host ::ng-deep .p-card .p-card-content>div:last-child{margin-top:1.5rem;display:flex;justify-content:flex-end}:host ::ng-deep .p-card .p-card-header{background-color:#f8f9fa;padding:1rem;border-bottom:1px solid #dee2e6}h3{color:#495057;margin-bottom:1.5rem;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i3$2.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i4$3.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "ngmodule", type: SelectModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5$2.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "ngmodule", type: ChipModule }, { kind: "ngmodule", type: TooltipModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2173
2474
  }
2174
2475
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: AccountPlatformForm, decorators: [{
2175
2476
  type: Component,
2176
2477
  args: [{ selector: 'account-platform-form', imports: [ReactiveFormsModule, CardModule, TextareaModule, DropdownModule, ButtonModule, SelectModule, InputTextModule, ChipModule, TooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<div class=\"source-form-card\">\n <p-card header=\"Cuenta\">\n @for (formAccount of formArray.controls; track formAccount) {\n <form [formGroup]=\"$any(formAccount)\">\n <div class=\"form-field\">\n <label class=\"block\">Platform</label>\n <p-dropdown [options]=\"platformOptions\" formControlName=\"platform\" optionLabel=\"label\" optionValue=\"value\" placeholder=\"Select a platform\"></p-dropdown>\n </div>\n\n <div class=\"form-field\">\n <label for=\"name\" class=\"block\">Username</label>\n <input pInputText id=\"name\" type=\"text\" formControlName=\"name\" placeholder=\"Enter name\" class=\"w-full\" />\n </div>\n\n <div class=\"form-field\">\n <label class=\"block\">Email</label>\n <input pInputText type=\"text\" formControlName=\"email\" placeholder=\"Enter name\" class=\"w-full\" />\n </div>\n </form>\n }\n </p-card>\n</div>\n", styles: [":host{display:block;padding:1rem}.source-form-card{max-width:800px;margin:0 auto}.form-field{margin-bottom:1.5rem;display:flex;flex-direction:column}.form-field label{margin-bottom:.5rem;font-weight:500;color:#495057}.form-field input,.form-field textarea,.form-field ::ng-deep .p-element{margin-top:.25rem}:host ::ng-deep .p-card .p-card-content>div:last-child{margin-top:1.5rem;display:flex;justify-content:flex-end}:host ::ng-deep .p-card .p-card-header{background-color:#f8f9fa;padding:1rem;border-bottom:1px solid #dee2e6}h3{color:#495057;margin-bottom:1.5rem;text-align:center}\n"] }]
2177
- }], ctorParameters: () => [{ type: i1$3.ActivatedRoute }, { type: i1$1.FormBuilder }, { type: i1$3.Router }, { type: i6$2.ToastAlertsAbstractService, decorators: [{
2478
+ }], ctorParameters: () => [{ type: i1$4.ActivatedRoute }, { type: i1$2.FormBuilder }, { type: i1$4.Router }, { type: i6.ToastAlertsAbstractService, decorators: [{
2178
2479
  type: Inject,
2179
2480
  args: [TOAST_ALERTS_TOKEN]
2180
2481
  }] }], propDecorators: { formArray: [{
@@ -2208,6 +2509,7 @@ class DCAgentCardFormComponent {
2208
2509
  this.accountsOptions = Object.values(EAccountsPlatform);
2209
2510
  this.languageOptions = Object.entries(LangCodeDescriptionEs).map(([value, label]) => ({ value, label }));
2210
2511
  this.agentCardId = this.activatedRoute.snapshot.paramMap.get('id');
2512
+ this.audioSpeedOptions = Object.values(AudioSpeed$1).map((speed) => ({ label: speed, value: speed }));
2211
2513
  this.storageSettings = this.getSettings();
2212
2514
  this.bannerImgSettings = {
2213
2515
  path: 'conversation-cards/' + this.agentCardId,
@@ -2252,9 +2554,9 @@ class DCAgentCardFormComponent {
2252
2554
  textEngine: [TextEngines.SimpleText],
2253
2555
  conversationType: [ConversationType.General],
2254
2556
  autoStart: [true],
2557
+ tts: this.fb.group({ voice: [''], secondaryVoice: [''], speed: ['1.0'], speedRate: [1.0] }),
2255
2558
  }),
2256
2559
  lang: [''],
2257
- tts: this.fb.group({ voice: [''], secondaryVoice: [''], speed: ['1.0'], speedRate: [1.0] }),
2258
2560
  metaApp: this.fb.group({ isPublished: [false], isPublic: [false], authorId: [''], authorEmail: [''], takenCount: [0] }),
2259
2561
  model: this.fb.group({ id: [''], modelName: [''], provider: [''] }),
2260
2562
  accounts: this.fb.array([]),
@@ -2597,8 +2899,8 @@ class DCAgentCardFormComponent {
2597
2899
  this.toastService.success({ title: 'Sticker removed', subtitle: 'Sticker was removed' });
2598
2900
  this.cdr.detectChanges();
2599
2901
  }
2600
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCAgentCardFormComponent, deps: [{ token: i1$1.FormBuilder }, { token: i2$2.MultiImagesStorageService }, { token: CONVERSATION_AI_TOKEN }, { token: i0.ChangeDetectorRef }, { token: i1$3.Router }, { token: i1$3.ActivatedRoute }, { token: i1$2.DialogService }, { token: DCConversationPromptBuilderService }, { token: TOAST_ALERTS_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
2601
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: DCAgentCardFormComponent, isStandalone: true, selector: "dc-conversation-form", inputs: { storageSettings: "storageSettings", bannerImgSettings: "bannerImgSettings", imageStorageSettings: "imageStorageSettings" }, outputs: { onImageLoaded: "onImageLoaded", onSave: "onSave", onGoDetails: "onGoDetails", onTranslate: "onTranslate" }, providers: [DialogService], ngImport: i0, template: "<div class=\"top-buttons\">\n <button pButton severity=\"info\" (click)=\"checkPrompt()\" label=\"\uD83D\uDC41\uFE0F Ver instrucciones finales \uD83D\uDCD3\"></button>\n\n <button pButton severity=\"info\" (click)=\"goToDetails()\" label=\"\uD83D\uDCAC Conversar\"></button>\n <button pButton severity=\"primary\" (click)=\"saveConversation()\" label=\"\uD83D\uDCBE Guardar cambios\"></button>\n</div>\n\n<div class=\"top-buttons\">\n <p-button severity=\"help\" (click)=\"translate()\" label=\"\uD83D\uDD04 Traducir\"></p-button>\n <p-button [loading]=\"isGenerating\" severity=\"help\" (click)=\"generateCharacter()\" label=\"Generar \uD83E\uDDBE\"></p-button>\n\n <p-button severity=\"info\" (click)=\"downloadConversation()\" label=\"\uD83D\uDCC1 Exportar \u2B07\uFE0F\"></p-button>\n <p-button severity=\"info\" (click)=\"importConversation()\" label=\"\uD83C\uDCCF Importar \u2B06\uFE0F\"></p-button>\n</div>\n\n<br />\n<br />\n<form [formGroup]=\"form\" class=\"conversation-form\">\n <div class=\"form-grid\">\n <div class=\"left-column\">\n <div style=\"display: flex; gap: 15px\">\n <div class=\"form-field\">\n <label for=\"version\">Version: {{ form.controls.version.value }} <span pTooltip=\"Version number of the conversation\">\u2139\uFE0F</span></label>\n </div>\n\n <div class=\"form-field\">\n <label for=\"id\"\n >ID: <span pTooltip=\"Unique identifier for this conversation\"> {{ form.controls.id.value }} \u2139\uFE0F</span></label\n >\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"title\">Title <span pTooltip=\"T\u00EDtulo de la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <input pInputText id=\"title\" type=\"text\" formControlName=\"title\" />\n @if(form.controls.title.errors?.['required'] && form.controls.title.touched){\n <div class=\"error\"> Title is required </div>\n }\n </div>\n\n <div class=\"form-field\">\n <label for=\"lang\">Language <span pTooltip=\"Select the primary language for the conversation\">\u2139\uFE0F</span></label>\n <p-select\n id=\"lang\"\n [options]=\"languageOptions\"\n formControlName=\"lang\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Language'\"></p-select>\n </div>\n\n <div formGroupName=\"conversationSettings\" class=\"group\">\n <h3>Conversation Settings <span pTooltip=\"Additional information about the conversation\">\u2139\uFE0F</span></h3>\n\n <div class=\"form-field\">\n <label for=\"textEngine\">\n Text Engine\n <span\n class=\"cursor-pointer\"\n (click)=\"textEngineDialog.toggle($event)\"\n pTooltip=\"Sistema de generaci\u00F3n de texto y audios. Client: el cliente llama al servidor en cada dialogo de voz/personaje, es optimo para historias, Server SSML: se sintetiza todo el audio en uno solo con los distintos cambios de voz/personaje, util para la reflexi\u00F3n porque es bilingue, utiliza dialogos en ingles y espa\u00F1ol en el mismo dialogo/audio\"\n >\u2139\uFE0F</span\n >\n </label>\n\n <p-select\n id=\"textEngine\"\n [options]=\"textEngineOptions\"\n formControlName=\"textEngine\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Text Engine'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"conversationType\">Conversation Type <span pTooltip=\"Choose the type of conversation interaction\">\u2139\uFE0F</span></label>\n <p-select\n id=\"conversationType\"\n [options]=\"conversationOptions\"\n formControlName=\"conversationType\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Conversation Type'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label> Auto Start <span pTooltip=\"Start conversation automatically\">\u2139\uFE0F</span> </label>\n <p-toggleSwitch formControlName=\"autoStart\"> </p-toggleSwitch>\n </div>\n </div>\n\n <div formGroupName=\"tts\" class=\"group\">\n <h3>TTS Settings <span pTooltip=\"Text-to-Speech configuration options\">\u2139\uFE0F</span></h3>\n\n <div class=\"form-field\">\n <label for=\"voice\">Voice <span pTooltip=\"Select the primary voice for text-to-speech\">\u2139\uFE0F</span></label>\n <p-select\n id=\"voice\"\n [options]=\"voiceTTSOptions\"\n formControlName=\"voice\"\n optionLabel=\"name\"\n optionValue=\"id\"\n [placeholder]=\"'Select Voice'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"secondaryVoice\">Secondary Voice <span pTooltip=\"Select an alternative voice for text-to-speech\">\u2139\uFE0F</span></label>\n <p-select\n id=\"secondaryVoice\"\n [options]=\"voiceTTSOptions\"\n formControlName=\"secondaryVoice\"\n optionLabel=\"name\"\n optionValue=\"id\"\n [placeholder]=\"'Select Secondary Voice'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"speed\">Speed <span pTooltip=\"Set the speech rate for text-to-speech conversion\">\u2139\uFE0F</span></label>\n <input pInputText id=\"speed\" type=\"text\" formControlName=\"speed\" />\n </div>\n\n <div class=\"form-field\">\n <label for=\"speedRate\">Speed Rate <span pTooltip=\"Adjust the rate of speech delivery\">\u2139\uFE0F</span></label>\n <input pInputText id=\"speedRate\" type=\"number\" formControlName=\"speedRate\" step=\"0.1\" />\n </div>\n </div>\n\n <div formGroupName=\"metaApp\" class=\"group\">\n <h3>Meta Information <span pTooltip=\"Additional information about the conversation\">\u2139\uFE0F</span></h3>\n <div class=\"form-field\">\n <label for=\"authorId\">Author ID <span pTooltip=\"Unique identifier for the conversation author\">\u2139\uFE0F</span></label>\n <input pInputText id=\"authorId\" type=\"text\" formControlName=\"authorId\" />\n </div>\n\n <div class=\"form-field\">\n <label for=\"authorEmail\">Author Email \u2139\uFE0F</label>\n <input pInputText id=\"authorEmail\" type=\"email\" formControlName=\"authorEmail\" />\n <div class=\"error\" *ngIf=\"form.get('metaApp.authorEmail')?.errors?.['email'] && form.get('metaApp.authorEmail')?.touched\">\n Please enter a valid email address\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"takenCount\"\n >Taken Count <span pTooltip=\"Es el contador de cuantas veces se ha tomado esta conversaci\u00F3n, no sirve por ahora\"> \u2139\uFE0F</span></label\n >\n <input pInputText id=\"takenCount\" type=\"number\" formControlName=\"takenCount\" />\n </div>\n\n <div class=\"form-field checkbox\">\n <label>\n <p-checkbox [binary]=\"true\" formControlName=\"isPublic\" />\n Public\n </label>\n </div>\n\n <div class=\"form-field checkbox\">\n <label>\n <p-checkbox [binary]=\"true\" formControlName=\"isPublished\" />\n Published\n </label>\n </div>\n </div>\n\n <div class=\"group\">\n <h4>Model Settings <span pTooltip=\"AI model configuration\">\u2139\uFE0F</span></h4>\n\n <dc-provider-selector [parentForm]=\"form.controls.model\"></dc-provider-selector>\n </div>\n\n <div class=\"group\">\n <h4>Gestion de cuentas</h4>\n @if(form.controls.accounts){\n <account-platform-form [formArray]=\"form.controls.accounts\"></account-platform-form>\n\n }\n </div>\n </div>\n\n <div class=\"right-column\">\n <div style=\"position: relative; min-height: 60px\">\n <img [src]=\"conversation?.assets?.bannerImg?.url || 'assets/images/default_banner.webp'\" class=\"main-banner-image-card\" />\n @if(!conversation?.assets?.bannerImg?.url && agentCardId) {\n\n <dc-cropper-modal\n style=\"position: absolute; bottom: 10px; right: 10px\"\n #cropperBanner\n id=\"cropperBanner\"\n [buttonLabel]=\"conversation?.assets?.bannerImg?.url ? 'Cambiar el banner' : 'Cargar un banner'\"\n [imgStorageSettings]=\"bannerImgSettings\"\n [currentStorage]=\"conversation?.assets?.bannerImg\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'bannerImg')\"></dc-cropper-modal>\n\n }\n </div>\n <div style=\"position: relative\">\n <img [src]=\"conversation?.assets?.image?.url || 'assets/images/default_2_3.webp'\" class=\"main-image-card\" />\n @if (!agentCardId) {\n <button pButton (click)=\"saveConversation()\"> Guarda el scenario para subir la imagen</button>\n } @else {\n\n <dc-cropper-modal\n style=\"position: absolute; bottom: 10px; left: 50%\"\n id=\"cropperCardImage\"\n #cropperCardImage\n [buttonLabel]=\"conversation?.assets?.image?.url ? 'Cambiar imagen' : 'Cargar una imagen'\"\n [imgStorageSettings]=\"imageStorageSettings\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'image')\"></dc-cropper-modal>\n }\n </div>\n\n <div>\n <h4>Agregar stickers</h4>\n\n <dc-cropper-modal\n id=\"cropperCardImage\"\n #cropperStickers\n [buttonLabel]=\"'agregar sticker'\"\n [imgStorageSettings]=\"stickerStorageSettings\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'sticker')\"></dc-cropper-modal>\n </div>\n\n <div style=\"display: flex; flex-wrap: wrap; gap: 10px\">\n @for (sticker of conversation?.assets?.stickers; track sticker.url) {\n <div style=\"position: relative\">\n <img width=\"100\" [src]=\"sticker.url\" alt=\"\" />\n <p-button (click)=\"removeSticker(sticker)\" class=\"remove-sticker\" icon=\"pi pi-times\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\" />\n </div>\n }\n </div>\n\n <!-- <input pInputText type=\"file\" accept=\"image/*\" (change)=\"onImageSelected($event)\" /> -->\n\n <div formGroupName=\"characterCard\">\n <div formGroupName=\"data\" class=\"card-group\">\n <h3>Character Card <span pTooltip=\"Informaci\u00F3n de la ficha del personaje\">\u2139\uFE0F</span></h3>\n <div class=\"form-field\">\n <label for=\"cardName\">Name <span pTooltip=\"El nombre del personaje\">\u2139\uFE0F</span></label>\n <input pInputText id=\"cardName\" type=\"text\" formControlName=\"name\" />\n <div class=\"error\" *ngIf=\"form.get('characterCard.data.name')?.errors?.['required'] && form.get('characterCard.data.name')?.touched\">\n Name is required\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardDescription\">Description <span pTooltip=\"Descripci\u00F3n detallada del personaje\">\u2139\uFE0F</span></label>\n <textarea class=\"textmin\" rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardDescription\" formControlName=\"description\"></textarea>\n <div class=\"error\" *ngIf=\"form.get('characterCard.data.description')?.errors?.['required'] && form.get('characterCard.data.description')?.touched\">\n Description is required\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardScenario\">Scenario <span pTooltip=\"Describe the context or setting for the conversation\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardScenario\" formControlName=\"scenario\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardFirstMessage\">\n First Message\n <span pTooltip=\"Es muy importante que la historia inicie bien, ya que es el patr\u00F3n inicial para la AI, respetar las convenciones de texto\"\n >\u2139\uFE0F</span\n >\n\n <p-togglebutton\n [formControl]=\"markdownForm.controls.seeMarkdown\"\n [onLabel]=\"'Editar'\"\n [offLabel]=\"'Ver Markdown Texto'\"\n size=\"small\"\n styleClass=\"min-w-16\"\n (onChange)=\"checkCdr()\" />\n </label>\n\n @if(markdownForm.controls.seeMarkdown.value){\n <div [innerHTML]=\"form.controls.characterCard.controls.data.controls.first_mes.value | mdToHtmlArray\"></div>\n }@else{\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardFirstMessage\" formControlName=\"first_mes\"> </textarea>\n }\n </div>\n\n <div class=\"form-field\">\n <label for=\"mes_example\">Mensajes de Ejemplo <span pTooltip=\"Importante para el estilo de la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"mes_example\" formControlName=\"mes_example\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardCreatorNotes\">Creator Notes <span pTooltip=\"son solo notas del creador, no afecta nada a la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardCreatorNotes\" formControlName=\"creator_notes\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardSystemPrompt\">System Prompt (Opcional) <span pTooltip=\"Instrucciones del sistema para la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardSystemPrompt\" formControlName=\"system_prompt\"></textarea>\n <div\n class=\"error\"\n *ngIf=\"form.get('characterCard.data.system_prompt')?.errors?.['required'] && form.get('characterCard.data.system_prompt')?.touched\">\n System prompt is required\n </div>\n </div>\n\n <div style=\"display: flex; flex-direction: column\">\n <label for=\"cardPostHistoryInstructions\"\n >Post-History Instructions (Opcional)\n <span\n pTooltip=\"Dejar en blanco, al menos que se sepa como funciona, esto se llama jailbreak, es para darle instrucciones finales y m\u00E1s importantes al modelo\"\n >\u2139\uFE0F</span\n ></label\n >\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" formControlName=\"post_history_instructions\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardAlternateGreetings\">Alternate Greetings <span pTooltip=\"Saludos alternativos para comenzar una historia diferente\">\u2139\uFE0F</span></label>\n <div class=\"array-field\">\n <div\n *ngFor=\"let greeting of form.controls.characterCard.controls.data.controls.alternate_greetings.controls; let i = index\"\n class=\"array-item\"\n style=\"position: relative\">\n <textarea\n pTextarea\n rows=\"1\"\n [autoResize]=\"true\"\n [id]=\"'cardAlternateGreeting' + i\"\n [formControl]=\"greeting\"\n (input)=\"updateArrayField('alternate_greetings', i, $event)\">\n </textarea>\n <button pButton severity=\"danger\" class=\"remove-button\" (click)=\"removeArrayItem('alternate_greetings', i)\">&#x2716;</button>\n </div>\n <button pButton severity=\"info\" (click)=\"addArrayItem('alternate_greetings')\">Add Greeting</button>\n </div>\n </div>\n\n <div class=\"form-field\">\n <label pTooltip=\"Agrega las categorias\" for=\"cardTags\">Tags \u2139\uFE0F</label>\n <div class=\"array-field\">\n <div *ngFor=\"let tag of form.controls.characterCard.controls.data.controls.tags.controls; let i = index\" class=\"array-item\">\n <input [id]=\"'cardTag' + i\" type=\"text\" [formControl]=\"tag\" (input)=\"updateArrayField('tags', i, $event)\" />\n <button pButton severity=\"danger\" (click)=\"removeArrayItem('tags', i)\">Remove</button>\n </div>\n <button pButton severity=\"info\" (click)=\"addArrayItem('tags')\">Add Tag</button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</form>\n\n<p-popover #textEngineDialog header=\"Text Engine Information\">\n <div class=\"p-4\">\n <h3>Text Engine Types</h3>\n <ul>\n <li> <strong>Texto Simple</strong> La conversaci\u00F3n es como chatgpt, preguntas y responde, es la m\u00E1s b\u00E1sica</li>\n\n <li\n ><strong>Multi Mensajes</strong> Utiliza markdown (recomendable entenderlo), sirve para darle formato al texto y sea m\u00E1s agradable de leer, el sistema\n puede partir dialogos que tienen distinto formato, como normal, cursiva y negritas, asi puede generar distintas voces y estilo para el narrador y\n personaje principal</li\n >\n <li\n ><strong>MD SSML :</strong> Markdown con Lenguaje de marcaci\u00F3n de s\u00EDntesis de voz (SSML), es tambien markdown pero a diferencia de multimessage, solo se\n presenta un mensaje. y la voz se genera para toda la linea,normalmente lo uso para conversaciones bilingues.</li\n >\n </ul>\n </div>\n</p-popover>\n\n<div class=\"float-button\">\n <p-button icon=\"pi pi-save\" (click)=\"saveConversation()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n", styles: [".textmin{min-width:36vw}.main-image-card{max-width:280px;display:block;margin:0 auto;border-radius:8px}.main-banner-image-card{border-radius:8px}.remove-sticker{position:absolute;top:5px;right:5px}.conversation-form{max-width:100%;padding:20px;background-color:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a}.conversation-form .card-group{background-color:#f8f9fa;padding:20px;border-radius:6px;margin-bottom:24px}.conversation-form .card-group h3{margin:0 0 20px;color:#2c3e50;font-size:1.25rem}.conversation-form .form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2rem;width:100%;max-width:100%}@media (max-width: 768px){.conversation-form .form-grid{grid-template-columns:1fr}}.conversation-form .form-field{margin-bottom:1.5rem;display:flex;flex-direction:column;gap:.5rem}.conversation-form .form-field label{font-weight:500}.conversation-form .form-field textarea{resize:vertical}.conversation-form .form-field.checkbox{flex-direction:row;align-items:center;gap:.5rem}.conversation-form .form-field.checkbox input[type=checkbox]{width:auto}.conversation-form .form-field .error{color:#dc3545;font-size:.875rem;margin-top:.25rem}.conversation-form .form-field .remove-button{position:absolute;border:none;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;cursor:pointer;top:-10px;right:-10px}.conversation-form .left-column,.conversation-form .right-column{display:flex;flex-direction:column;gap:1rem}.conversation-form .array-field{display:flex;flex-direction:column;gap:.5rem}.conversation-form .array-field .array-item{display:flex;gap:.5rem}.conversation-form .array-field .array-item input,.conversation-form .array-field .array-item textarea{flex:1}.conversation-form .array-field .array-item button{padding:.5rem}.conversation-form .array-field button[type=button]{background-color:#28a745;color:#fff;border:none;padding:8px 12px;border-radius:4px;cursor:pointer;transition:background-color .2s}.conversation-form .array-field button[type=button]:hover{background-color:#218838}.conversation-form .group,.conversation-form .meta-group,.conversation-form .card-group{background-color:#f8f9fa;padding:1rem;border-radius:4px;margin-bottom:1.5rem}.conversation-form .group h3,.conversation-form .meta-group h3,.conversation-form .card-group h3{margin-top:0;margin-bottom:1rem}.top-buttons{display:flex;justify-content:space-between;margin-bottom:2rem;gap:1rem}.top-buttons button{flex:1}::ng-deep em{font-weight:900;color:#014a93}.float-button{position:fixed;bottom:4rem;right:2rem;z-index:1000;display:flex;gap:1px}.float-button :host ::ng-deep .p-button{width:4rem;height:4rem;border-radius:50%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "ngmodule", type: PortalModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i7$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "component", type: i7$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i8$1.Textarea, selector: "[pTextarea]", inputs: ["autoResize", "variant", "fluid", "pSize"], outputs: ["onResize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5$1.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$1.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ToggleButtonModule }, { kind: "component", type: i11.ToggleButton, selector: "p-toggleButton, p-togglebutton, p-toggle-button", inputs: ["onLabel", "offLabel", "onIcon", "offIcon", "ariaLabel", "ariaLabelledBy", "disabled", "style", "styleClass", "inputId", "tabindex", "size", "iconPos", "autofocus", "allowEmpty"], outputs: ["onChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "ngmodule", type: ToggleSwitchModule }, { kind: "component", type: i13.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["style", "styleClass", "tabindex", "inputId", "name", "disabled", "readonly", "trueValue", "falseValue", "ariaLabel", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "pipe", type: MdToHtmlArrayPipe, name: "mdToHtmlArray" }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i14.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: DynamicDialogModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i15.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: ProviderSelectorComponent, selector: "dc-provider-selector", inputs: ["parentForm"] }, { kind: "component", type: AccountPlatformForm, selector: "account-platform-form", inputs: ["formArray"] }] }); }
2902
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCAgentCardFormComponent, deps: [{ token: i1$2.FormBuilder }, { token: i2$2.MultiImagesStorageService }, { token: CONVERSATION_AI_TOKEN }, { token: i0.ChangeDetectorRef }, { token: i1$4.Router }, { token: i1$4.ActivatedRoute }, { token: i1$3.DialogService }, { token: DCConversationPromptBuilderService }, { token: TOAST_ALERTS_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
2903
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: DCAgentCardFormComponent, isStandalone: true, selector: "dc-conversation-form", inputs: { storageSettings: "storageSettings", bannerImgSettings: "bannerImgSettings", imageStorageSettings: "imageStorageSettings" }, outputs: { onImageLoaded: "onImageLoaded", onSave: "onSave", onGoDetails: "onGoDetails", onTranslate: "onTranslate" }, providers: [DialogService], ngImport: i0, template: "<div class=\"top-buttons\">\n <button pButton severity=\"info\" (click)=\"checkPrompt()\" label=\"\uD83D\uDC41\uFE0F Ver instrucciones finales \uD83D\uDCD3\"></button>\n\n <button pButton severity=\"info\" (click)=\"goToDetails()\" label=\"\uD83D\uDCAC Conversar\"></button>\n <button pButton severity=\"primary\" (click)=\"saveConversation()\" label=\"\uD83D\uDCBE Guardar cambios\"></button>\n</div>\n\n<div class=\"top-buttons\">\n <p-button severity=\"help\" (click)=\"translate()\" label=\"\uD83D\uDD04 Traducir\"></p-button>\n <p-button [loading]=\"isGenerating\" severity=\"help\" (click)=\"generateCharacter()\" label=\"Generar \uD83E\uDDBE\"></p-button>\n\n <p-button severity=\"info\" (click)=\"downloadConversation()\" label=\"\uD83D\uDCC1 Exportar \u2B07\uFE0F\"></p-button>\n <p-button severity=\"info\" (click)=\"importConversation()\" label=\"\uD83C\uDCCF Importar \u2B06\uFE0F\"></p-button>\n</div>\n\n<br />\n<br />\n<form [formGroup]=\"form\" class=\"conversation-form\">\n <div class=\"form-grid\">\n <div class=\"left-column\">\n <div style=\"display: flex; gap: 15px\">\n <div class=\"form-field\">\n <label for=\"version\">Version: {{ form.controls.version.value }} <span pTooltip=\"Version number of the conversation\">\u2139\uFE0F</span></label>\n </div>\n\n <div class=\"form-field\">\n <label for=\"id\"\n >ID: <span pTooltip=\"Unique identifier for this conversation\"> {{ form.controls.id.value }} \u2139\uFE0F</span></label\n >\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"title\">Title <span pTooltip=\"T\u00EDtulo de la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <input pInputText id=\"title\" type=\"text\" formControlName=\"title\" />\n @if(form.controls.title.errors?.['required'] && form.controls.title.touched){\n <div class=\"error\"> Title is required </div>\n }\n </div>\n\n <div class=\"form-field\">\n <label for=\"lang\">Language <span pTooltip=\"Select the primary language for the conversation\">\u2139\uFE0F</span></label>\n <p-select\n id=\"lang\"\n [options]=\"languageOptions\"\n formControlName=\"lang\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Language'\"></p-select>\n </div>\n\n <div formGroupName=\"conversationSettings\" class=\"group\">\n <h3>Conversation Settings <span pTooltip=\"Additional information about the conversation\">\u2139\uFE0F</span></h3>\n\n <div class=\"form-field\">\n <label for=\"textEngine\">\n Text Engine\n <span\n class=\"cursor-pointer\"\n (click)=\"textEngineDialog.toggle($event)\"\n pTooltip=\"Sistema de generaci\u00F3n de texto y audios. Client: el cliente llama al servidor en cada dialogo de voz/personaje, es optimo para historias, Server SSML: se sintetiza todo el audio en uno solo con los distintos cambios de voz/personaje, util para la reflexi\u00F3n porque es bilingue, utiliza dialogos en ingles y espa\u00F1ol en el mismo dialogo/audio\"\n >\u2139\uFE0F</span\n >\n </label>\n\n <p-select\n id=\"textEngine\"\n [options]=\"textEngineOptions\"\n formControlName=\"textEngine\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Text Engine'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"conversationType\">Conversation Type <span pTooltip=\"Choose the type of conversation interaction\">\u2139\uFE0F</span></label>\n <p-select\n id=\"conversationType\"\n [options]=\"conversationOptions\"\n formControlName=\"conversationType\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Conversation Type'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label> Auto Start <span pTooltip=\"Start conversation automatically\">\u2139\uFE0F</span> </label>\n <p-toggleSwitch formControlName=\"autoStart\"> </p-toggleSwitch>\n </div>\n\n <div formGroupName=\"tts\" class=\"group\">\n <h3>TTS Settings <span pTooltip=\"Text-to-Speech configuration options\">\u2139\uFE0F</span></h3>\n\n <div class=\"form-field\">\n <label for=\"voice\">Voice <span pTooltip=\"Select the primary voice for text-to-speech\">\u2139\uFE0F</span></label>\n <p-select\n id=\"voice\"\n [options]=\"voiceTTSOptions\"\n formControlName=\"voice\"\n optionLabel=\"name\"\n optionValue=\"id\"\n [placeholder]=\"'Select Voice'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"secondaryVoice\">Secondary Voice <span pTooltip=\"Select an alternative voice for text-to-speech\">\u2139\uFE0F</span></label>\n <p-select\n id=\"secondaryVoice\"\n [options]=\"voiceTTSOptions\"\n formControlName=\"secondaryVoice\"\n optionLabel=\"name\"\n optionValue=\"id\"\n [placeholder]=\"'Select Secondary Voice'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"speed\">Speed <span pTooltip=\"Set the speech rate for text-to-speech conversion\">\u2139\uFE0F</span></label>\n <p-select\n id=\"speed\"\n [options]=\"audioSpeedOptions\"\n formControlName=\"speed\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Speed'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"speedRate\">Speed Rate <span pTooltip=\"Adjust the rate of speech delivery\">\u2139\uFE0F</span></label>\n <input pInputText id=\"speedRate\" type=\"number\" formControlName=\"speedRate\" step=\"0.1\" />\n </div>\n </div>\n </div>\n\n <div formGroupName=\"metaApp\" class=\"group\">\n <h3>Meta Information <span pTooltip=\"Additional information about the conversation\">\u2139\uFE0F</span></h3>\n <div class=\"form-field\">\n <label for=\"authorId\">Author ID <span pTooltip=\"Unique identifier for the conversation author\">\u2139\uFE0F</span></label>\n <input pInputText id=\"authorId\" type=\"text\" formControlName=\"authorId\" />\n </div>\n\n <div class=\"form-field\">\n <label for=\"authorEmail\">Author Email \u2139\uFE0F</label>\n <input pInputText id=\"authorEmail\" type=\"email\" formControlName=\"authorEmail\" />\n <div class=\"error\" *ngIf=\"form.get('metaApp.authorEmail')?.errors?.['email'] && form.get('metaApp.authorEmail')?.touched\">\n Please enter a valid email address\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"takenCount\"\n >Taken Count <span pTooltip=\"Es el contador de cuantas veces se ha tomado esta conversaci\u00F3n, no sirve por ahora\"> \u2139\uFE0F</span></label\n >\n <input pInputText id=\"takenCount\" type=\"number\" formControlName=\"takenCount\" />\n </div>\n\n <div class=\"form-field checkbox\">\n <label>\n <p-checkbox [binary]=\"true\" formControlName=\"isPublic\" />\n Public\n </label>\n </div>\n\n <div class=\"form-field checkbox\">\n <label>\n <p-checkbox [binary]=\"true\" formControlName=\"isPublished\" />\n Published\n </label>\n </div>\n </div>\n\n <div class=\"group\">\n <h4>Model Settings <span pTooltip=\"AI model configuration\">\u2139\uFE0F</span></h4>\n\n <dc-provider-selector [parentForm]=\"form.controls.model\"></dc-provider-selector>\n </div>\n\n <div class=\"group\">\n <h4>Gestion de cuentas</h4>\n @if(form.controls.accounts){\n <account-platform-form [formArray]=\"form.controls.accounts\"></account-platform-form>\n\n }\n </div>\n </div>\n\n <div class=\"right-column\">\n <div style=\"position: relative; min-height: 60px\">\n <img [src]=\"conversation?.assets?.bannerImg?.url || 'assets/images/default_banner.webp'\" class=\"main-banner-image-card\" />\n @if(!conversation?.assets?.bannerImg?.url && agentCardId) {\n\n <dc-cropper-modal\n style=\"position: absolute; bottom: 10px; right: 10px\"\n #cropperBanner\n id=\"cropperBanner\"\n [buttonLabel]=\"conversation?.assets?.bannerImg?.url ? 'Cambiar el banner' : 'Cargar un banner'\"\n [imgStorageSettings]=\"bannerImgSettings\"\n [currentStorage]=\"conversation?.assets?.bannerImg\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'bannerImg')\"></dc-cropper-modal>\n\n }\n </div>\n <div style=\"position: relative\">\n <img [src]=\"conversation?.assets?.image?.url || 'assets/images/default_2_3.webp'\" class=\"main-image-card\" />\n @if (!agentCardId) {\n <button pButton (click)=\"saveConversation()\"> Guarda el scenario para subir la imagen</button>\n } @else {\n\n <dc-cropper-modal\n style=\"position: absolute; bottom: 10px; left: 50%\"\n id=\"cropperCardImage\"\n #cropperCardImage\n [buttonLabel]=\"conversation?.assets?.image?.url ? 'Cambiar imagen' : 'Cargar una imagen'\"\n [imgStorageSettings]=\"imageStorageSettings\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'image')\"></dc-cropper-modal>\n }\n </div>\n\n <div>\n <h4>Agregar stickers</h4>\n\n <dc-cropper-modal\n id=\"cropperCardImage\"\n #cropperStickers\n [buttonLabel]=\"'agregar sticker'\"\n [imgStorageSettings]=\"stickerStorageSettings\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'sticker')\"></dc-cropper-modal>\n </div>\n\n <div style=\"display: flex; flex-wrap: wrap; gap: 10px\">\n @for (sticker of conversation?.assets?.stickers; track sticker.url) {\n <div style=\"position: relative\">\n <img width=\"100\" [src]=\"sticker.url\" alt=\"\" />\n <p-button (click)=\"removeSticker(sticker)\" class=\"remove-sticker\" icon=\"pi pi-times\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\" />\n </div>\n }\n </div>\n\n <!-- <input pInputText type=\"file\" accept=\"image/*\" (change)=\"onImageSelected($event)\" /> -->\n\n <div formGroupName=\"characterCard\">\n <div formGroupName=\"data\" class=\"card-group\">\n <h3>Character Card <span pTooltip=\"Informaci\u00F3n de la ficha del personaje\">\u2139\uFE0F</span></h3>\n <div class=\"form-field\">\n <label for=\"cardName\">Name <span pTooltip=\"El nombre del personaje\">\u2139\uFE0F</span></label>\n <input pInputText id=\"cardName\" type=\"text\" formControlName=\"name\" />\n <div class=\"error\" *ngIf=\"form.get('characterCard.data.name')?.errors?.['required'] && form.get('characterCard.data.name')?.touched\">\n Name is required\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardDescription\">Description <span pTooltip=\"Descripci\u00F3n detallada del personaje\">\u2139\uFE0F</span></label>\n <textarea class=\"textmin\" rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardDescription\" formControlName=\"description\"></textarea>\n <div class=\"error\" *ngIf=\"form.get('characterCard.data.description')?.errors?.['required'] && form.get('characterCard.data.description')?.touched\">\n Description is required\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardScenario\">Scenario <span pTooltip=\"Describe the context or setting for the conversation\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardScenario\" formControlName=\"scenario\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardFirstMessage\">\n First Message\n <span pTooltip=\"Es muy importante que la historia inicie bien, ya que es el patr\u00F3n inicial para la AI, respetar las convenciones de texto\"\n >\u2139\uFE0F</span\n >\n\n <p-togglebutton\n [formControl]=\"markdownForm.controls.seeMarkdown\"\n [onLabel]=\"'Editar'\"\n [offLabel]=\"'Ver Markdown Texto'\"\n size=\"small\"\n styleClass=\"min-w-16\"\n (onChange)=\"checkCdr()\" />\n </label>\n\n @if(markdownForm.controls.seeMarkdown.value){\n <div [innerHTML]=\"form.controls.characterCard.controls.data.controls.first_mes.value | mdToHtmlArray\"></div>\n }@else{\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardFirstMessage\" formControlName=\"first_mes\"> </textarea>\n }\n </div>\n\n <div class=\"form-field\">\n <label for=\"mes_example\">Mensajes de Ejemplo <span pTooltip=\"Importante para el estilo de la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"mes_example\" formControlName=\"mes_example\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardCreatorNotes\">Creator Notes <span pTooltip=\"son solo notas del creador, no afecta nada a la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardCreatorNotes\" formControlName=\"creator_notes\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardSystemPrompt\">System Prompt (Opcional) <span pTooltip=\"Instrucciones del sistema para la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardSystemPrompt\" formControlName=\"system_prompt\"></textarea>\n <div\n class=\"error\"\n *ngIf=\"form.get('characterCard.data.system_prompt')?.errors?.['required'] && form.get('characterCard.data.system_prompt')?.touched\">\n System prompt is required\n </div>\n </div>\n\n <div style=\"display: flex; flex-direction: column\">\n <label for=\"cardPostHistoryInstructions\"\n >Post-History Instructions (Opcional)\n <span\n pTooltip=\"Dejar en blanco, al menos que se sepa como funciona, esto se llama jailbreak, es para darle instrucciones finales y m\u00E1s importantes al modelo\"\n >\u2139\uFE0F</span\n ></label\n >\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" formControlName=\"post_history_instructions\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardAlternateGreetings\">Alternate Greetings <span pTooltip=\"Saludos alternativos para comenzar una historia diferente\">\u2139\uFE0F</span></label>\n <div class=\"array-field\">\n <div\n *ngFor=\"let greeting of form.controls.characterCard.controls.data.controls.alternate_greetings.controls; let i = index\"\n class=\"array-item\"\n style=\"position: relative\">\n <textarea\n pTextarea\n rows=\"1\"\n [autoResize]=\"true\"\n [id]=\"'cardAlternateGreeting' + i\"\n [formControl]=\"greeting\"\n (input)=\"updateArrayField('alternate_greetings', i, $event)\">\n </textarea>\n <button pButton severity=\"danger\" class=\"remove-button\" (click)=\"removeArrayItem('alternate_greetings', i)\">&#x2716;</button>\n </div>\n <button pButton severity=\"info\" (click)=\"addArrayItem('alternate_greetings')\">Add Greeting</button>\n </div>\n </div>\n\n <div class=\"form-field\">\n <label pTooltip=\"Agrega las categorias\" for=\"cardTags\">Tags \u2139\uFE0F</label>\n <div class=\"array-field\">\n <div *ngFor=\"let tag of form.controls.characterCard.controls.data.controls.tags.controls; let i = index\" class=\"array-item\">\n <input [id]=\"'cardTag' + i\" type=\"text\" [formControl]=\"tag\" (input)=\"updateArrayField('tags', i, $event)\" />\n <button pButton severity=\"danger\" (click)=\"removeArrayItem('tags', i)\">Remove</button>\n </div>\n <button pButton severity=\"info\" (click)=\"addArrayItem('tags')\">Add Tag</button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</form>\n\n<p-popover #textEngineDialog header=\"Text Engine Information\">\n <div class=\"p-4\">\n <h3>Text Engine Types</h3>\n <ul>\n <li> <strong>Texto Simple</strong> La conversaci\u00F3n es como chatgpt, preguntas y responde, es la m\u00E1s b\u00E1sica</li>\n\n <li\n ><strong>Multi Mensajes</strong> Utiliza markdown (recomendable entenderlo), sirve para darle formato al texto y sea m\u00E1s agradable de leer, el sistema\n puede partir dialogos que tienen distinto formato, como normal, cursiva y negritas, asi puede generar distintas voces y estilo para el narrador y\n personaje principal</li\n >\n <li\n ><strong>MD SSML :</strong> Markdown con Lenguaje de marcaci\u00F3n de s\u00EDntesis de voz (SSML), es tambien markdown pero a diferencia de multimessage, solo se\n presenta un mensaje. y la voz se genera para toda la linea,normalmente lo uso para conversaciones bilingues.</li\n >\n </ul>\n </div>\n</p-popover>\n\n<div class=\"float-button\">\n <p-button icon=\"pi pi-save\" (click)=\"saveConversation()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n", styles: [".textmin{min-width:36vw}.main-image-card{max-width:280px;display:block;margin:0 auto;border-radius:8px}.main-banner-image-card{border-radius:8px}.remove-sticker{position:absolute;top:5px;right:5px}.conversation-form{max-width:100%;padding:20px;background-color:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a}.conversation-form .card-group{background-color:#f8f9fa;padding:20px;border-radius:6px;margin-bottom:24px}.conversation-form .card-group h3{margin:0 0 20px;color:#2c3e50;font-size:1.25rem}.conversation-form .form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2rem;width:100%;max-width:100%}@media (max-width: 768px){.conversation-form .form-grid{grid-template-columns:1fr}}.conversation-form .form-field{margin-bottom:1.5rem;display:flex;flex-direction:column;gap:.5rem}.conversation-form .form-field label{font-weight:500}.conversation-form .form-field textarea{resize:vertical}.conversation-form .form-field.checkbox{flex-direction:row;align-items:center;gap:.5rem}.conversation-form .form-field.checkbox input[type=checkbox]{width:auto}.conversation-form .form-field .error{color:#dc3545;font-size:.875rem;margin-top:.25rem}.conversation-form .form-field .remove-button{position:absolute;border:none;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;cursor:pointer;top:-10px;right:-10px}.conversation-form .left-column,.conversation-form .right-column{display:flex;flex-direction:column;gap:1rem}.conversation-form .array-field{display:flex;flex-direction:column;gap:.5rem}.conversation-form .array-field .array-item{display:flex;gap:.5rem}.conversation-form .array-field .array-item input,.conversation-form .array-field .array-item textarea{flex:1}.conversation-form .array-field .array-item button{padding:.5rem}.conversation-form .array-field button[type=button]{background-color:#28a745;color:#fff;border:none;padding:8px 12px;border-radius:4px;cursor:pointer;transition:background-color .2s}.conversation-form .array-field button[type=button]:hover{background-color:#218838}.conversation-form .group,.conversation-form .meta-group,.conversation-form .card-group{background-color:#f8f9fa;padding:1rem;border-radius:4px;margin-bottom:1.5rem}.conversation-form .group h3,.conversation-form .meta-group h3,.conversation-form .card-group h3{margin-top:0;margin-bottom:1rem}.top-buttons{display:flex;justify-content:space-between;margin-bottom:2rem;gap:1rem}.top-buttons button{flex:1}::ng-deep em{font-weight:900;color:#014a93}.float-button{position:fixed;bottom:4rem;right:2rem;z-index:1000;display:flex;gap:1px}.float-button :host ::ng-deep .p-button{width:4rem;height:4rem;border-radius:50%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "ngmodule", type: PortalModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i7.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "component", type: i7.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i3.Textarea, selector: "[pTextarea]", inputs: ["autoResize", "variant", "fluid", "pSize"], outputs: ["onResize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5$2.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$2.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ToggleButtonModule }, { kind: "component", type: i11.ToggleButton, selector: "p-toggleButton, p-togglebutton, p-toggle-button", inputs: ["onLabel", "offLabel", "onIcon", "offIcon", "ariaLabel", "ariaLabelledBy", "disabled", "style", "styleClass", "inputId", "tabindex", "size", "iconPos", "autofocus", "allowEmpty"], outputs: ["onChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7$1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "ngmodule", type: ToggleSwitchModule }, { kind: "component", type: i13.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["style", "styleClass", "tabindex", "inputId", "name", "disabled", "readonly", "trueValue", "falseValue", "ariaLabel", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "pipe", type: MdToHtmlArrayPipe, name: "mdToHtmlArray" }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i14.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: DynamicDialogModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i15.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: ProviderSelectorComponent, selector: "dc-provider-selector", inputs: ["parentForm"] }, { kind: "component", type: AccountPlatformForm, selector: "account-platform-form", inputs: ["formArray"] }] }); }
2602
2904
  }
2603
2905
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCAgentCardFormComponent, decorators: [{
2604
2906
  type: Component,
@@ -2623,11 +2925,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImpor
2623
2925
  PopoverModule,
2624
2926
  ProviderSelectorComponent,
2625
2927
  AccountPlatformForm,
2626
- ], template: "<div class=\"top-buttons\">\n <button pButton severity=\"info\" (click)=\"checkPrompt()\" label=\"\uD83D\uDC41\uFE0F Ver instrucciones finales \uD83D\uDCD3\"></button>\n\n <button pButton severity=\"info\" (click)=\"goToDetails()\" label=\"\uD83D\uDCAC Conversar\"></button>\n <button pButton severity=\"primary\" (click)=\"saveConversation()\" label=\"\uD83D\uDCBE Guardar cambios\"></button>\n</div>\n\n<div class=\"top-buttons\">\n <p-button severity=\"help\" (click)=\"translate()\" label=\"\uD83D\uDD04 Traducir\"></p-button>\n <p-button [loading]=\"isGenerating\" severity=\"help\" (click)=\"generateCharacter()\" label=\"Generar \uD83E\uDDBE\"></p-button>\n\n <p-button severity=\"info\" (click)=\"downloadConversation()\" label=\"\uD83D\uDCC1 Exportar \u2B07\uFE0F\"></p-button>\n <p-button severity=\"info\" (click)=\"importConversation()\" label=\"\uD83C\uDCCF Importar \u2B06\uFE0F\"></p-button>\n</div>\n\n<br />\n<br />\n<form [formGroup]=\"form\" class=\"conversation-form\">\n <div class=\"form-grid\">\n <div class=\"left-column\">\n <div style=\"display: flex; gap: 15px\">\n <div class=\"form-field\">\n <label for=\"version\">Version: {{ form.controls.version.value }} <span pTooltip=\"Version number of the conversation\">\u2139\uFE0F</span></label>\n </div>\n\n <div class=\"form-field\">\n <label for=\"id\"\n >ID: <span pTooltip=\"Unique identifier for this conversation\"> {{ form.controls.id.value }} \u2139\uFE0F</span></label\n >\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"title\">Title <span pTooltip=\"T\u00EDtulo de la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <input pInputText id=\"title\" type=\"text\" formControlName=\"title\" />\n @if(form.controls.title.errors?.['required'] && form.controls.title.touched){\n <div class=\"error\"> Title is required </div>\n }\n </div>\n\n <div class=\"form-field\">\n <label for=\"lang\">Language <span pTooltip=\"Select the primary language for the conversation\">\u2139\uFE0F</span></label>\n <p-select\n id=\"lang\"\n [options]=\"languageOptions\"\n formControlName=\"lang\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Language'\"></p-select>\n </div>\n\n <div formGroupName=\"conversationSettings\" class=\"group\">\n <h3>Conversation Settings <span pTooltip=\"Additional information about the conversation\">\u2139\uFE0F</span></h3>\n\n <div class=\"form-field\">\n <label for=\"textEngine\">\n Text Engine\n <span\n class=\"cursor-pointer\"\n (click)=\"textEngineDialog.toggle($event)\"\n pTooltip=\"Sistema de generaci\u00F3n de texto y audios. Client: el cliente llama al servidor en cada dialogo de voz/personaje, es optimo para historias, Server SSML: se sintetiza todo el audio en uno solo con los distintos cambios de voz/personaje, util para la reflexi\u00F3n porque es bilingue, utiliza dialogos en ingles y espa\u00F1ol en el mismo dialogo/audio\"\n >\u2139\uFE0F</span\n >\n </label>\n\n <p-select\n id=\"textEngine\"\n [options]=\"textEngineOptions\"\n formControlName=\"textEngine\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Text Engine'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"conversationType\">Conversation Type <span pTooltip=\"Choose the type of conversation interaction\">\u2139\uFE0F</span></label>\n <p-select\n id=\"conversationType\"\n [options]=\"conversationOptions\"\n formControlName=\"conversationType\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Conversation Type'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label> Auto Start <span pTooltip=\"Start conversation automatically\">\u2139\uFE0F</span> </label>\n <p-toggleSwitch formControlName=\"autoStart\"> </p-toggleSwitch>\n </div>\n </div>\n\n <div formGroupName=\"tts\" class=\"group\">\n <h3>TTS Settings <span pTooltip=\"Text-to-Speech configuration options\">\u2139\uFE0F</span></h3>\n\n <div class=\"form-field\">\n <label for=\"voice\">Voice <span pTooltip=\"Select the primary voice for text-to-speech\">\u2139\uFE0F</span></label>\n <p-select\n id=\"voice\"\n [options]=\"voiceTTSOptions\"\n formControlName=\"voice\"\n optionLabel=\"name\"\n optionValue=\"id\"\n [placeholder]=\"'Select Voice'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"secondaryVoice\">Secondary Voice <span pTooltip=\"Select an alternative voice for text-to-speech\">\u2139\uFE0F</span></label>\n <p-select\n id=\"secondaryVoice\"\n [options]=\"voiceTTSOptions\"\n formControlName=\"secondaryVoice\"\n optionLabel=\"name\"\n optionValue=\"id\"\n [placeholder]=\"'Select Secondary Voice'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"speed\">Speed <span pTooltip=\"Set the speech rate for text-to-speech conversion\">\u2139\uFE0F</span></label>\n <input pInputText id=\"speed\" type=\"text\" formControlName=\"speed\" />\n </div>\n\n <div class=\"form-field\">\n <label for=\"speedRate\">Speed Rate <span pTooltip=\"Adjust the rate of speech delivery\">\u2139\uFE0F</span></label>\n <input pInputText id=\"speedRate\" type=\"number\" formControlName=\"speedRate\" step=\"0.1\" />\n </div>\n </div>\n\n <div formGroupName=\"metaApp\" class=\"group\">\n <h3>Meta Information <span pTooltip=\"Additional information about the conversation\">\u2139\uFE0F</span></h3>\n <div class=\"form-field\">\n <label for=\"authorId\">Author ID <span pTooltip=\"Unique identifier for the conversation author\">\u2139\uFE0F</span></label>\n <input pInputText id=\"authorId\" type=\"text\" formControlName=\"authorId\" />\n </div>\n\n <div class=\"form-field\">\n <label for=\"authorEmail\">Author Email \u2139\uFE0F</label>\n <input pInputText id=\"authorEmail\" type=\"email\" formControlName=\"authorEmail\" />\n <div class=\"error\" *ngIf=\"form.get('metaApp.authorEmail')?.errors?.['email'] && form.get('metaApp.authorEmail')?.touched\">\n Please enter a valid email address\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"takenCount\"\n >Taken Count <span pTooltip=\"Es el contador de cuantas veces se ha tomado esta conversaci\u00F3n, no sirve por ahora\"> \u2139\uFE0F</span></label\n >\n <input pInputText id=\"takenCount\" type=\"number\" formControlName=\"takenCount\" />\n </div>\n\n <div class=\"form-field checkbox\">\n <label>\n <p-checkbox [binary]=\"true\" formControlName=\"isPublic\" />\n Public\n </label>\n </div>\n\n <div class=\"form-field checkbox\">\n <label>\n <p-checkbox [binary]=\"true\" formControlName=\"isPublished\" />\n Published\n </label>\n </div>\n </div>\n\n <div class=\"group\">\n <h4>Model Settings <span pTooltip=\"AI model configuration\">\u2139\uFE0F</span></h4>\n\n <dc-provider-selector [parentForm]=\"form.controls.model\"></dc-provider-selector>\n </div>\n\n <div class=\"group\">\n <h4>Gestion de cuentas</h4>\n @if(form.controls.accounts){\n <account-platform-form [formArray]=\"form.controls.accounts\"></account-platform-form>\n\n }\n </div>\n </div>\n\n <div class=\"right-column\">\n <div style=\"position: relative; min-height: 60px\">\n <img [src]=\"conversation?.assets?.bannerImg?.url || 'assets/images/default_banner.webp'\" class=\"main-banner-image-card\" />\n @if(!conversation?.assets?.bannerImg?.url && agentCardId) {\n\n <dc-cropper-modal\n style=\"position: absolute; bottom: 10px; right: 10px\"\n #cropperBanner\n id=\"cropperBanner\"\n [buttonLabel]=\"conversation?.assets?.bannerImg?.url ? 'Cambiar el banner' : 'Cargar un banner'\"\n [imgStorageSettings]=\"bannerImgSettings\"\n [currentStorage]=\"conversation?.assets?.bannerImg\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'bannerImg')\"></dc-cropper-modal>\n\n }\n </div>\n <div style=\"position: relative\">\n <img [src]=\"conversation?.assets?.image?.url || 'assets/images/default_2_3.webp'\" class=\"main-image-card\" />\n @if (!agentCardId) {\n <button pButton (click)=\"saveConversation()\"> Guarda el scenario para subir la imagen</button>\n } @else {\n\n <dc-cropper-modal\n style=\"position: absolute; bottom: 10px; left: 50%\"\n id=\"cropperCardImage\"\n #cropperCardImage\n [buttonLabel]=\"conversation?.assets?.image?.url ? 'Cambiar imagen' : 'Cargar una imagen'\"\n [imgStorageSettings]=\"imageStorageSettings\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'image')\"></dc-cropper-modal>\n }\n </div>\n\n <div>\n <h4>Agregar stickers</h4>\n\n <dc-cropper-modal\n id=\"cropperCardImage\"\n #cropperStickers\n [buttonLabel]=\"'agregar sticker'\"\n [imgStorageSettings]=\"stickerStorageSettings\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'sticker')\"></dc-cropper-modal>\n </div>\n\n <div style=\"display: flex; flex-wrap: wrap; gap: 10px\">\n @for (sticker of conversation?.assets?.stickers; track sticker.url) {\n <div style=\"position: relative\">\n <img width=\"100\" [src]=\"sticker.url\" alt=\"\" />\n <p-button (click)=\"removeSticker(sticker)\" class=\"remove-sticker\" icon=\"pi pi-times\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\" />\n </div>\n }\n </div>\n\n <!-- <input pInputText type=\"file\" accept=\"image/*\" (change)=\"onImageSelected($event)\" /> -->\n\n <div formGroupName=\"characterCard\">\n <div formGroupName=\"data\" class=\"card-group\">\n <h3>Character Card <span pTooltip=\"Informaci\u00F3n de la ficha del personaje\">\u2139\uFE0F</span></h3>\n <div class=\"form-field\">\n <label for=\"cardName\">Name <span pTooltip=\"El nombre del personaje\">\u2139\uFE0F</span></label>\n <input pInputText id=\"cardName\" type=\"text\" formControlName=\"name\" />\n <div class=\"error\" *ngIf=\"form.get('characterCard.data.name')?.errors?.['required'] && form.get('characterCard.data.name')?.touched\">\n Name is required\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardDescription\">Description <span pTooltip=\"Descripci\u00F3n detallada del personaje\">\u2139\uFE0F</span></label>\n <textarea class=\"textmin\" rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardDescription\" formControlName=\"description\"></textarea>\n <div class=\"error\" *ngIf=\"form.get('characterCard.data.description')?.errors?.['required'] && form.get('characterCard.data.description')?.touched\">\n Description is required\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardScenario\">Scenario <span pTooltip=\"Describe the context or setting for the conversation\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardScenario\" formControlName=\"scenario\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardFirstMessage\">\n First Message\n <span pTooltip=\"Es muy importante que la historia inicie bien, ya que es el patr\u00F3n inicial para la AI, respetar las convenciones de texto\"\n >\u2139\uFE0F</span\n >\n\n <p-togglebutton\n [formControl]=\"markdownForm.controls.seeMarkdown\"\n [onLabel]=\"'Editar'\"\n [offLabel]=\"'Ver Markdown Texto'\"\n size=\"small\"\n styleClass=\"min-w-16\"\n (onChange)=\"checkCdr()\" />\n </label>\n\n @if(markdownForm.controls.seeMarkdown.value){\n <div [innerHTML]=\"form.controls.characterCard.controls.data.controls.first_mes.value | mdToHtmlArray\"></div>\n }@else{\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardFirstMessage\" formControlName=\"first_mes\"> </textarea>\n }\n </div>\n\n <div class=\"form-field\">\n <label for=\"mes_example\">Mensajes de Ejemplo <span pTooltip=\"Importante para el estilo de la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"mes_example\" formControlName=\"mes_example\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardCreatorNotes\">Creator Notes <span pTooltip=\"son solo notas del creador, no afecta nada a la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardCreatorNotes\" formControlName=\"creator_notes\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardSystemPrompt\">System Prompt (Opcional) <span pTooltip=\"Instrucciones del sistema para la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardSystemPrompt\" formControlName=\"system_prompt\"></textarea>\n <div\n class=\"error\"\n *ngIf=\"form.get('characterCard.data.system_prompt')?.errors?.['required'] && form.get('characterCard.data.system_prompt')?.touched\">\n System prompt is required\n </div>\n </div>\n\n <div style=\"display: flex; flex-direction: column\">\n <label for=\"cardPostHistoryInstructions\"\n >Post-History Instructions (Opcional)\n <span\n pTooltip=\"Dejar en blanco, al menos que se sepa como funciona, esto se llama jailbreak, es para darle instrucciones finales y m\u00E1s importantes al modelo\"\n >\u2139\uFE0F</span\n ></label\n >\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" formControlName=\"post_history_instructions\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardAlternateGreetings\">Alternate Greetings <span pTooltip=\"Saludos alternativos para comenzar una historia diferente\">\u2139\uFE0F</span></label>\n <div class=\"array-field\">\n <div\n *ngFor=\"let greeting of form.controls.characterCard.controls.data.controls.alternate_greetings.controls; let i = index\"\n class=\"array-item\"\n style=\"position: relative\">\n <textarea\n pTextarea\n rows=\"1\"\n [autoResize]=\"true\"\n [id]=\"'cardAlternateGreeting' + i\"\n [formControl]=\"greeting\"\n (input)=\"updateArrayField('alternate_greetings', i, $event)\">\n </textarea>\n <button pButton severity=\"danger\" class=\"remove-button\" (click)=\"removeArrayItem('alternate_greetings', i)\">&#x2716;</button>\n </div>\n <button pButton severity=\"info\" (click)=\"addArrayItem('alternate_greetings')\">Add Greeting</button>\n </div>\n </div>\n\n <div class=\"form-field\">\n <label pTooltip=\"Agrega las categorias\" for=\"cardTags\">Tags \u2139\uFE0F</label>\n <div class=\"array-field\">\n <div *ngFor=\"let tag of form.controls.characterCard.controls.data.controls.tags.controls; let i = index\" class=\"array-item\">\n <input [id]=\"'cardTag' + i\" type=\"text\" [formControl]=\"tag\" (input)=\"updateArrayField('tags', i, $event)\" />\n <button pButton severity=\"danger\" (click)=\"removeArrayItem('tags', i)\">Remove</button>\n </div>\n <button pButton severity=\"info\" (click)=\"addArrayItem('tags')\">Add Tag</button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</form>\n\n<p-popover #textEngineDialog header=\"Text Engine Information\">\n <div class=\"p-4\">\n <h3>Text Engine Types</h3>\n <ul>\n <li> <strong>Texto Simple</strong> La conversaci\u00F3n es como chatgpt, preguntas y responde, es la m\u00E1s b\u00E1sica</li>\n\n <li\n ><strong>Multi Mensajes</strong> Utiliza markdown (recomendable entenderlo), sirve para darle formato al texto y sea m\u00E1s agradable de leer, el sistema\n puede partir dialogos que tienen distinto formato, como normal, cursiva y negritas, asi puede generar distintas voces y estilo para el narrador y\n personaje principal</li\n >\n <li\n ><strong>MD SSML :</strong> Markdown con Lenguaje de marcaci\u00F3n de s\u00EDntesis de voz (SSML), es tambien markdown pero a diferencia de multimessage, solo se\n presenta un mensaje. y la voz se genera para toda la linea,normalmente lo uso para conversaciones bilingues.</li\n >\n </ul>\n </div>\n</p-popover>\n\n<div class=\"float-button\">\n <p-button icon=\"pi pi-save\" (click)=\"saveConversation()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n", styles: [".textmin{min-width:36vw}.main-image-card{max-width:280px;display:block;margin:0 auto;border-radius:8px}.main-banner-image-card{border-radius:8px}.remove-sticker{position:absolute;top:5px;right:5px}.conversation-form{max-width:100%;padding:20px;background-color:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a}.conversation-form .card-group{background-color:#f8f9fa;padding:20px;border-radius:6px;margin-bottom:24px}.conversation-form .card-group h3{margin:0 0 20px;color:#2c3e50;font-size:1.25rem}.conversation-form .form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2rem;width:100%;max-width:100%}@media (max-width: 768px){.conversation-form .form-grid{grid-template-columns:1fr}}.conversation-form .form-field{margin-bottom:1.5rem;display:flex;flex-direction:column;gap:.5rem}.conversation-form .form-field label{font-weight:500}.conversation-form .form-field textarea{resize:vertical}.conversation-form .form-field.checkbox{flex-direction:row;align-items:center;gap:.5rem}.conversation-form .form-field.checkbox input[type=checkbox]{width:auto}.conversation-form .form-field .error{color:#dc3545;font-size:.875rem;margin-top:.25rem}.conversation-form .form-field .remove-button{position:absolute;border:none;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;cursor:pointer;top:-10px;right:-10px}.conversation-form .left-column,.conversation-form .right-column{display:flex;flex-direction:column;gap:1rem}.conversation-form .array-field{display:flex;flex-direction:column;gap:.5rem}.conversation-form .array-field .array-item{display:flex;gap:.5rem}.conversation-form .array-field .array-item input,.conversation-form .array-field .array-item textarea{flex:1}.conversation-form .array-field .array-item button{padding:.5rem}.conversation-form .array-field button[type=button]{background-color:#28a745;color:#fff;border:none;padding:8px 12px;border-radius:4px;cursor:pointer;transition:background-color .2s}.conversation-form .array-field button[type=button]:hover{background-color:#218838}.conversation-form .group,.conversation-form .meta-group,.conversation-form .card-group{background-color:#f8f9fa;padding:1rem;border-radius:4px;margin-bottom:1.5rem}.conversation-form .group h3,.conversation-form .meta-group h3,.conversation-form .card-group h3{margin-top:0;margin-bottom:1rem}.top-buttons{display:flex;justify-content:space-between;margin-bottom:2rem;gap:1rem}.top-buttons button{flex:1}::ng-deep em{font-weight:900;color:#014a93}.float-button{position:fixed;bottom:4rem;right:2rem;z-index:1000;display:flex;gap:1px}.float-button :host ::ng-deep .p-button{width:4rem;height:4rem;border-radius:50%}\n"] }]
2627
- }], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: i2$2.MultiImagesStorageService }, { type: AgentCardsAbstractService, decorators: [{
2928
+ ], template: "<div class=\"top-buttons\">\n <button pButton severity=\"info\" (click)=\"checkPrompt()\" label=\"\uD83D\uDC41\uFE0F Ver instrucciones finales \uD83D\uDCD3\"></button>\n\n <button pButton severity=\"info\" (click)=\"goToDetails()\" label=\"\uD83D\uDCAC Conversar\"></button>\n <button pButton severity=\"primary\" (click)=\"saveConversation()\" label=\"\uD83D\uDCBE Guardar cambios\"></button>\n</div>\n\n<div class=\"top-buttons\">\n <p-button severity=\"help\" (click)=\"translate()\" label=\"\uD83D\uDD04 Traducir\"></p-button>\n <p-button [loading]=\"isGenerating\" severity=\"help\" (click)=\"generateCharacter()\" label=\"Generar \uD83E\uDDBE\"></p-button>\n\n <p-button severity=\"info\" (click)=\"downloadConversation()\" label=\"\uD83D\uDCC1 Exportar \u2B07\uFE0F\"></p-button>\n <p-button severity=\"info\" (click)=\"importConversation()\" label=\"\uD83C\uDCCF Importar \u2B06\uFE0F\"></p-button>\n</div>\n\n<br />\n<br />\n<form [formGroup]=\"form\" class=\"conversation-form\">\n <div class=\"form-grid\">\n <div class=\"left-column\">\n <div style=\"display: flex; gap: 15px\">\n <div class=\"form-field\">\n <label for=\"version\">Version: {{ form.controls.version.value }} <span pTooltip=\"Version number of the conversation\">\u2139\uFE0F</span></label>\n </div>\n\n <div class=\"form-field\">\n <label for=\"id\"\n >ID: <span pTooltip=\"Unique identifier for this conversation\"> {{ form.controls.id.value }} \u2139\uFE0F</span></label\n >\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"title\">Title <span pTooltip=\"T\u00EDtulo de la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <input pInputText id=\"title\" type=\"text\" formControlName=\"title\" />\n @if(form.controls.title.errors?.['required'] && form.controls.title.touched){\n <div class=\"error\"> Title is required </div>\n }\n </div>\n\n <div class=\"form-field\">\n <label for=\"lang\">Language <span pTooltip=\"Select the primary language for the conversation\">\u2139\uFE0F</span></label>\n <p-select\n id=\"lang\"\n [options]=\"languageOptions\"\n formControlName=\"lang\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Language'\"></p-select>\n </div>\n\n <div formGroupName=\"conversationSettings\" class=\"group\">\n <h3>Conversation Settings <span pTooltip=\"Additional information about the conversation\">\u2139\uFE0F</span></h3>\n\n <div class=\"form-field\">\n <label for=\"textEngine\">\n Text Engine\n <span\n class=\"cursor-pointer\"\n (click)=\"textEngineDialog.toggle($event)\"\n pTooltip=\"Sistema de generaci\u00F3n de texto y audios. Client: el cliente llama al servidor en cada dialogo de voz/personaje, es optimo para historias, Server SSML: se sintetiza todo el audio en uno solo con los distintos cambios de voz/personaje, util para la reflexi\u00F3n porque es bilingue, utiliza dialogos en ingles y espa\u00F1ol en el mismo dialogo/audio\"\n >\u2139\uFE0F</span\n >\n </label>\n\n <p-select\n id=\"textEngine\"\n [options]=\"textEngineOptions\"\n formControlName=\"textEngine\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Text Engine'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"conversationType\">Conversation Type <span pTooltip=\"Choose the type of conversation interaction\">\u2139\uFE0F</span></label>\n <p-select\n id=\"conversationType\"\n [options]=\"conversationOptions\"\n formControlName=\"conversationType\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Conversation Type'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label> Auto Start <span pTooltip=\"Start conversation automatically\">\u2139\uFE0F</span> </label>\n <p-toggleSwitch formControlName=\"autoStart\"> </p-toggleSwitch>\n </div>\n\n <div formGroupName=\"tts\" class=\"group\">\n <h3>TTS Settings <span pTooltip=\"Text-to-Speech configuration options\">\u2139\uFE0F</span></h3>\n\n <div class=\"form-field\">\n <label for=\"voice\">Voice <span pTooltip=\"Select the primary voice for text-to-speech\">\u2139\uFE0F</span></label>\n <p-select\n id=\"voice\"\n [options]=\"voiceTTSOptions\"\n formControlName=\"voice\"\n optionLabel=\"name\"\n optionValue=\"id\"\n [placeholder]=\"'Select Voice'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"secondaryVoice\">Secondary Voice <span pTooltip=\"Select an alternative voice for text-to-speech\">\u2139\uFE0F</span></label>\n <p-select\n id=\"secondaryVoice\"\n [options]=\"voiceTTSOptions\"\n formControlName=\"secondaryVoice\"\n optionLabel=\"name\"\n optionValue=\"id\"\n [placeholder]=\"'Select Secondary Voice'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"speed\">Speed <span pTooltip=\"Set the speech rate for text-to-speech conversion\">\u2139\uFE0F</span></label>\n <p-select\n id=\"speed\"\n [options]=\"audioSpeedOptions\"\n formControlName=\"speed\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Speed'\"></p-select>\n </div>\n\n <div class=\"form-field\">\n <label for=\"speedRate\">Speed Rate <span pTooltip=\"Adjust the rate of speech delivery\">\u2139\uFE0F</span></label>\n <input pInputText id=\"speedRate\" type=\"number\" formControlName=\"speedRate\" step=\"0.1\" />\n </div>\n </div>\n </div>\n\n <div formGroupName=\"metaApp\" class=\"group\">\n <h3>Meta Information <span pTooltip=\"Additional information about the conversation\">\u2139\uFE0F</span></h3>\n <div class=\"form-field\">\n <label for=\"authorId\">Author ID <span pTooltip=\"Unique identifier for the conversation author\">\u2139\uFE0F</span></label>\n <input pInputText id=\"authorId\" type=\"text\" formControlName=\"authorId\" />\n </div>\n\n <div class=\"form-field\">\n <label for=\"authorEmail\">Author Email \u2139\uFE0F</label>\n <input pInputText id=\"authorEmail\" type=\"email\" formControlName=\"authorEmail\" />\n <div class=\"error\" *ngIf=\"form.get('metaApp.authorEmail')?.errors?.['email'] && form.get('metaApp.authorEmail')?.touched\">\n Please enter a valid email address\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"takenCount\"\n >Taken Count <span pTooltip=\"Es el contador de cuantas veces se ha tomado esta conversaci\u00F3n, no sirve por ahora\"> \u2139\uFE0F</span></label\n >\n <input pInputText id=\"takenCount\" type=\"number\" formControlName=\"takenCount\" />\n </div>\n\n <div class=\"form-field checkbox\">\n <label>\n <p-checkbox [binary]=\"true\" formControlName=\"isPublic\" />\n Public\n </label>\n </div>\n\n <div class=\"form-field checkbox\">\n <label>\n <p-checkbox [binary]=\"true\" formControlName=\"isPublished\" />\n Published\n </label>\n </div>\n </div>\n\n <div class=\"group\">\n <h4>Model Settings <span pTooltip=\"AI model configuration\">\u2139\uFE0F</span></h4>\n\n <dc-provider-selector [parentForm]=\"form.controls.model\"></dc-provider-selector>\n </div>\n\n <div class=\"group\">\n <h4>Gestion de cuentas</h4>\n @if(form.controls.accounts){\n <account-platform-form [formArray]=\"form.controls.accounts\"></account-platform-form>\n\n }\n </div>\n </div>\n\n <div class=\"right-column\">\n <div style=\"position: relative; min-height: 60px\">\n <img [src]=\"conversation?.assets?.bannerImg?.url || 'assets/images/default_banner.webp'\" class=\"main-banner-image-card\" />\n @if(!conversation?.assets?.bannerImg?.url && agentCardId) {\n\n <dc-cropper-modal\n style=\"position: absolute; bottom: 10px; right: 10px\"\n #cropperBanner\n id=\"cropperBanner\"\n [buttonLabel]=\"conversation?.assets?.bannerImg?.url ? 'Cambiar el banner' : 'Cargar un banner'\"\n [imgStorageSettings]=\"bannerImgSettings\"\n [currentStorage]=\"conversation?.assets?.bannerImg\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'bannerImg')\"></dc-cropper-modal>\n\n }\n </div>\n <div style=\"position: relative\">\n <img [src]=\"conversation?.assets?.image?.url || 'assets/images/default_2_3.webp'\" class=\"main-image-card\" />\n @if (!agentCardId) {\n <button pButton (click)=\"saveConversation()\"> Guarda el scenario para subir la imagen</button>\n } @else {\n\n <dc-cropper-modal\n style=\"position: absolute; bottom: 10px; left: 50%\"\n id=\"cropperCardImage\"\n #cropperCardImage\n [buttonLabel]=\"conversation?.assets?.image?.url ? 'Cambiar imagen' : 'Cargar una imagen'\"\n [imgStorageSettings]=\"imageStorageSettings\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'image')\"></dc-cropper-modal>\n }\n </div>\n\n <div>\n <h4>Agregar stickers</h4>\n\n <dc-cropper-modal\n id=\"cropperCardImage\"\n #cropperStickers\n [buttonLabel]=\"'agregar sticker'\"\n [imgStorageSettings]=\"stickerStorageSettings\"\n (onFileSelected)=\"onImageSelected($event)\"\n (imageUploaded)=\"onImageUploaded($event, 'sticker')\"></dc-cropper-modal>\n </div>\n\n <div style=\"display: flex; flex-wrap: wrap; gap: 10px\">\n @for (sticker of conversation?.assets?.stickers; track sticker.url) {\n <div style=\"position: relative\">\n <img width=\"100\" [src]=\"sticker.url\" alt=\"\" />\n <p-button (click)=\"removeSticker(sticker)\" class=\"remove-sticker\" icon=\"pi pi-times\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\" />\n </div>\n }\n </div>\n\n <!-- <input pInputText type=\"file\" accept=\"image/*\" (change)=\"onImageSelected($event)\" /> -->\n\n <div formGroupName=\"characterCard\">\n <div formGroupName=\"data\" class=\"card-group\">\n <h3>Character Card <span pTooltip=\"Informaci\u00F3n de la ficha del personaje\">\u2139\uFE0F</span></h3>\n <div class=\"form-field\">\n <label for=\"cardName\">Name <span pTooltip=\"El nombre del personaje\">\u2139\uFE0F</span></label>\n <input pInputText id=\"cardName\" type=\"text\" formControlName=\"name\" />\n <div class=\"error\" *ngIf=\"form.get('characterCard.data.name')?.errors?.['required'] && form.get('characterCard.data.name')?.touched\">\n Name is required\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardDescription\">Description <span pTooltip=\"Descripci\u00F3n detallada del personaje\">\u2139\uFE0F</span></label>\n <textarea class=\"textmin\" rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardDescription\" formControlName=\"description\"></textarea>\n <div class=\"error\" *ngIf=\"form.get('characterCard.data.description')?.errors?.['required'] && form.get('characterCard.data.description')?.touched\">\n Description is required\n </div>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardScenario\">Scenario <span pTooltip=\"Describe the context or setting for the conversation\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardScenario\" formControlName=\"scenario\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardFirstMessage\">\n First Message\n <span pTooltip=\"Es muy importante que la historia inicie bien, ya que es el patr\u00F3n inicial para la AI, respetar las convenciones de texto\"\n >\u2139\uFE0F</span\n >\n\n <p-togglebutton\n [formControl]=\"markdownForm.controls.seeMarkdown\"\n [onLabel]=\"'Editar'\"\n [offLabel]=\"'Ver Markdown Texto'\"\n size=\"small\"\n styleClass=\"min-w-16\"\n (onChange)=\"checkCdr()\" />\n </label>\n\n @if(markdownForm.controls.seeMarkdown.value){\n <div [innerHTML]=\"form.controls.characterCard.controls.data.controls.first_mes.value | mdToHtmlArray\"></div>\n }@else{\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardFirstMessage\" formControlName=\"first_mes\"> </textarea>\n }\n </div>\n\n <div class=\"form-field\">\n <label for=\"mes_example\">Mensajes de Ejemplo <span pTooltip=\"Importante para el estilo de la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"mes_example\" formControlName=\"mes_example\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardCreatorNotes\">Creator Notes <span pTooltip=\"son solo notas del creador, no afecta nada a la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardCreatorNotes\" formControlName=\"creator_notes\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardSystemPrompt\">System Prompt (Opcional) <span pTooltip=\"Instrucciones del sistema para la conversaci\u00F3n\">\u2139\uFE0F</span></label>\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" id=\"cardSystemPrompt\" formControlName=\"system_prompt\"></textarea>\n <div\n class=\"error\"\n *ngIf=\"form.get('characterCard.data.system_prompt')?.errors?.['required'] && form.get('characterCard.data.system_prompt')?.touched\">\n System prompt is required\n </div>\n </div>\n\n <div style=\"display: flex; flex-direction: column\">\n <label for=\"cardPostHistoryInstructions\"\n >Post-History Instructions (Opcional)\n <span\n pTooltip=\"Dejar en blanco, al menos que se sepa como funciona, esto se llama jailbreak, es para darle instrucciones finales y m\u00E1s importantes al modelo\"\n >\u2139\uFE0F</span\n ></label\n >\n <textarea rows=\"1\" pTextarea [autoResize]=\"true\" formControlName=\"post_history_instructions\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label for=\"cardAlternateGreetings\">Alternate Greetings <span pTooltip=\"Saludos alternativos para comenzar una historia diferente\">\u2139\uFE0F</span></label>\n <div class=\"array-field\">\n <div\n *ngFor=\"let greeting of form.controls.characterCard.controls.data.controls.alternate_greetings.controls; let i = index\"\n class=\"array-item\"\n style=\"position: relative\">\n <textarea\n pTextarea\n rows=\"1\"\n [autoResize]=\"true\"\n [id]=\"'cardAlternateGreeting' + i\"\n [formControl]=\"greeting\"\n (input)=\"updateArrayField('alternate_greetings', i, $event)\">\n </textarea>\n <button pButton severity=\"danger\" class=\"remove-button\" (click)=\"removeArrayItem('alternate_greetings', i)\">&#x2716;</button>\n </div>\n <button pButton severity=\"info\" (click)=\"addArrayItem('alternate_greetings')\">Add Greeting</button>\n </div>\n </div>\n\n <div class=\"form-field\">\n <label pTooltip=\"Agrega las categorias\" for=\"cardTags\">Tags \u2139\uFE0F</label>\n <div class=\"array-field\">\n <div *ngFor=\"let tag of form.controls.characterCard.controls.data.controls.tags.controls; let i = index\" class=\"array-item\">\n <input [id]=\"'cardTag' + i\" type=\"text\" [formControl]=\"tag\" (input)=\"updateArrayField('tags', i, $event)\" />\n <button pButton severity=\"danger\" (click)=\"removeArrayItem('tags', i)\">Remove</button>\n </div>\n <button pButton severity=\"info\" (click)=\"addArrayItem('tags')\">Add Tag</button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</form>\n\n<p-popover #textEngineDialog header=\"Text Engine Information\">\n <div class=\"p-4\">\n <h3>Text Engine Types</h3>\n <ul>\n <li> <strong>Texto Simple</strong> La conversaci\u00F3n es como chatgpt, preguntas y responde, es la m\u00E1s b\u00E1sica</li>\n\n <li\n ><strong>Multi Mensajes</strong> Utiliza markdown (recomendable entenderlo), sirve para darle formato al texto y sea m\u00E1s agradable de leer, el sistema\n puede partir dialogos que tienen distinto formato, como normal, cursiva y negritas, asi puede generar distintas voces y estilo para el narrador y\n personaje principal</li\n >\n <li\n ><strong>MD SSML :</strong> Markdown con Lenguaje de marcaci\u00F3n de s\u00EDntesis de voz (SSML), es tambien markdown pero a diferencia de multimessage, solo se\n presenta un mensaje. y la voz se genera para toda la linea,normalmente lo uso para conversaciones bilingues.</li\n >\n </ul>\n </div>\n</p-popover>\n\n<div class=\"float-button\">\n <p-button icon=\"pi pi-save\" (click)=\"saveConversation()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n", styles: [".textmin{min-width:36vw}.main-image-card{max-width:280px;display:block;margin:0 auto;border-radius:8px}.main-banner-image-card{border-radius:8px}.remove-sticker{position:absolute;top:5px;right:5px}.conversation-form{max-width:100%;padding:20px;background-color:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a}.conversation-form .card-group{background-color:#f8f9fa;padding:20px;border-radius:6px;margin-bottom:24px}.conversation-form .card-group h3{margin:0 0 20px;color:#2c3e50;font-size:1.25rem}.conversation-form .form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2rem;width:100%;max-width:100%}@media (max-width: 768px){.conversation-form .form-grid{grid-template-columns:1fr}}.conversation-form .form-field{margin-bottom:1.5rem;display:flex;flex-direction:column;gap:.5rem}.conversation-form .form-field label{font-weight:500}.conversation-form .form-field textarea{resize:vertical}.conversation-form .form-field.checkbox{flex-direction:row;align-items:center;gap:.5rem}.conversation-form .form-field.checkbox input[type=checkbox]{width:auto}.conversation-form .form-field .error{color:#dc3545;font-size:.875rem;margin-top:.25rem}.conversation-form .form-field .remove-button{position:absolute;border:none;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;cursor:pointer;top:-10px;right:-10px}.conversation-form .left-column,.conversation-form .right-column{display:flex;flex-direction:column;gap:1rem}.conversation-form .array-field{display:flex;flex-direction:column;gap:.5rem}.conversation-form .array-field .array-item{display:flex;gap:.5rem}.conversation-form .array-field .array-item input,.conversation-form .array-field .array-item textarea{flex:1}.conversation-form .array-field .array-item button{padding:.5rem}.conversation-form .array-field button[type=button]{background-color:#28a745;color:#fff;border:none;padding:8px 12px;border-radius:4px;cursor:pointer;transition:background-color .2s}.conversation-form .array-field button[type=button]:hover{background-color:#218838}.conversation-form .group,.conversation-form .meta-group,.conversation-form .card-group{background-color:#f8f9fa;padding:1rem;border-radius:4px;margin-bottom:1.5rem}.conversation-form .group h3,.conversation-form .meta-group h3,.conversation-form .card-group h3{margin-top:0;margin-bottom:1rem}.top-buttons{display:flex;justify-content:space-between;margin-bottom:2rem;gap:1rem}.top-buttons button{flex:1}::ng-deep em{font-weight:900;color:#014a93}.float-button{position:fixed;bottom:4rem;right:2rem;z-index:1000;display:flex;gap:1px}.float-button :host ::ng-deep .p-button{width:4rem;height:4rem;border-radius:50%}\n"] }]
2929
+ }], ctorParameters: () => [{ type: i1$2.FormBuilder }, { type: i2$2.MultiImagesStorageService }, { type: AgentCardsAbstractService, decorators: [{
2628
2930
  type: Inject,
2629
2931
  args: [CONVERSATION_AI_TOKEN]
2630
- }] }, { type: i0.ChangeDetectorRef }, { type: i1$3.Router }, { type: i1$3.ActivatedRoute }, { type: i1$2.DialogService }, { type: DCConversationPromptBuilderService }, { type: i6$2.ToastAlertsAbstractService, decorators: [{
2932
+ }] }, { type: i0.ChangeDetectorRef }, { type: i1$4.Router }, { type: i1$4.ActivatedRoute }, { type: i1$3.DialogService }, { type: DCConversationPromptBuilderService }, { type: i6.ToastAlertsAbstractService, decorators: [{
2631
2933
  type: Optional
2632
2934
  }, {
2633
2935
  type: Inject,
@@ -2655,6 +2957,7 @@ class DCConversationCardUIComponent {
2655
2957
  { label: 'Delete', icon: 'pi pi-trash', title: 'delete', severity: 'danger', command: () => this.onDelete() },
2656
2958
  { label: 'Select', icon: 'pi pi-check', title: 'select', severity: 'success', command: () => this.onDetails() },
2657
2959
  ];
2960
+ this.showOptions = true;
2658
2961
  this.onCardAction = new EventEmitter();
2659
2962
  }
2660
2963
  ngOnInit() {
@@ -2672,13 +2975,15 @@ class DCConversationCardUIComponent {
2672
2975
  this.onCardAction.emit({ event: 'delete', card: this.card });
2673
2976
  }
2674
2977
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCConversationCardUIComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2675
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.1", type: DCConversationCardUIComponent, isStandalone: true, selector: "dc-agent-card-default-ui", inputs: { card: "card" }, outputs: { onCardAction: "onCardAction" }, ngImport: i0, template: "<p-card class=\"card-image\">\n <div style=\"position: absolute; top: 5px; right: 5px; z-index: 1000\">\n <p-speeddial\n [model]=\"speedDialModel\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true, raised: true }\" />\n </div>\n\n <img [src]=\"card?.assets?.image?.url || 'assets/images/default_conversation_card.webp'\" alt=\"\" />\n\n <div (click)=\"onDetails()\" class=\"content\">\n <h2 class=\"title-text\">{{ card.title }}</h2>\n\n <h5 class=\"title\">\n <span [innerHTML]=\"card.characterCard?.data.description | truncate : 100\"></span>\n </h5>\n\n <p-button\n (click)=\"onDetails()\"\n [style]=\"{ position: 'absolute', bottom: '10px', right: '10px' }\"\n icon=\"pi pi-comment\"\n [rounded]=\"true\"\n severity=\"info\"\n [outlined]=\"true\"\n [raised]=\"true\" />\n </div>\n</p-card>\n", styles: [":host{display:block}:host ::ng-deep .p-card{height:100%}:host ::ng-deep .p-card-body{height:100%;padding:0!important}.card-image{width:280px;height:380px;position:relative;align-items:center;display:block;padding:-10px}.card-image img{position:absolute;z-index:3;width:100%;height:100%;opacity:.75;object-fit:cover;transition:opacity .5s}.content{position:absolute;inset:0;z-index:4;padding:1.5rem;color:#fff;background:linear-gradient(to bottom,#0003,#0000001a);height:100%;display:flex;flex-direction:column}.content:hover{background:linear-gradient(to bottom,color-mix(in srgb,var(--p-primary-color) 20%,transparent),color-mix(in srgb,black 10%,transparent));cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: PopoverModule }, { kind: "pipe", type: TruncatePipe, name: "truncate" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i7$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SpeedDialModule }, { kind: "component", type: i2$3.SpeedDial, selector: "p-speeddial, p-speedDial, p-speed-dial", inputs: ["id", "model", "visible", "style", "className", "direction", "transitionDelay", "type", "radius", "mask", "disabled", "hideOnClickOutside", "buttonStyle", "buttonClassName", "maskStyle", "maskClassName", "showIcon", "hideIcon", "rotateAnimation", "ariaLabel", "ariaLabelledBy", "tooltipOptions", "buttonProps"], outputs: ["onVisibleChange", "visibleChange", "onClick", "onShow", "onHide"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i3$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2978
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: DCConversationCardUIComponent, isStandalone: true, selector: "dc-agent-card-default-ui", inputs: { card: "card", showOptions: "showOptions" }, outputs: { onCardAction: "onCardAction" }, ngImport: i0, template: "<p-card class=\"card-image\">\n @if(showOptions) {\n <div style=\"position: absolute; top: 5px; right: 5px; z-index: 1000\">\n <p-speeddial\n [model]=\"speedDialModel\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true, raised: true }\" />\n </div>\n }\n\n <img [src]=\"card?.assets?.image?.url || 'assets/images/default_conversation_card.webp'\" alt=\"\" />\n\n <div (click)=\"onDetails()\" class=\"content\">\n <h2 class=\"title-text\">{{ card.title }}</h2>\n\n <h5 class=\"title\">\n <span [innerHTML]=\"card.characterCard?.data.description | truncate : 100\"></span>\n </h5>\n\n <p-button\n (click)=\"onDetails()\"\n [style]=\"{ position: 'absolute', bottom: '10px', right: '10px' }\"\n icon=\"pi pi-comment\"\n [rounded]=\"true\"\n severity=\"info\"\n [outlined]=\"true\"\n [raised]=\"true\" />\n </div>\n</p-card>\n", styles: [":host{display:block}:host ::ng-deep .p-card{height:100%}:host ::ng-deep .p-card-body{height:100%;padding:0!important}.card-image{width:280px;height:380px;position:relative;align-items:center;display:block;padding:-10px}.card-image img{position:absolute;z-index:3;width:100%;height:100%;opacity:.75;object-fit:cover;transition:opacity .5s}.content{position:absolute;inset:0;z-index:4;padding:1.5rem;color:#fff;background:linear-gradient(to bottom,#0003,#0000001a);height:100%;display:flex;flex-direction:column}.content:hover{background:linear-gradient(to bottom,color-mix(in srgb,var(--p-primary-color) 20%,transparent),color-mix(in srgb,black 10%,transparent));cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: PopoverModule }, { kind: "pipe", type: TruncatePipe, name: "truncate" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i7.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SpeedDialModule }, { kind: "component", type: i2$3.SpeedDial, selector: "p-speeddial, p-speedDial, p-speed-dial", inputs: ["id", "model", "visible", "style", "className", "direction", "transitionDelay", "type", "radius", "mask", "disabled", "hideOnClickOutside", "buttonStyle", "buttonClassName", "maskStyle", "maskClassName", "showIcon", "hideIcon", "rotateAnimation", "ariaLabel", "ariaLabelledBy", "tooltipOptions", "buttonProps"], outputs: ["onVisibleChange", "visibleChange", "onClick", "onShow", "onHide"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i3$2.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2676
2979
  }
2677
2980
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCConversationCardUIComponent, decorators: [{
2678
2981
  type: Component,
2679
- args: [{ selector: 'dc-agent-card-default-ui', imports: [PopoverModule, TruncatePipe, ButtonModule, SpeedDialModule, CardModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p-card class=\"card-image\">\n <div style=\"position: absolute; top: 5px; right: 5px; z-index: 1000\">\n <p-speeddial\n [model]=\"speedDialModel\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true, raised: true }\" />\n </div>\n\n <img [src]=\"card?.assets?.image?.url || 'assets/images/default_conversation_card.webp'\" alt=\"\" />\n\n <div (click)=\"onDetails()\" class=\"content\">\n <h2 class=\"title-text\">{{ card.title }}</h2>\n\n <h5 class=\"title\">\n <span [innerHTML]=\"card.characterCard?.data.description | truncate : 100\"></span>\n </h5>\n\n <p-button\n (click)=\"onDetails()\"\n [style]=\"{ position: 'absolute', bottom: '10px', right: '10px' }\"\n icon=\"pi pi-comment\"\n [rounded]=\"true\"\n severity=\"info\"\n [outlined]=\"true\"\n [raised]=\"true\" />\n </div>\n</p-card>\n", styles: [":host{display:block}:host ::ng-deep .p-card{height:100%}:host ::ng-deep .p-card-body{height:100%;padding:0!important}.card-image{width:280px;height:380px;position:relative;align-items:center;display:block;padding:-10px}.card-image img{position:absolute;z-index:3;width:100%;height:100%;opacity:.75;object-fit:cover;transition:opacity .5s}.content{position:absolute;inset:0;z-index:4;padding:1.5rem;color:#fff;background:linear-gradient(to bottom,#0003,#0000001a);height:100%;display:flex;flex-direction:column}.content:hover{background:linear-gradient(to bottom,color-mix(in srgb,var(--p-primary-color) 20%,transparent),color-mix(in srgb,black 10%,transparent));cursor:pointer}\n"] }]
2982
+ args: [{ selector: 'dc-agent-card-default-ui', imports: [PopoverModule, TruncatePipe, ButtonModule, SpeedDialModule, CardModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p-card class=\"card-image\">\n @if(showOptions) {\n <div style=\"position: absolute; top: 5px; right: 5px; z-index: 1000\">\n <p-speeddial\n [model]=\"speedDialModel\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true, raised: true }\" />\n </div>\n }\n\n <img [src]=\"card?.assets?.image?.url || 'assets/images/default_conversation_card.webp'\" alt=\"\" />\n\n <div (click)=\"onDetails()\" class=\"content\">\n <h2 class=\"title-text\">{{ card.title }}</h2>\n\n <h5 class=\"title\">\n <span [innerHTML]=\"card.characterCard?.data.description | truncate : 100\"></span>\n </h5>\n\n <p-button\n (click)=\"onDetails()\"\n [style]=\"{ position: 'absolute', bottom: '10px', right: '10px' }\"\n icon=\"pi pi-comment\"\n [rounded]=\"true\"\n severity=\"info\"\n [outlined]=\"true\"\n [raised]=\"true\" />\n </div>\n</p-card>\n", styles: [":host{display:block}:host ::ng-deep .p-card{height:100%}:host ::ng-deep .p-card-body{height:100%;padding:0!important}.card-image{width:280px;height:380px;position:relative;align-items:center;display:block;padding:-10px}.card-image img{position:absolute;z-index:3;width:100%;height:100%;opacity:.75;object-fit:cover;transition:opacity .5s}.content{position:absolute;inset:0;z-index:4;padding:1.5rem;color:#fff;background:linear-gradient(to bottom,#0003,#0000001a);height:100%;display:flex;flex-direction:column}.content:hover{background:linear-gradient(to bottom,color-mix(in srgb,var(--p-primary-color) 20%,transparent),color-mix(in srgb,black 10%,transparent));cursor:pointer}\n"] }]
2680
2983
  }], propDecorators: { card: [{
2681
2984
  type: Input
2985
+ }], showOptions: [{
2986
+ type: Input
2682
2987
  }], onCardAction: [{
2683
2988
  type: Output
2684
2989
  }] } });
@@ -2698,6 +3003,7 @@ class AgentCardListComponent extends PaginationBase {
2698
3003
  this.toastService = toastService;
2699
3004
  this.cdr = cdr;
2700
3005
  this.viewMode = 'cards';
3006
+ this.showOptions = true;
2701
3007
  this.gridLayout = true;
2702
3008
  this.agentCards = [];
2703
3009
  this.cardEventSubs = [];
@@ -2814,8 +3120,8 @@ class AgentCardListComponent extends PaginationBase {
2814
3120
  this.doAction(actionEvent); // handle by father.
2815
3121
  }
2816
3122
  }
2817
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: AgentCardListComponent, deps: [{ token: CONVERSATION_AI_TOKEN }, { token: TOAST_ALERTS_TOKEN }, { token: i1$3.ActivatedRoute }, { token: i1$3.Router }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2818
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: AgentCardListComponent, isStandalone: true, selector: "dc-agent-card-lists", inputs: { viewMode: "viewMode", customCardComponent: "customCardComponent", gridLayout: "gridLayout", getCustomButtons: "getCustomButtons" }, viewQueries: [{ propertyName: "outlets", predicate: ["outlet"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<dc-filter-bar [isAdmin]=\"true\" (onAction)=\"doFilterBarAction($event)\" (onSearch)=\"search($event)\" (onFilterChange)=\"filterChange($event)\"></dc-filter-bar>\n\n@if(viewMode === 'table'){\n<app-quick-table [columns]=\"columns\" [tableData]=\"agentCards\" [actions]=\"actions\" (onAction)=\"onCardAction($event)\"></app-quick-table>\n\n}@else{\n\n<div class=\"conversation-card-lists\">\n @if(!isLoading) {\n <div [ngClass]=\"{ 'cards-container': gridLayout }\">\n @for (card of agentCards; track card) {\n <div style=\"position: relative\">\n <ng-container #outlet=\"ngComponentOutlet\" [ngComponentOutlet]=\"cardComponent\" [ngComponentOutletInputs]=\"{ card: card }\"> </ng-container>\n </div>\n }\n </div>\n }\n</div>\n\n@if(isLoading) {\n<div>\n <p-skeleton styleClass=\"mb-2\" />\n <p-skeleton width=\"10rem\" styleClass=\"mb-2\" />\n <p-skeleton width=\"5rem\" styleClass=\"mb-2\" />\n <p-skeleton height=\"2rem\" styleClass=\"mb-2\" />\n <p-skeleton width=\"10rem\" height=\"4rem\" />\n</div>\n} @if(agentCards.length === 0) {\n<div>\n <p>No conversations found or no connection with server</p>\n</div>\n} }\n\n<p-paginator\n currentPageReportTemplate=\"{{ totalRecords }} conversations\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [first]=\"paginatorFirst\"\n [rows]=\"paginatorRows\"\n [totalRecords]=\"totalRecords\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n</p-paginator>\n", styles: [":host{display:block;height:100%}.options-icon{cursor:pointer;position:absolute;top:2px;right:3px;font-size:1.2rem;color:#dde9e9;background-color:#4f486281;border-radius:50%;padding:5px;z-index:1000}.conversation-card-lists{padding:1.5rem;width:100%;height:100%;display:flex;flex-direction:column}.conversation-card-lists .cards-container{display:flex;flex-wrap:wrap;gap:2rem;width:100%;justify-content:center;flex:1;overflow-y:auto;min-height:0}.conversation-card-lists .cards-container>div{flex:0 0 240px}.conversation-card-lists .dc-card{position:relative;background:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a;padding:.5rem;transition:transform .2s ease,box-shadow .2s ease;display:flex;flex-direction:column;gap:2px}.conversation-card-lists .dc-card:hover{transform:translateY(-2px);box-shadow:0 4px 8px #00000026}.conversation-card-lists .dc-card .dc-card-header{position:absolute;top:10px;left:5px;border-radius:5px;padding:5px}.conversation-card-lists .dc-card .dc-card-header:before{content:\"\";position:absolute;inset:0;background-color:#4d30db81;filter:blur(2px);border-radius:5px;z-index:0}.conversation-card-lists .dc-card .dc-card-header h3{margin:0;font-size:1.25rem;font-weight:600;color:#ece7e7;position:relative;z-index:1}.conversation-card-lists .dc-card .dc-card-content{flex:1}.conversation-card-lists .dc-card .dc-card-content p{margin:0;color:#666;line-height:1.5}.conversation-card-lists .dc-card button{padding:.5rem 1rem;border:none;border-radius:4px;background-color:#007bff;color:#fff;cursor:pointer;font-weight:500;transition:background-color .2s ease}.conversation-card-lists .dc-card button:hover{background-color:#0056b3}.conversation-card-lists .dc-card button:active{transform:translateY(1px)}:host{display:flex;flex-direction:column;height:100%}p-paginator{margin-top:1rem;flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i3$2.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "style", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "appendTo", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first"], outputs: ["onPageChange"] }, { kind: "component", type: DCFilterBarComponent, selector: "dc-filter-bar", inputs: ["isAdmin", "customFilters", "items"], outputs: ["onAction", "onChangeSort", "onNew", "onSearch", "onFilterChange"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i6.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "style", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: SpeedDialModule }, { kind: "component", type: QuickTableComponent, selector: "app-quick-table", inputs: ["onlyView", "columns", "tableData", "actions"], outputs: ["onAction"] }] }); }
3123
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: AgentCardListComponent, deps: [{ token: CONVERSATION_AI_TOKEN }, { token: TOAST_ALERTS_TOKEN }, { token: i1$4.ActivatedRoute }, { token: i1$4.Router }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3124
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: AgentCardListComponent, isStandalone: true, selector: "dc-agent-card-lists", inputs: { viewMode: "viewMode", customCardComponent: "customCardComponent", showOptions: "showOptions", gridLayout: "gridLayout", getCustomButtons: "getCustomButtons" }, viewQueries: [{ propertyName: "outlets", predicate: ["outlet"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<dc-filter-bar [isAdmin]=\"true\" (onFilterAction)=\"doFilterBarAction($event)\"></dc-filter-bar>\n\n@if(viewMode === 'table'){\n<app-quick-table [columns]=\"columns\" [tableData]=\"agentCards\" [actions]=\"actions\" (onAction)=\"onCardAction($event)\"></app-quick-table>\n\n}@else{\n\n<div class=\"conversation-card-lists\">\n @if(!isLoading) {\n <div [ngClass]=\"{ 'cards-container': gridLayout }\">\n @for (card of agentCards; track card) {\n <div style=\"position: relative\">\n <ng-container #outlet=\"ngComponentOutlet\" [ngComponentOutlet]=\"cardComponent\" [ngComponentOutletInputs]=\"{ card: card, showOptions: showOptions }\">\n </ng-container>\n </div>\n }\n </div>\n }\n</div>\n\n@if(isLoading) {\n<div>\n <p-skeleton styleClass=\"mb-2\" />\n <p-skeleton width=\"10rem\" styleClass=\"mb-2\" />\n <p-skeleton width=\"5rem\" styleClass=\"mb-2\" />\n <p-skeleton height=\"2rem\" styleClass=\"mb-2\" />\n <p-skeleton width=\"10rem\" height=\"4rem\" />\n</div>\n} @if(agentCards.length === 0) {\n<div>\n <p>No conversations found or no connection with server</p>\n</div>\n} }\n\n<p-paginator\n currentPageReportTemplate=\"{{ totalRecords }} conversations\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [first]=\"paginatorFirst\"\n [rows]=\"paginatorRows\"\n [totalRecords]=\"totalRecords\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n</p-paginator>\n", styles: [":host{display:block;height:100%}.options-icon{cursor:pointer;position:absolute;top:2px;right:3px;font-size:1.2rem;color:#dde9e9;background-color:#4f486281;border-radius:50%;padding:5px;z-index:1000}.conversation-card-lists{padding:1.5rem;width:100%;height:100%;display:flex;flex-direction:column}.conversation-card-lists .cards-container{display:flex;flex-wrap:wrap;gap:2rem;width:100%;justify-content:center;flex:1;overflow-y:auto;min-height:0}.conversation-card-lists .cards-container>div{flex:0 0 240px}.conversation-card-lists .dc-card{position:relative;background:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a;padding:.5rem;transition:transform .2s ease,box-shadow .2s ease;display:flex;flex-direction:column;gap:2px}.conversation-card-lists .dc-card:hover{transform:translateY(-2px);box-shadow:0 4px 8px #00000026}.conversation-card-lists .dc-card .dc-card-header{position:absolute;top:10px;left:5px;border-radius:5px;padding:5px}.conversation-card-lists .dc-card .dc-card-header:before{content:\"\";position:absolute;inset:0;background-color:#4d30db81;filter:blur(2px);border-radius:5px;z-index:0}.conversation-card-lists .dc-card .dc-card-header h3{margin:0;font-size:1.25rem;font-weight:600;color:#ece7e7;position:relative;z-index:1}.conversation-card-lists .dc-card .dc-card-content{flex:1}.conversation-card-lists .dc-card .dc-card-content p{margin:0;color:#666;line-height:1.5}.conversation-card-lists .dc-card button{padding:.5rem 1rem;border:none;border-radius:4px;background-color:#007bff;color:#fff;cursor:pointer;font-weight:500;transition:background-color .2s ease}.conversation-card-lists .dc-card button:hover{background-color:#0056b3}.conversation-card-lists .dc-card button:active{transform:translateY(1px)}:host{display:flex;flex-direction:column;height:100%}p-paginator{margin-top:1rem;flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i3$3.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "style", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "appendTo", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first"], outputs: ["onPageChange"] }, { kind: "component", type: DCFilterBarComponent, selector: "dc-filter-bar", inputs: ["isAdmin", "customFilters", "items"], outputs: ["onFilterAction", "onChangeSort"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i4$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "style", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: SpeedDialModule }, { kind: "component", type: QuickTableComponent, selector: "app-quick-table", inputs: ["onlyView", "columns", "tableData", "actions"], outputs: ["onAction"] }] }); }
2819
3125
  }
2820
3126
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: AgentCardListComponent, decorators: [{
2821
3127
  type: Component,
@@ -2829,17 +3135,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImpor
2829
3135
  SkeletonModule,
2830
3136
  SpeedDialModule,
2831
3137
  QuickTableComponent,
2832
- ], standalone: true, template: "<dc-filter-bar [isAdmin]=\"true\" (onAction)=\"doFilterBarAction($event)\" (onSearch)=\"search($event)\" (onFilterChange)=\"filterChange($event)\"></dc-filter-bar>\n\n@if(viewMode === 'table'){\n<app-quick-table [columns]=\"columns\" [tableData]=\"agentCards\" [actions]=\"actions\" (onAction)=\"onCardAction($event)\"></app-quick-table>\n\n}@else{\n\n<div class=\"conversation-card-lists\">\n @if(!isLoading) {\n <div [ngClass]=\"{ 'cards-container': gridLayout }\">\n @for (card of agentCards; track card) {\n <div style=\"position: relative\">\n <ng-container #outlet=\"ngComponentOutlet\" [ngComponentOutlet]=\"cardComponent\" [ngComponentOutletInputs]=\"{ card: card }\"> </ng-container>\n </div>\n }\n </div>\n }\n</div>\n\n@if(isLoading) {\n<div>\n <p-skeleton styleClass=\"mb-2\" />\n <p-skeleton width=\"10rem\" styleClass=\"mb-2\" />\n <p-skeleton width=\"5rem\" styleClass=\"mb-2\" />\n <p-skeleton height=\"2rem\" styleClass=\"mb-2\" />\n <p-skeleton width=\"10rem\" height=\"4rem\" />\n</div>\n} @if(agentCards.length === 0) {\n<div>\n <p>No conversations found or no connection with server</p>\n</div>\n} }\n\n<p-paginator\n currentPageReportTemplate=\"{{ totalRecords }} conversations\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [first]=\"paginatorFirst\"\n [rows]=\"paginatorRows\"\n [totalRecords]=\"totalRecords\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n</p-paginator>\n", styles: [":host{display:block;height:100%}.options-icon{cursor:pointer;position:absolute;top:2px;right:3px;font-size:1.2rem;color:#dde9e9;background-color:#4f486281;border-radius:50%;padding:5px;z-index:1000}.conversation-card-lists{padding:1.5rem;width:100%;height:100%;display:flex;flex-direction:column}.conversation-card-lists .cards-container{display:flex;flex-wrap:wrap;gap:2rem;width:100%;justify-content:center;flex:1;overflow-y:auto;min-height:0}.conversation-card-lists .cards-container>div{flex:0 0 240px}.conversation-card-lists .dc-card{position:relative;background:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a;padding:.5rem;transition:transform .2s ease,box-shadow .2s ease;display:flex;flex-direction:column;gap:2px}.conversation-card-lists .dc-card:hover{transform:translateY(-2px);box-shadow:0 4px 8px #00000026}.conversation-card-lists .dc-card .dc-card-header{position:absolute;top:10px;left:5px;border-radius:5px;padding:5px}.conversation-card-lists .dc-card .dc-card-header:before{content:\"\";position:absolute;inset:0;background-color:#4d30db81;filter:blur(2px);border-radius:5px;z-index:0}.conversation-card-lists .dc-card .dc-card-header h3{margin:0;font-size:1.25rem;font-weight:600;color:#ece7e7;position:relative;z-index:1}.conversation-card-lists .dc-card .dc-card-content{flex:1}.conversation-card-lists .dc-card .dc-card-content p{margin:0;color:#666;line-height:1.5}.conversation-card-lists .dc-card button{padding:.5rem 1rem;border:none;border-radius:4px;background-color:#007bff;color:#fff;cursor:pointer;font-weight:500;transition:background-color .2s ease}.conversation-card-lists .dc-card button:hover{background-color:#0056b3}.conversation-card-lists .dc-card button:active{transform:translateY(1px)}:host{display:flex;flex-direction:column;height:100%}p-paginator{margin-top:1rem;flex-shrink:0}\n"] }]
3138
+ ], standalone: true, template: "<dc-filter-bar [isAdmin]=\"true\" (onFilterAction)=\"doFilterBarAction($event)\"></dc-filter-bar>\n\n@if(viewMode === 'table'){\n<app-quick-table [columns]=\"columns\" [tableData]=\"agentCards\" [actions]=\"actions\" (onAction)=\"onCardAction($event)\"></app-quick-table>\n\n}@else{\n\n<div class=\"conversation-card-lists\">\n @if(!isLoading) {\n <div [ngClass]=\"{ 'cards-container': gridLayout }\">\n @for (card of agentCards; track card) {\n <div style=\"position: relative\">\n <ng-container #outlet=\"ngComponentOutlet\" [ngComponentOutlet]=\"cardComponent\" [ngComponentOutletInputs]=\"{ card: card, showOptions: showOptions }\">\n </ng-container>\n </div>\n }\n </div>\n }\n</div>\n\n@if(isLoading) {\n<div>\n <p-skeleton styleClass=\"mb-2\" />\n <p-skeleton width=\"10rem\" styleClass=\"mb-2\" />\n <p-skeleton width=\"5rem\" styleClass=\"mb-2\" />\n <p-skeleton height=\"2rem\" styleClass=\"mb-2\" />\n <p-skeleton width=\"10rem\" height=\"4rem\" />\n</div>\n} @if(agentCards.length === 0) {\n<div>\n <p>No conversations found or no connection with server</p>\n</div>\n} }\n\n<p-paginator\n currentPageReportTemplate=\"{{ totalRecords }} conversations\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [first]=\"paginatorFirst\"\n [rows]=\"paginatorRows\"\n [totalRecords]=\"totalRecords\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n</p-paginator>\n", styles: [":host{display:block;height:100%}.options-icon{cursor:pointer;position:absolute;top:2px;right:3px;font-size:1.2rem;color:#dde9e9;background-color:#4f486281;border-radius:50%;padding:5px;z-index:1000}.conversation-card-lists{padding:1.5rem;width:100%;height:100%;display:flex;flex-direction:column}.conversation-card-lists .cards-container{display:flex;flex-wrap:wrap;gap:2rem;width:100%;justify-content:center;flex:1;overflow-y:auto;min-height:0}.conversation-card-lists .cards-container>div{flex:0 0 240px}.conversation-card-lists .dc-card{position:relative;background:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a;padding:.5rem;transition:transform .2s ease,box-shadow .2s ease;display:flex;flex-direction:column;gap:2px}.conversation-card-lists .dc-card:hover{transform:translateY(-2px);box-shadow:0 4px 8px #00000026}.conversation-card-lists .dc-card .dc-card-header{position:absolute;top:10px;left:5px;border-radius:5px;padding:5px}.conversation-card-lists .dc-card .dc-card-header:before{content:\"\";position:absolute;inset:0;background-color:#4d30db81;filter:blur(2px);border-radius:5px;z-index:0}.conversation-card-lists .dc-card .dc-card-header h3{margin:0;font-size:1.25rem;font-weight:600;color:#ece7e7;position:relative;z-index:1}.conversation-card-lists .dc-card .dc-card-content{flex:1}.conversation-card-lists .dc-card .dc-card-content p{margin:0;color:#666;line-height:1.5}.conversation-card-lists .dc-card button{padding:.5rem 1rem;border:none;border-radius:4px;background-color:#007bff;color:#fff;cursor:pointer;font-weight:500;transition:background-color .2s ease}.conversation-card-lists .dc-card button:hover{background-color:#0056b3}.conversation-card-lists .dc-card button:active{transform:translateY(1px)}:host{display:flex;flex-direction:column;height:100%}p-paginator{margin-top:1rem;flex-shrink:0}\n"] }]
2833
3139
  }], ctorParameters: () => [{ type: AgentCardsAbstractService, decorators: [{
2834
3140
  type: Inject,
2835
3141
  args: [CONVERSATION_AI_TOKEN]
2836
- }] }, { type: i6$2.ToastAlertsAbstractService, decorators: [{
3142
+ }] }, { type: i6.ToastAlertsAbstractService, decorators: [{
2837
3143
  type: Inject,
2838
3144
  args: [TOAST_ALERTS_TOKEN]
2839
- }] }, { type: i1$3.ActivatedRoute }, { type: i1$3.Router }, { type: i0.ChangeDetectorRef }], propDecorators: { viewMode: [{
3145
+ }] }, { type: i1$4.ActivatedRoute }, { type: i1$4.Router }, { type: i0.ChangeDetectorRef }], propDecorators: { viewMode: [{
2840
3146
  type: Input
2841
3147
  }], customCardComponent: [{
2842
3148
  type: Input
3149
+ }], showOptions: [{
3150
+ type: Input
2843
3151
  }], gridLayout: [{
2844
3152
  type: Input
2845
3153
  }], getCustomButtons: [{
@@ -2849,50 +3157,77 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImpor
2849
3157
  args: ['outlet']
2850
3158
  }] } });
2851
3159
 
2852
- const DefaultConversationSettings = {
2853
- textEngine: TextEngines.SimpleText,
2854
- conversationType: ConversationType.Default,
2855
- tts: { voice: '', secondaryVoice: '', speed: '1', speedRate: 1 },
2856
- autoStart: false, // usally start with characterCard.first_mes but if not set also can start with LLM response.
2857
- messages: [], // Esto es calculado por el prompt builder tomando el agente.
2858
- };
3160
+ class ParseCardPipe {
3161
+ constructor() {
3162
+ this.userDataExchange = inject(USER_DATA_EXCHANGE);
3163
+ this.builderConversation = inject(DCConversationPromptBuilderService);
3164
+ }
3165
+ transform(text, card = null) {
3166
+ let parseDict = this.userDataExchange.getParseDict();
3167
+ if (card) {
3168
+ const cardMacros = { char: card?.characterCard?.data?.name };
3169
+ parseDict = { ...parseDict, ...cardMacros };
3170
+ }
3171
+ const result = this.builderConversation.applyReplacements(text, parseDict);
3172
+ return result;
3173
+ }
3174
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: ParseCardPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
3175
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.1.1", ngImport: i0, type: ParseCardPipe, isStandalone: true, name: "parseCard" }); }
3176
+ }
3177
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: ParseCardPipe, decorators: [{
3178
+ type: Pipe,
3179
+ args: [{
3180
+ name: 'parseCard',
3181
+ standalone: true,
3182
+ }]
3183
+ }] });
3184
+
2859
3185
  class DcAgentCardDetailsComponent {
2860
- constructor(agentCardService, route, cdr) {
3186
+ constructor(agentCardService, route, cdr, userDataExchange) {
2861
3187
  this.agentCardService = agentCardService;
2862
3188
  this.route = route;
2863
3189
  this.cdr = cdr;
2864
- this.conversationCardId = '';
3190
+ this.userDataExchange = userDataExchange;
3191
+ this.agentCardId = '';
2865
3192
  this.onStartConversation = new EventEmitter();
3193
+ this.showInfoLayer = false;
2866
3194
  }
2867
3195
  async ngOnInit() {
2868
- console.log('DcAgentCardDetailsComponent', this.conversationCardId);
3196
+ console.log('DcAgentCardDetailsComponent', this.agentCardId);
2869
3197
  const id = this.route.snapshot.paramMap.get('id');
2870
3198
  if (id) {
2871
- this.conversationCardId = id;
2872
- console.log(this.conversationCardId);
3199
+ this.agentCardId = id;
3200
+ console.log(this.agentCardId);
2873
3201
  }
2874
- this.conversation = await this.agentCardService.findConversationCardByID(this.conversationCardId);
2875
- if (!this.conversation.conversationSettings) {
3202
+ this.agentCard = await this.agentCardService.findConversationCardByID(this.agentCardId);
3203
+ if (!this.agentCard.conversationSettings) {
2876
3204
  console.warn('⚠️ Conversation settings not found ⚠️ probably is an old version of the card.');
2877
- this.conversation.conversationSettings = {};
3205
+ this.agentCard.conversationSettings = {};
2878
3206
  }
2879
- console.log(this.conversation);
3207
+ console.log(this.agentCard);
2880
3208
  this.cdr.detectChanges();
2881
3209
  }
2882
3210
  startConversation() {
2883
- console.log('⚠️ last version startConversation', this.conversation);
2884
- this.onStartConversation.emit(this.conversation);
3211
+ console.log('⚠️ last version startConversation', this.agentCard);
3212
+ this.onStartConversation.emit(this.agentCard);
3213
+ }
3214
+ toggleInfoLayer() {
3215
+ this.showInfoLayer = !this.showInfoLayer;
3216
+ this.cdr.markForCheck();
2885
3217
  }
2886
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DcAgentCardDetailsComponent, deps: [{ token: CONVERSATION_AI_TOKEN }, { token: i1$3.ActivatedRoute }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2887
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.1", type: DcAgentCardDetailsComponent, isStandalone: true, selector: "dc-agent-card-details", inputs: { conversationCardId: "conversationCardId" }, outputs: { onStartConversation: "onStartConversation" }, ngImport: i0, template: "<div class=\"dc-conversation-card-details\">\n <div class=\"header\">\n <h2>{{ conversation?.title }}</h2>\n <span class=\"version\">v{{ conversation?.version }}</span>\n </div>\n\n <div class=\"character-card\" *ngIf=\"conversation?.characterCard\">\n <div class=\"character-header\">\n <h3>{{ conversation?.characterCard.data.name }}</h3>\n <div class=\"tags\">\n <span class=\"tag\" *ngFor=\"let tag of conversation?.characterCard.data?.tags\">{{ tag }}</span>\n </div>\n </div>\n\n <div class=\"image-wrapper\">\n <div class=\"image\">\n <img [src]=\"conversation?.assets?.image?.url || 'assets/images/default_conversation_card.webp'\" alt=\"\" />\n <div class=\"actions\">\n <p-button label=\"Start Conversation\" (click)=\"startConversation()\"></p-button>\n </div>\n </div>\n </div>\n\n <div class=\"description\">\n <p>{{ conversation?.characterCard.data?.description }}</p>\n </div>\n\n <div class=\"scenario\" *ngIf=\"conversation?.characterCard.data?.scenario\">\n <h4>Scenario</h4>\n <p>{{ conversation?.characterCard.data.scenario }}</p>\n </div>\n\n <div class=\"first-message\" *ngIf=\"conversation?.characterCard.data?.first_mes\">\n <h4>First Message</h4>\n <p>{{ conversation?.characterCard.data.first_mes }}</p>\n </div>\n\n <div class=\"alternate-greetings\" *ngIf=\"conversation?.characterCard.data?.alternate_greetings?.length\">\n <h4>Alternate Greetings</h4>\n <ul>\n <li *ngFor=\"let greeting of conversation?.characterCard.data.alternate_greetings\">{{ greeting }}</li>\n </ul>\n </div>\n </div>\n\n <div class=\"settings\">\n <div class=\"conversation-settings\">\n <h3>Conversation Settings</h3>\n <div class=\"setting-item\">\n <span class=\"label\">Type:</span>\n <span class=\"value\">{{ conversation?.conversationSettings?.conversationType }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Language:</span>\n <span class=\"value\">{{ conversation?.lang }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Text Engine:</span>\n <span class=\"value\">{{ conversation?.conversationSettings?.textEngine }}</span>\n </div>\n </div>\n\n <div class=\"tts-settings\" *ngIf=\"conversation?.tts\">\n <h3>TTS Settings</h3>\n <div class=\"setting-item\">\n <span class=\"label\">Primary Voice:</span>\n <span class=\"value\">{{ conversation?.tts.voice }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Secondary Voice:</span>\n <span class=\"value\">{{ conversation?.tts.secondaryVoice }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Speed:</span>\n <span class=\"value\">{{ conversation?.tts.speed }} ({{ conversation?.tts.speedRate }}x)</span>\n </div>\n </div>\n </div>\n</div>\n", styles: [".dc-conversation-card-details{padding:1.5rem;max-width:800px;margin:0 auto}.dc-conversation-card-details .header{display:flex;align-items:center;margin-bottom:2rem;gap:1rem}.dc-conversation-card-details .header h2{margin:0;font-size:1.8rem;color:#333}.dc-conversation-card-details .header .version{color:#666;font-size:.9rem;padding:.2rem .5rem;background:#f5f5f5;border-radius:4px}.dc-conversation-card-details .character-card{background:#fff;border-radius:8px;padding:1.5rem;margin-bottom:2rem;box-shadow:0 2px 4px #0000001a}.dc-conversation-card-details .character-card .character-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:1rem}.dc-conversation-card-details .character-card .character-header h3{margin:0;color:#2c3e50;font-size:1.4rem}.dc-conversation-card-details .character-card .character-header .tags{display:flex;gap:.5rem;flex-wrap:wrap}.dc-conversation-card-details .character-card .character-header .tags .tag{background:#e9ecef;color:#495057;padding:.2rem .6rem;border-radius:4px;font-size:.8rem}.dc-conversation-card-details .character-card .description{color:#555;line-height:1.6;margin-bottom:1.5rem}.dc-conversation-card-details .character-card h4{color:#2c3e50;margin:1rem 0 .5rem;font-size:1.1rem}.dc-conversation-card-details .character-card .scenario,.dc-conversation-card-details .character-card .first-message{background:#f8f9fa;padding:1rem;border-radius:6px;margin-bottom:1rem}.dc-conversation-card-details .character-card .scenario p,.dc-conversation-card-details .character-card .first-message p{margin:0;color:#666}.dc-conversation-card-details .character-card .alternate-greetings ul{list-style:none;padding:0;margin:0}.dc-conversation-card-details .character-card .alternate-greetings ul li{padding:.5rem;border-bottom:1px solid #eee;color:#666}.dc-conversation-card-details .character-card .alternate-greetings ul li:last-child{border-bottom:none}.dc-conversation-card-details .settings{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem}@media (max-width: 768px){.dc-conversation-card-details .settings{grid-template-columns:1fr}}.dc-conversation-card-details .settings .conversation-settings,.dc-conversation-card-details .settings .tts-settings{background:#fff;border-radius:8px;padding:1.5rem;box-shadow:0 2px 4px #0000001a}.dc-conversation-card-details .settings .conversation-settings h3,.dc-conversation-card-details .settings .tts-settings h3{margin:0 0 1rem;color:#2c3e50;font-size:1.2rem}.dc-conversation-card-details .settings .conversation-settings .setting-item,.dc-conversation-card-details .settings .tts-settings .setting-item{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px solid #eee}.dc-conversation-card-details .settings .conversation-settings .setting-item:last-child,.dc-conversation-card-details .settings .tts-settings .setting-item:last-child{border-bottom:none}.dc-conversation-card-details .settings .conversation-settings .setting-item .label,.dc-conversation-card-details .settings .tts-settings .setting-item .label{color:#666;font-weight:500}.dc-conversation-card-details .settings .conversation-settings .setting-item .value,.dc-conversation-card-details .settings .tts-settings .setting-item .value{color:#333}.btn{padding:.5rem 1rem;background:#007bff;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s ease-in-out}.btn:hover{background:#0056b3}.image-wrapper{display:flex;justify-content:center;width:100%}.image-wrapper .image{position:relative;max-width:400px;width:100%}.image-wrapper .image img{width:100%;height:auto;object-fit:cover;border-radius:8px}.image-wrapper .image .actions{position:absolute;bottom:20px;left:50%;transform:translate(-50%);z-index:2}.image-wrapper .image .actions .btn{min-width:200px;background:#007bffe6;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.image-wrapper .image .actions .btn:hover{background:#0056b3f2}.actions-wrapper{display:flex;justify-content:center;width:100%;margin:1rem 0}.actions-wrapper .actions .btn{min-width:200px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i7$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }] }); }
3218
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DcAgentCardDetailsComponent, deps: [{ token: CONVERSATION_AI_TOKEN }, { token: i1$4.ActivatedRoute }, { token: i0.ChangeDetectorRef }, { token: USER_DATA_EXCHANGE }], target: i0.ɵɵFactoryTarget.Component }); }
3219
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.1", type: DcAgentCardDetailsComponent, isStandalone: true, selector: "dc-agent-card-details", inputs: { agentCardId: "agentCardId" }, outputs: { onStartConversation: "onStartConversation" }, ngImport: i0, template: "<div style=\"display: flex; justify-content: center; align-items: center\">\n <p-card>\n <div class=\"card-container\">\n <img class=\"card-image\" [src]=\"agentCard?.assets?.image?.url || 'assets/images/default_conversation_card.webp'\" alt=\"\" />\n\n <div class=\"info-button\" (click)=\"toggleInfoLayer()\">\n <p-button icon=\"pi pi-arrow-down-left\" [rounded]=\"true\" [raised]=\"true\" severity=\"primary\" [outlined]=\"true\" />\n </div>\n\n <div style=\"position: absolute; bottom: 20px; right: 50%; transform: translateX(50%); z-index: 3\">\n <p-button size=\"large\" label=\"Iniciar Conversaci\u00F3n\" [rounded]=\"true\" (click)=\"startConversation()\" />\n </div>\n\n <div class=\"info-layer\" [class.active]=\"showInfoLayer\">\n <div class=\"info-content\">\n <h1\n ><strong>{{ agentCard?.title }}</strong></h1\n >\n <p>{{ agentCard?.characterCard.data?.name }}</p>\n\n <div class=\"scenario\" *ngIf=\"agentCard?.characterCard.data?.scenario\">\n <h4>Scenario</h4>\n <p>{{ agentCard?.characterCard.data.scenario | parseCard : agentCard }}</p>\n </div>\n </div>\n </div>\n </div>\n </p-card>\n</div>\n\n<!-- <div class=\"dc-conversation-card-details\">\n <div class=\"header\">\n <h2>{{ agentCard?.title }}</h2>\n <span class=\"version\">v{{ agentCard?.version }}</span>\n </div>\n\n <div class=\"character-card\" *ngIf=\"agentCard?.characterCard\">\n <div class=\"character-header\">\n <h3>{{ agentCard?.characterCard.data.name }}</h3>\n <div class=\"tags\">\n <span class=\"tag\" *ngFor=\"let tag of agentCard?.characterCard.data?.tags\">{{ tag }}</span>\n </div>\n </div>\n\n <div class=\"image-wrapper\">\n <div class=\"image\">\n <img [src]=\"agentCard?.assets?.image?.url || 'assets/images/default_conversation_card.webp'\" alt=\"\" />\n <div class=\"actions\">\n <p-button label=\"Start Conversation\" (click)=\"startConversation()\"></p-button>\n </div>\n </div>\n </div>\n\n <div class=\"description\">\n <p>{{ agentCard?.characterCard.data?.description | parseCard : agentCard }}</p>\n </div>\n\n <div class=\"scenario\" *ngIf=\"agentCard?.characterCard.data?.scenario\">\n <h4>Scenario</h4>\n <p>{{ agentCard?.characterCard.data.scenario }}</p>\n </div>\n\n <div class=\"first-message\" *ngIf=\"agentCard?.characterCard.data?.first_mes\">\n <h4>First Message</h4>\n <p>{{ agentCard?.characterCard.data.first_mes }}</p>\n </div>\n\n <div class=\"alternate-greetings\" *ngIf=\"agentCard?.characterCard.data?.alternate_greetings?.length\">\n <h4>Alternate Greetings</h4>\n <ul>\n <li *ngFor=\"let greeting of agentCard?.characterCard.data.alternate_greetings\">{{ greeting }}</li>\n </ul>\n </div>\n </div>\n\n <div class=\"settings\">\n <div class=\"conversation-settings\">\n <h3>Conversation Settings</h3>\n <div class=\"setting-item\">\n <span class=\"label\">Type:</span>\n <span class=\"value\">{{ agentCard?.conversationSettings?.conversationType }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Language:</span>\n <span class=\"value\">{{ agentCard?.lang }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Text Engine:</span>\n <span class=\"value\">{{ agentCard?.conversationSettings?.textEngine }}</span>\n </div>\n </div>\n\n <div class=\"tts-settings\" *ngIf=\"agentCard?.tts\">\n <h3>TTS Settings</h3>\n <div class=\"setting-item\">\n <span class=\"label\">Primary Voice:</span>\n <span class=\"value\">{{ agentCard?.tts.voice }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Secondary Voice:</span>\n <span class=\"value\">{{ agentCard?.tts.secondaryVoice }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Speed:</span>\n <span class=\"value\">{{ agentCard?.tts.speed }} ({{ agentCard?.tts.speedRate }}x)</span>\n </div>\n </div>\n </div>\n</div> -->\n", styles: ["::ng-deep .p-card{width:420px;height:700px}::ng-deep .p-card .p-card-body{width:100%;height:100%}.card-image{height:100%;width:100%;object-fit:cover;object-position:center;position:absolute;top:0;left:0;transition:filter .3s ease}.info-button{position:absolute;top:15px;right:15px;z-index:3}.info-button:hover{transform:scale(1.1)}.info-layer{height:100%;width:100%;position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;z-index:2;-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);background-color:#ed122833;color:#fff;opacity:1;clip-path:circle(0% at top right);transition:clip-path .5s cubic-bezier(.25,1,.5,1);pointer-events:none}.info-layer.active{clip-path:circle(150% at top right);pointer-events:auto}.info-content{padding:15px;text-align:center;max-width:90%}.info-content h1{margin-top:0;font-size:18px;margin-bottom:10px}.info-content p{font-size:12px;margin:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i7.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i3$2.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "pipe", type: ParseCardPipe, name: "parseCard" }] }); }
2888
3220
  }
2889
3221
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DcAgentCardDetailsComponent, decorators: [{
2890
3222
  type: Component,
2891
- args: [{ selector: 'dc-agent-card-details', standalone: true, imports: [CommonModule, ButtonModule], template: "<div class=\"dc-conversation-card-details\">\n <div class=\"header\">\n <h2>{{ conversation?.title }}</h2>\n <span class=\"version\">v{{ conversation?.version }}</span>\n </div>\n\n <div class=\"character-card\" *ngIf=\"conversation?.characterCard\">\n <div class=\"character-header\">\n <h3>{{ conversation?.characterCard.data.name }}</h3>\n <div class=\"tags\">\n <span class=\"tag\" *ngFor=\"let tag of conversation?.characterCard.data?.tags\">{{ tag }}</span>\n </div>\n </div>\n\n <div class=\"image-wrapper\">\n <div class=\"image\">\n <img [src]=\"conversation?.assets?.image?.url || 'assets/images/default_conversation_card.webp'\" alt=\"\" />\n <div class=\"actions\">\n <p-button label=\"Start Conversation\" (click)=\"startConversation()\"></p-button>\n </div>\n </div>\n </div>\n\n <div class=\"description\">\n <p>{{ conversation?.characterCard.data?.description }}</p>\n </div>\n\n <div class=\"scenario\" *ngIf=\"conversation?.characterCard.data?.scenario\">\n <h4>Scenario</h4>\n <p>{{ conversation?.characterCard.data.scenario }}</p>\n </div>\n\n <div class=\"first-message\" *ngIf=\"conversation?.characterCard.data?.first_mes\">\n <h4>First Message</h4>\n <p>{{ conversation?.characterCard.data.first_mes }}</p>\n </div>\n\n <div class=\"alternate-greetings\" *ngIf=\"conversation?.characterCard.data?.alternate_greetings?.length\">\n <h4>Alternate Greetings</h4>\n <ul>\n <li *ngFor=\"let greeting of conversation?.characterCard.data.alternate_greetings\">{{ greeting }}</li>\n </ul>\n </div>\n </div>\n\n <div class=\"settings\">\n <div class=\"conversation-settings\">\n <h3>Conversation Settings</h3>\n <div class=\"setting-item\">\n <span class=\"label\">Type:</span>\n <span class=\"value\">{{ conversation?.conversationSettings?.conversationType }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Language:</span>\n <span class=\"value\">{{ conversation?.lang }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Text Engine:</span>\n <span class=\"value\">{{ conversation?.conversationSettings?.textEngine }}</span>\n </div>\n </div>\n\n <div class=\"tts-settings\" *ngIf=\"conversation?.tts\">\n <h3>TTS Settings</h3>\n <div class=\"setting-item\">\n <span class=\"label\">Primary Voice:</span>\n <span class=\"value\">{{ conversation?.tts.voice }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Secondary Voice:</span>\n <span class=\"value\">{{ conversation?.tts.secondaryVoice }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Speed:</span>\n <span class=\"value\">{{ conversation?.tts.speed }} ({{ conversation?.tts.speedRate }}x)</span>\n </div>\n </div>\n </div>\n</div>\n", styles: [".dc-conversation-card-details{padding:1.5rem;max-width:800px;margin:0 auto}.dc-conversation-card-details .header{display:flex;align-items:center;margin-bottom:2rem;gap:1rem}.dc-conversation-card-details .header h2{margin:0;font-size:1.8rem;color:#333}.dc-conversation-card-details .header .version{color:#666;font-size:.9rem;padding:.2rem .5rem;background:#f5f5f5;border-radius:4px}.dc-conversation-card-details .character-card{background:#fff;border-radius:8px;padding:1.5rem;margin-bottom:2rem;box-shadow:0 2px 4px #0000001a}.dc-conversation-card-details .character-card .character-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:1rem}.dc-conversation-card-details .character-card .character-header h3{margin:0;color:#2c3e50;font-size:1.4rem}.dc-conversation-card-details .character-card .character-header .tags{display:flex;gap:.5rem;flex-wrap:wrap}.dc-conversation-card-details .character-card .character-header .tags .tag{background:#e9ecef;color:#495057;padding:.2rem .6rem;border-radius:4px;font-size:.8rem}.dc-conversation-card-details .character-card .description{color:#555;line-height:1.6;margin-bottom:1.5rem}.dc-conversation-card-details .character-card h4{color:#2c3e50;margin:1rem 0 .5rem;font-size:1.1rem}.dc-conversation-card-details .character-card .scenario,.dc-conversation-card-details .character-card .first-message{background:#f8f9fa;padding:1rem;border-radius:6px;margin-bottom:1rem}.dc-conversation-card-details .character-card .scenario p,.dc-conversation-card-details .character-card .first-message p{margin:0;color:#666}.dc-conversation-card-details .character-card .alternate-greetings ul{list-style:none;padding:0;margin:0}.dc-conversation-card-details .character-card .alternate-greetings ul li{padding:.5rem;border-bottom:1px solid #eee;color:#666}.dc-conversation-card-details .character-card .alternate-greetings ul li:last-child{border-bottom:none}.dc-conversation-card-details .settings{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem}@media (max-width: 768px){.dc-conversation-card-details .settings{grid-template-columns:1fr}}.dc-conversation-card-details .settings .conversation-settings,.dc-conversation-card-details .settings .tts-settings{background:#fff;border-radius:8px;padding:1.5rem;box-shadow:0 2px 4px #0000001a}.dc-conversation-card-details .settings .conversation-settings h3,.dc-conversation-card-details .settings .tts-settings h3{margin:0 0 1rem;color:#2c3e50;font-size:1.2rem}.dc-conversation-card-details .settings .conversation-settings .setting-item,.dc-conversation-card-details .settings .tts-settings .setting-item{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px solid #eee}.dc-conversation-card-details .settings .conversation-settings .setting-item:last-child,.dc-conversation-card-details .settings .tts-settings .setting-item:last-child{border-bottom:none}.dc-conversation-card-details .settings .conversation-settings .setting-item .label,.dc-conversation-card-details .settings .tts-settings .setting-item .label{color:#666;font-weight:500}.dc-conversation-card-details .settings .conversation-settings .setting-item .value,.dc-conversation-card-details .settings .tts-settings .setting-item .value{color:#333}.btn{padding:.5rem 1rem;background:#007bff;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s ease-in-out}.btn:hover{background:#0056b3}.image-wrapper{display:flex;justify-content:center;width:100%}.image-wrapper .image{position:relative;max-width:400px;width:100%}.image-wrapper .image img{width:100%;height:auto;object-fit:cover;border-radius:8px}.image-wrapper .image .actions{position:absolute;bottom:20px;left:50%;transform:translate(-50%);z-index:2}.image-wrapper .image .actions .btn{min-width:200px;background:#007bffe6;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.image-wrapper .image .actions .btn:hover{background:#0056b3f2}.actions-wrapper{display:flex;justify-content:center;width:100%;margin:1rem 0}.actions-wrapper .actions .btn{min-width:200px}\n"] }]
3223
+ args: [{ selector: 'dc-agent-card-details', standalone: true, imports: [CommonModule, ButtonModule, CardModule, ParseCardPipe], template: "<div style=\"display: flex; justify-content: center; align-items: center\">\n <p-card>\n <div class=\"card-container\">\n <img class=\"card-image\" [src]=\"agentCard?.assets?.image?.url || 'assets/images/default_conversation_card.webp'\" alt=\"\" />\n\n <div class=\"info-button\" (click)=\"toggleInfoLayer()\">\n <p-button icon=\"pi pi-arrow-down-left\" [rounded]=\"true\" [raised]=\"true\" severity=\"primary\" [outlined]=\"true\" />\n </div>\n\n <div style=\"position: absolute; bottom: 20px; right: 50%; transform: translateX(50%); z-index: 3\">\n <p-button size=\"large\" label=\"Iniciar Conversaci\u00F3n\" [rounded]=\"true\" (click)=\"startConversation()\" />\n </div>\n\n <div class=\"info-layer\" [class.active]=\"showInfoLayer\">\n <div class=\"info-content\">\n <h1\n ><strong>{{ agentCard?.title }}</strong></h1\n >\n <p>{{ agentCard?.characterCard.data?.name }}</p>\n\n <div class=\"scenario\" *ngIf=\"agentCard?.characterCard.data?.scenario\">\n <h4>Scenario</h4>\n <p>{{ agentCard?.characterCard.data.scenario | parseCard : agentCard }}</p>\n </div>\n </div>\n </div>\n </div>\n </p-card>\n</div>\n\n<!-- <div class=\"dc-conversation-card-details\">\n <div class=\"header\">\n <h2>{{ agentCard?.title }}</h2>\n <span class=\"version\">v{{ agentCard?.version }}</span>\n </div>\n\n <div class=\"character-card\" *ngIf=\"agentCard?.characterCard\">\n <div class=\"character-header\">\n <h3>{{ agentCard?.characterCard.data.name }}</h3>\n <div class=\"tags\">\n <span class=\"tag\" *ngFor=\"let tag of agentCard?.characterCard.data?.tags\">{{ tag }}</span>\n </div>\n </div>\n\n <div class=\"image-wrapper\">\n <div class=\"image\">\n <img [src]=\"agentCard?.assets?.image?.url || 'assets/images/default_conversation_card.webp'\" alt=\"\" />\n <div class=\"actions\">\n <p-button label=\"Start Conversation\" (click)=\"startConversation()\"></p-button>\n </div>\n </div>\n </div>\n\n <div class=\"description\">\n <p>{{ agentCard?.characterCard.data?.description | parseCard : agentCard }}</p>\n </div>\n\n <div class=\"scenario\" *ngIf=\"agentCard?.characterCard.data?.scenario\">\n <h4>Scenario</h4>\n <p>{{ agentCard?.characterCard.data.scenario }}</p>\n </div>\n\n <div class=\"first-message\" *ngIf=\"agentCard?.characterCard.data?.first_mes\">\n <h4>First Message</h4>\n <p>{{ agentCard?.characterCard.data.first_mes }}</p>\n </div>\n\n <div class=\"alternate-greetings\" *ngIf=\"agentCard?.characterCard.data?.alternate_greetings?.length\">\n <h4>Alternate Greetings</h4>\n <ul>\n <li *ngFor=\"let greeting of agentCard?.characterCard.data.alternate_greetings\">{{ greeting }}</li>\n </ul>\n </div>\n </div>\n\n <div class=\"settings\">\n <div class=\"conversation-settings\">\n <h3>Conversation Settings</h3>\n <div class=\"setting-item\">\n <span class=\"label\">Type:</span>\n <span class=\"value\">{{ agentCard?.conversationSettings?.conversationType }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Language:</span>\n <span class=\"value\">{{ agentCard?.lang }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Text Engine:</span>\n <span class=\"value\">{{ agentCard?.conversationSettings?.textEngine }}</span>\n </div>\n </div>\n\n <div class=\"tts-settings\" *ngIf=\"agentCard?.tts\">\n <h3>TTS Settings</h3>\n <div class=\"setting-item\">\n <span class=\"label\">Primary Voice:</span>\n <span class=\"value\">{{ agentCard?.tts.voice }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Secondary Voice:</span>\n <span class=\"value\">{{ agentCard?.tts.secondaryVoice }}</span>\n </div>\n <div class=\"setting-item\">\n <span class=\"label\">Speed:</span>\n <span class=\"value\">{{ agentCard?.tts.speed }} ({{ agentCard?.tts.speedRate }}x)</span>\n </div>\n </div>\n </div>\n</div> -->\n", styles: ["::ng-deep .p-card{width:420px;height:700px}::ng-deep .p-card .p-card-body{width:100%;height:100%}.card-image{height:100%;width:100%;object-fit:cover;object-position:center;position:absolute;top:0;left:0;transition:filter .3s ease}.info-button{position:absolute;top:15px;right:15px;z-index:3}.info-button:hover{transform:scale(1.1)}.info-layer{height:100%;width:100%;position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;z-index:2;-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);background-color:#ed122833;color:#fff;opacity:1;clip-path:circle(0% at top right);transition:clip-path .5s cubic-bezier(.25,1,.5,1);pointer-events:none}.info-layer.active{clip-path:circle(150% at top right);pointer-events:auto}.info-content{padding:15px;text-align:center;max-width:90%}.info-content h1{margin-top:0;font-size:18px;margin-bottom:10px}.info-content p{font-size:12px;margin:0}\n"] }]
2892
3224
  }], ctorParameters: () => [{ type: AgentCardsAbstractService, decorators: [{
2893
3225
  type: Inject,
2894
3226
  args: [CONVERSATION_AI_TOKEN]
2895
- }] }, { type: i1$3.ActivatedRoute }, { type: i0.ChangeDetectorRef }], propDecorators: { conversationCardId: [{
3227
+ }] }, { type: i1$4.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: UserDataExchangeAbstractService, decorators: [{
3228
+ type: Inject,
3229
+ args: [USER_DATA_EXCHANGE]
3230
+ }] }], propDecorators: { agentCardId: [{
2896
3231
  type: Input
2897
3232
  }], onStartConversation: [{
2898
3233
  type: Output
@@ -2907,5 +3242,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImpor
2907
3242
  * Generated bundle index. Do not edit.
2908
3243
  */
2909
3244
 
2910
- export { AgentCardListComponent, AgentCardsAbstractService, AudioService, AudioSpeed, CONVERSATION_AI_TOKEN, ChatMessage, ChatMessageComponent, ChatMultiMessage, ChatRole, ChatUserSettings, ConversationDTO, ConversationMessagesDTO, ConversationType, ConversationTypeOptions, DCAgentCardFormComponent, DCChatComponent, DCConversationCardUIComponent, DCConversationPromptBuilderService, DcAgentCardDetailsComponent, EAccountsPlatform, LangCodeDescriptionEs, ProviderSelectorComponent, TextEngineOptions, TextEngines, USER_DATA_EXCHANGE, UserDataExchangeAbstractService, VoiceTTSOption, VoiceTTSOptions, WordTimestamps, characterCardStringDataDefinition, extractJsonFromResponse, provideChatAIService, provideUserDataExchange };
3245
+ export { AgentCardListComponent, AgentCardsAbstractService, AudioService, AudioSpeed, CONVERSATION_AI_TOKEN, ChatMessage, ChatMessageComponent, ChatMultiMessage, ChatRole, ChatUserSettings, ConversationDTO, ConversationMessagesDTO, ConversationType, ConversationTypeOptions, DCAgentCardFormComponent, DCChatComponent, DCConversationCardUIComponent, DCConversationPromptBuilderService, DcAgentCardDetailsComponent, EAccountsPlatform, LangCodeDescriptionEs, ProviderSelectorComponent, TextEngineOptions, TextEngines, USER_DATA_EXCHANGE, UserDataExchangeAbstractService, VoiceTTSOption, VoiceTTSOptions, WordTimestamps, characterCardStringDataDefinition, defaultconvUserSettings, extractJsonFromResponse, provideChatAIService, provideUserDataExchange };
2911
3246
  //# sourceMappingURL=dataclouder-ngx-agent-cards.mjs.map