@memberjunction/ng-conversations 5.43.0 → 5.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts +0 -1
- package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts.map +1 -1
- package/dist/lib/components/active-tasks/active-tasks-panel.component.js +56 -52
- package/dist/lib/components/active-tasks/active-tasks-panel.component.js.map +1 -1
- package/dist/lib/components/artifact/artifact-share-modal.component.d.ts +3 -1
- package/dist/lib/components/artifact/artifact-share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/artifact/artifact-share-modal.component.js +52 -52
- package/dist/lib/components/artifact/artifact-share-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-form-modal.component.js +10 -14
- package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-share-modal.component.d.ts +3 -1
- package/dist/lib/components/collection/collection-share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-share-modal.component.js +56 -56
- package/dist/lib/components/collection/collection-share-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-tree.component.d.ts +3 -1
- package/dist/lib/components/collection/collection-tree.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-tree.component.js +10 -7
- package/dist/lib/components/collection/collection-tree.component.js.map +1 -1
- package/dist/lib/components/collection/collection-view.component.d.ts +3 -1
- package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-view.component.js +29 -41
- package/dist/lib/components/collection/collection-view.component.js.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.d.ts +4 -0
- package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.js +134 -166
- package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.d.ts +103 -0
- package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -0
- package/dist/lib/components/composer/ai-composer.component.js +263 -0
- package/dist/lib/components/composer/ai-composer.component.js.map +1 -0
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +76 -12
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +522 -158
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.d.ts +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.js.map +1 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.js +6 -9
- package/dist/lib/components/conversation/pinned-messages-panel.component.js.map +1 -1
- package/dist/lib/components/library/library-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/library/library-full-view.component.js +20 -24
- package/dist/lib/components/library/library-full-view.component.js.map +1 -1
- package/dist/lib/components/members/members-modal.component.d.ts.map +1 -1
- package/dist/lib/components/members/members-modal.component.js +10 -11
- package/dist/lib/components/members/members-modal.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +87 -23
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +245 -158
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +11 -3
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +73 -21
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.js +6 -9
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.d.ts +4 -1
- package/dist/lib/components/overlay/chat-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.js +9 -4
- package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +45 -0
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +10 -0
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +1 -1
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts +46 -0
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/channels/client-context-channel.js +174 -0
- package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.d.ts +123 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.js +397 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-state.d.ts +103 -0
- package/dist/lib/components/realtime/media/media-channel-state.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-state.js +143 -0
- package/dist/lib/components/realtime/media/media-channel-state.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-tools.d.ts +24 -0
- package/dist/lib/components/realtime/media/media-channel-tools.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-tools.js +107 -0
- package/dist/lib/components/realtime/media/media-channel-tools.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts +89 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/media-channel.js +253 -0
- package/dist/lib/components/realtime/media/media-channel.js.map +1 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.d.ts +141 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.js +574 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +59 -14
- package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-activity-rail.component.js +277 -74
- package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +28 -27
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.js +144 -143
- package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +12 -0
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.js +105 -43
- package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +2 -2
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.d.ts +41 -7
- package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.js +216 -102
- package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +0 -2
- package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-delegation-card.component.js +67 -71
- package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +364 -44
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.js +839 -153
- package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-session-state.d.ts +5 -5
- package/dist/lib/components/realtime/realtime-session-state.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-state.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tab-style.d.ts +70 -0
- package/dist/lib/components/realtime/realtime-surface-tab-style.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tab-style.js +115 -0
- package/dist/lib/components/realtime/realtime-surface-tab-style.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +55 -57
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js +165 -143
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +80 -71
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js +83 -113
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.d.ts +270 -0
- package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-ui-config.js +212 -0
- package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -0
- package/dist/lib/components/search/search-panel.component.d.ts +2 -0
- package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
- package/dist/lib/components/search/search-panel.component.js +92 -101
- package/dist/lib/components/search/search-panel.component.js.map +1 -1
- package/dist/lib/components/share/share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/share/share-modal.component.js +10 -11
- package/dist/lib/components/share/share-modal.component.js.map +1 -1
- package/dist/lib/components/shared/user-picker.component.d.ts.map +1 -1
- package/dist/lib/components/shared/user-picker.component.js +12 -15
- package/dist/lib/components/shared/user-picker.component.js.map +1 -1
- package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts +11 -3
- package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts.map +1 -1
- package/dist/lib/components/sidebar/conversation-sidebar.component.js +34 -10
- package/dist/lib/components/sidebar/conversation-sidebar.component.js.map +1 -1
- package/dist/lib/components/sidebar/routines-section.component.d.ts +73 -0
- package/dist/lib/components/sidebar/routines-section.component.d.ts.map +1 -0
- package/dist/lib/components/sidebar/routines-section.component.js +211 -0
- package/dist/lib/components/sidebar/routines-section.component.js.map +1 -0
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts +12 -0
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.js +37 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +16 -5
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +51 -31
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/composer-plugins/agent-mention.provider.d.ts +16 -0
- package/dist/lib/composer-plugins/agent-mention.provider.d.ts.map +1 -0
- package/dist/lib/composer-plugins/agent-mention.provider.js +28 -0
- package/dist/lib/composer-plugins/agent-mention.provider.js.map +1 -0
- package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts +20 -0
- package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts.map +1 -0
- package/dist/lib/composer-plugins/base-conversation-mention.provider.js +32 -0
- package/dist/lib/composer-plugins/base-conversation-mention.provider.js.map +1 -0
- package/dist/lib/composer-plugins/load-composer-plugins.d.ts +9 -0
- package/dist/lib/composer-plugins/load-composer-plugins.d.ts.map +1 -0
- package/dist/lib/composer-plugins/load-composer-plugins.js +17 -0
- package/dist/lib/composer-plugins/load-composer-plugins.js.map +1 -0
- package/dist/lib/composer-plugins/record-mention.provider.d.ts +14 -0
- package/dist/lib/composer-plugins/record-mention.provider.d.ts.map +1 -0
- package/dist/lib/composer-plugins/record-mention.provider.js +26 -0
- package/dist/lib/composer-plugins/record-mention.provider.js.map +1 -0
- package/dist/lib/composer-plugins/skill-command.provider.d.ts +15 -0
- package/dist/lib/composer-plugins/skill-command.provider.d.ts.map +1 -0
- package/dist/lib/composer-plugins/skill-command.provider.js +27 -0
- package/dist/lib/composer-plugins/skill-command.provider.js.map +1 -0
- package/dist/lib/conversations.module.d.ts +68 -64
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +69 -18
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/models/conversation-state.model.d.ts +6 -3
- package/dist/lib/models/conversation-state.model.d.ts.map +1 -1
- package/dist/lib/models/conversation-state.model.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +9 -2
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +26 -2
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-attachment.service.d.ts +1 -1
- package/dist/lib/services/conversation-attachment.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-attachment.service.js.map +1 -1
- package/dist/lib/services/mention-autocomplete.service.d.ts +42 -19
- package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
- package/dist/lib/services/mention-autocomplete.service.js +113 -18
- package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.d.ts +143 -0
- package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -0
- package/dist/lib/services/realtime-audio-recorder.js +379 -0
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -0
- package/dist/lib/services/realtime-pcm-wav.d.ts +75 -0
- package/dist/lib/services/realtime-pcm-wav.d.ts.map +1 -0
- package/dist/lib/services/realtime-pcm-wav.js +205 -0
- package/dist/lib/services/realtime-pcm-wav.js.map +1 -0
- package/dist/lib/services/realtime-session-review.service.d.ts +28 -1
- package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session-review.service.js +12 -3
- package/dist/lib/services/realtime-session-review.service.js.map +1 -1
- package/dist/lib/services/realtime-session.service.d.ts +210 -20
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session.service.js +452 -21
- package/dist/lib/services/realtime-session.service.js.map +1 -1
- package/dist/lib/services/realtime-sessions-adapter.js +1 -1
- package/dist/lib/services/realtime-sessions-adapter.js.map +1 -1
- package/dist/lib/services/ui-command-handler.service.d.ts +7 -2
- package/dist/lib/services/ui-command-handler.service.d.ts.map +1 -1
- package/dist/lib/services/ui-command-handler.service.js +6 -2
- package/dist/lib/services/ui-command-handler.service.js.map +1 -1
- package/dist/lib/utils/plan-mode-preference.d.ts +62 -0
- package/dist/lib/utils/plan-mode-preference.d.ts.map +1 -0
- package/dist/lib/utils/plan-mode-preference.js +130 -0
- package/dist/lib/utils/plan-mode-preference.js.map +1 -0
- package/dist/public-api.d.ts +29 -3
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +46 -3
- package/dist/public-api.js.map +1 -1
- package/package.json +30 -26
- package/dist/__tests__/attachment-badge.test.d.ts +0 -2
- package/dist/__tests__/attachment-badge.test.d.ts.map +0 -1
- package/dist/__tests__/attachment-badge.test.js +0 -66
- package/dist/__tests__/attachment-badge.test.js.map +0 -1
- package/dist/__tests__/channel-optional-surface.test.d.ts +0 -2
- package/dist/__tests__/channel-optional-surface.test.d.ts.map +0 -1
- package/dist/__tests__/channel-optional-surface.test.js +0 -53
- package/dist/__tests__/channel-optional-surface.test.js.map +0 -1
- package/dist/__tests__/chat-events.test.d.ts +0 -14
- package/dist/__tests__/chat-events.test.d.ts.map +0 -1
- package/dist/__tests__/chat-events.test.js +0 -109
- package/dist/__tests__/chat-events.test.js.map +0 -1
- package/dist/__tests__/collections-full-view.test.d.ts +0 -2
- package/dist/__tests__/collections-full-view.test.d.ts.map +0 -1
- package/dist/__tests__/collections-full-view.test.js +0 -225
- package/dist/__tests__/collections-full-view.test.js.map +0 -1
- package/dist/__tests__/conversation-cache.test.d.ts +0 -2
- package/dist/__tests__/conversation-cache.test.d.ts.map +0 -1
- package/dist/__tests__/conversation-cache.test.js +0 -233
- package/dist/__tests__/conversation-cache.test.js.map +0 -1
- package/dist/__tests__/conversation-naming.test.d.ts +0 -2
- package/dist/__tests__/conversation-naming.test.d.ts.map +0 -1
- package/dist/__tests__/conversation-naming.test.js +0 -110
- package/dist/__tests__/conversation-naming.test.js.map +0 -1
- package/dist/__tests__/delegation-result-parser.test.d.ts +0 -2
- package/dist/__tests__/delegation-result-parser.test.d.ts.map +0 -1
- package/dist/__tests__/delegation-result-parser.test.js +0 -107
- package/dist/__tests__/delegation-result-parser.test.js.map +0 -1
- package/dist/__tests__/distinct-artifacts.test.d.ts +0 -2
- package/dist/__tests__/distinct-artifacts.test.d.ts.map +0 -1
- package/dist/__tests__/distinct-artifacts.test.js +0 -56
- package/dist/__tests__/distinct-artifacts.test.js.map +0 -1
- package/dist/__tests__/event-wiring.test.d.ts +0 -15
- package/dist/__tests__/event-wiring.test.d.ts.map +0 -1
- package/dist/__tests__/event-wiring.test.js +0 -100
- package/dist/__tests__/event-wiring.test.js.map +0 -1
- package/dist/__tests__/index.test.d.ts +0 -2
- package/dist/__tests__/index.test.d.ts.map +0 -1
- package/dist/__tests__/index.test.js +0 -7
- package/dist/__tests__/index.test.js.map +0 -1
- package/dist/__tests__/narration-template.test.d.ts +0 -2
- package/dist/__tests__/narration-template.test.d.ts.map +0 -1
- package/dist/__tests__/narration-template.test.js +0 -76
- package/dist/__tests__/narration-template.test.js.map +0 -1
- package/dist/__tests__/notification-model.test.d.ts +0 -2
- package/dist/__tests__/notification-model.test.d.ts.map +0 -1
- package/dist/__tests__/notification-model.test.js +0 -68
- package/dist/__tests__/notification-model.test.js.map +0 -1
- package/dist/__tests__/realtime-agent-picker-models.test.d.ts +0 -2
- package/dist/__tests__/realtime-agent-picker-models.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-agent-picker-models.test.js +0 -49
- package/dist/__tests__/realtime-agent-picker-models.test.js.map +0 -1
- package/dist/__tests__/realtime-audio-visuals.test.d.ts +0 -2
- package/dist/__tests__/realtime-audio-visuals.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-audio-visuals.test.js +0 -123
- package/dist/__tests__/realtime-audio-visuals.test.js.map +0 -1
- package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts +0 -2
- package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-delegation-card-cancel.test.js +0 -48
- package/dist/__tests__/realtime-delegation-card-cancel.test.js.map +0 -1
- package/dist/__tests__/realtime-disclosure.test.d.ts +0 -2
- package/dist/__tests__/realtime-disclosure.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-disclosure.test.js +0 -164
- package/dist/__tests__/realtime-disclosure.test.js.map +0 -1
- package/dist/__tests__/realtime-pairing.test.d.ts +0 -2
- package/dist/__tests__/realtime-pairing.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-pairing.test.js +0 -207
- package/dist/__tests__/realtime-pairing.test.js.map +0 -1
- package/dist/__tests__/realtime-review-lifecycle.test.d.ts +0 -2
- package/dist/__tests__/realtime-review-lifecycle.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-review-lifecycle.test.js +0 -154
- package/dist/__tests__/realtime-review-lifecycle.test.js.map +0 -1
- package/dist/__tests__/realtime-session-cancel-usage.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-cancel-usage.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-cancel-usage.test.js +0 -230
- package/dist/__tests__/realtime-session-cancel-usage.test.js.map +0 -1
- package/dist/__tests__/realtime-session-channels.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-channels.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-channels.test.js +0 -252
- package/dist/__tests__/realtime-session-channels.test.js.map +0 -1
- package/dist/__tests__/realtime-session-client-tools.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-client-tools.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-client-tools.test.js +0 -103
- package/dist/__tests__/realtime-session-client-tools.test.js.map +0 -1
- package/dist/__tests__/realtime-session-minimized.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-minimized.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-minimized.test.js +0 -32
- package/dist/__tests__/realtime-session-minimized.test.js.map +0 -1
- package/dist/__tests__/realtime-session-mint.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-mint.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-mint.test.js +0 -69
- package/dist/__tests__/realtime-session-mint.test.js.map +0 -1
- package/dist/__tests__/realtime-session-policy.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-policy.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-policy.test.js +0 -303
- package/dist/__tests__/realtime-session-policy.test.js.map +0 -1
- package/dist/__tests__/realtime-session-review.service.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-review.service.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-review.service.test.js +0 -743
- package/dist/__tests__/realtime-session-review.service.test.js.map +0 -1
- package/dist/__tests__/realtime-session-state.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-state.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-state.test.js +0 -83
- package/dist/__tests__/realtime-session-state.test.js.map +0 -1
- package/dist/__tests__/realtime-session-timeline-card.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-timeline-card.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-timeline-card.test.js +0 -106
- package/dist/__tests__/realtime-session-timeline-card.test.js.map +0 -1
- package/dist/__tests__/realtime-session-timeline.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-timeline.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-timeline.test.js +0 -142
- package/dist/__tests__/realtime-session-timeline.test.js.map +0 -1
- package/dist/__tests__/realtime-sessions-adapter.test.d.ts +0 -19
- package/dist/__tests__/realtime-sessions-adapter.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-sessions-adapter.test.js +0 -188
- package/dist/__tests__/realtime-sessions-adapter.test.js.map +0 -1
- package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts +0 -2
- package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-surface-panel-prefs.test.js +0 -100
- package/dist/__tests__/realtime-surface-panel-prefs.test.js.map +0 -1
- package/dist/__tests__/realtime-surface-tabs-model.test.d.ts +0 -2
- package/dist/__tests__/realtime-surface-tabs-model.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-surface-tabs-model.test.js +0 -193
- package/dist/__tests__/realtime-surface-tabs-model.test.js.map +0 -1
- package/dist/__tests__/remote-browser-audio-player.test.d.ts +0 -2
- package/dist/__tests__/remote-browser-audio-player.test.d.ts.map +0 -1
- package/dist/__tests__/remote-browser-audio-player.test.js +0 -137
- package/dist/__tests__/remote-browser-audio-player.test.js.map +0 -1
- package/dist/__tests__/remote-browser-channel.test.d.ts +0 -2
- package/dist/__tests__/remote-browser-channel.test.d.ts.map +0 -1
- package/dist/__tests__/remote-browser-channel.test.js +0 -585
- package/dist/__tests__/remote-browser-channel.test.js.map +0 -1
- package/dist/__tests__/search-service.test.d.ts +0 -2
- package/dist/__tests__/search-service.test.d.ts.map +0 -1
- package/dist/__tests__/search-service.test.js +0 -114
- package/dist/__tests__/search-service.test.js.map +0 -1
- package/dist/__tests__/slot-defaults.test.d.ts +0 -24
- package/dist/__tests__/slot-defaults.test.d.ts.map +0 -1
- package/dist/__tests__/slot-defaults.test.js +0 -63
- package/dist/__tests__/slot-defaults.test.js.map +0 -1
- package/dist/__tests__/toast-service.test.d.ts +0 -2
- package/dist/__tests__/toast-service.test.d.ts.map +0 -1
- package/dist/__tests__/toast-service.test.js +0 -143
- package/dist/__tests__/toast-service.test.js.map +0 -1
- package/dist/__tests__/user-authorization.test.d.ts +0 -2
- package/dist/__tests__/user-authorization.test.d.ts.map +0 -1
- package/dist/__tests__/user-authorization.test.js +0 -97
- package/dist/__tests__/user-authorization.test.js.map +0 -1
- package/dist/__tests__/voice-session-narration.test.d.ts +0 -2
- package/dist/__tests__/voice-session-narration.test.d.ts.map +0 -1
- package/dist/__tests__/voice-session-narration.test.js +0 -609
- package/dist/__tests__/voice-session-narration.test.js.map +0 -1
- package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts +0 -2
- package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts.map +0 -1
- package/dist/__tests__/whiteboard-artifact-viewer.test.js +0 -101
- package/dist/__tests__/whiteboard-artifact-viewer.test.js.map +0 -1
- package/dist/__tests__/whiteboard-channel.test.d.ts +0 -2
- package/dist/__tests__/whiteboard-channel.test.d.ts.map +0 -1
- package/dist/__tests__/whiteboard-channel.test.js +0 -260
- package/dist/__tests__/whiteboard-channel.test.js.map +0 -1
- package/dist/__tests__/whiteboard-restore-state.test.d.ts +0 -2
- package/dist/__tests__/whiteboard-restore-state.test.d.ts.map +0 -1
- package/dist/__tests__/whiteboard-restore-state.test.js +0 -108
- package/dist/__tests__/whiteboard-restore-state.test.js.map +0 -1
- package/dist/lib/components/mention/mention-dropdown.component.d.ts +0 -53
- package/dist/lib/components/mention/mention-dropdown.component.d.ts.map +0 -1
- package/dist/lib/components/mention/mention-dropdown.component.js +0 -276
- package/dist/lib/components/mention/mention-dropdown.component.js.map +0 -1
- package/dist/lib/components/mention/mention-editor.component.d.ts +0 -256
- package/dist/lib/components/mention/mention-editor.component.d.ts.map +0 -1
- package/dist/lib/components/mention/mention-editor.component.js +0 -1233
- package/dist/lib/components/mention/mention-editor.component.js.map +0 -1
- package/dist/lib/components/message/message-input-box.component.d.ts +0 -137
- package/dist/lib/components/message/message-input-box.component.d.ts.map +0 -1
- package/dist/lib/components/message/message-input-box.component.js +0 -321
- package/dist/lib/components/message/message-input-box.component.js.map +0 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Pure, browser-and-node-safe helpers for the CLIENT-DIRECT realtime recorder:
|
|
3
|
+
* encoding accumulated Float32 PCM into a seekable 16-bit PCM **WAV** container and computing a
|
|
4
|
+
* bounded, downsampled waveform **peak** array at capture time.
|
|
5
|
+
*
|
|
6
|
+
* These functions are deliberately free of any browser API (`AudioContext`, `Blob`, …) so they can
|
|
7
|
+
* be unit-tested in a plain Node environment. {@link RealtimeAudioRecorder} owns the live audio
|
|
8
|
+
* graph and feeds the captured samples here.
|
|
9
|
+
*
|
|
10
|
+
* Why WAV (PCM) over webm/opus: a RIFF/WAVE header carries the exact duration and maps a byte
|
|
11
|
+
* offset linearly to a time offset, so HTTP-range seeking is exact (no client-side duration nudge),
|
|
12
|
+
* and peak extraction is trivial. The tradeoff is size — PCM WAV is larger than opus — which is
|
|
13
|
+
* acceptable for these short session recordings.
|
|
14
|
+
*
|
|
15
|
+
* @module @memberjunction/ng-conversations/realtime-pcm-wav
|
|
16
|
+
*/
|
|
17
|
+
/** Canonical WAV/PCM header size in bytes (RIFF + fmt + data chunk headers). */
|
|
18
|
+
export declare const WAV_HEADER_BYTES = 44;
|
|
19
|
+
/**
|
|
20
|
+
* Encodes mono Float32 PCM samples as a canonical single-chunk 16-bit PCM WAV (RIFF/WAVE).
|
|
21
|
+
* The returned `ArrayBuffer` is `WAV_HEADER_BYTES + samples.length * 2` bytes — a proper
|
|
22
|
+
* 44-byte header followed by little-endian PCM16 data, so it is seekable and self-describing.
|
|
23
|
+
*
|
|
24
|
+
* @param samples Mono Float32 PCM in `[-1, 1]` (downmixed by the caller).
|
|
25
|
+
* @param sampleRate Sample rate in Hz (from the capturing `AudioContext`).
|
|
26
|
+
* @returns A standalone `ArrayBuffer` containing the full WAV file.
|
|
27
|
+
*/
|
|
28
|
+
export declare function encodePcm16Wav(samples: Float32Array, sampleRate: number): ArrayBuffer;
|
|
29
|
+
/**
|
|
30
|
+
* A bounded, streaming waveform-peak accumulator. It maintains a fixed number of buckets
|
|
31
|
+
* (`targetBuckets`) of max-absolute amplitude across the WHOLE recording regardless of length:
|
|
32
|
+
* once every bucket has absorbed `samplesPerBucket` samples, the buckets are halved (pairwise
|
|
33
|
+
* max-merged) and the per-bucket capacity doubles — so memory + cost stay O(targetBuckets) for an
|
|
34
|
+
* arbitrarily long call. {@link Normalize} returns the final 0..1 peaks.
|
|
35
|
+
*/
|
|
36
|
+
export declare class PeakAccumulator {
|
|
37
|
+
/** Target (max) number of buckets in the produced peak array. */
|
|
38
|
+
private readonly targetBuckets;
|
|
39
|
+
/** Current max-abs amplitude per bucket (length grows up to `2 * targetBuckets` before folding). */
|
|
40
|
+
private buckets;
|
|
41
|
+
/** How many samples each bucket currently absorbs before a new bucket opens. */
|
|
42
|
+
private samplesPerBucket;
|
|
43
|
+
/** Samples absorbed into the current (last) bucket so far. */
|
|
44
|
+
private samplesInCurrent;
|
|
45
|
+
/**
|
|
46
|
+
* @param targetBuckets Desired bucket count (waveform resolution). Clamped to >= 1.
|
|
47
|
+
* ~600 gives a smooth overview waveform at trivial cost.
|
|
48
|
+
*/
|
|
49
|
+
constructor(targetBuckets?: number);
|
|
50
|
+
/** Number of buckets currently held (for tests/inspection). */
|
|
51
|
+
get BucketCount(): number;
|
|
52
|
+
/** Absorbs a block of Float32 PCM samples, updating the running per-bucket max-abs. */
|
|
53
|
+
Push(samples: Float32Array): void;
|
|
54
|
+
/** Absorbs one sample into the current bucket, opening/folding buckets as capacity is reached. */
|
|
55
|
+
private pushSample;
|
|
56
|
+
/** Pairwise max-merges adjacent buckets, halving the count and doubling per-bucket capacity. */
|
|
57
|
+
private fold;
|
|
58
|
+
/**
|
|
59
|
+
* Produces the final normalized peak array (each value 0..1, divided by the global max).
|
|
60
|
+
* Trailing empty buckets are trimmed; an all-silent / empty recording yields `[]`.
|
|
61
|
+
*/
|
|
62
|
+
Normalize(): number[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* One-shot peak downsampling of a complete Float32 PCM buffer into `targetBuckets` normalized
|
|
66
|
+
* max-abs peaks (0..1). The streaming {@link PeakAccumulator} is the production path; this is the
|
|
67
|
+
* direct, allocation-light equivalent used where the whole buffer is already in hand (and in tests).
|
|
68
|
+
*
|
|
69
|
+
* @param samples The full mono Float32 PCM buffer.
|
|
70
|
+
* @param targetBuckets Desired bucket count (clamped to >= 1). Buckets beyond the sample count are
|
|
71
|
+
* not produced — a short buffer yields at most `samples.length` peaks.
|
|
72
|
+
* @returns Normalized peaks; `[]` for an empty or all-silent buffer.
|
|
73
|
+
*/
|
|
74
|
+
export declare function downsamplePeaks(samples: Float32Array, targetBuckets?: number): number[];
|
|
75
|
+
//# sourceMappingURL=realtime-pcm-wav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-pcm-wav.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-pcm-wav.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,gFAAgF;AAChF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAcnC;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,CAkCrF;AASD;;;;;;GAMG;AACH,qBAAa,eAAe;IACxB,iEAAiE;IACjE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,oGAAoG;IACpG,OAAO,CAAC,OAAO,CAAgB;IAC/B,gFAAgF;IAChF,OAAO,CAAC,gBAAgB,CAAK;IAC7B,8DAA8D;IAC9D,OAAO,CAAC,gBAAgB,CAAK;IAE7B;;;OAGG;gBACS,aAAa,SAAM;IAI/B,+DAA+D;IAC/D,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,uFAAuF;IAChF,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAMxC,kGAAkG;IAClG,OAAO,CAAC,UAAU;IAsBlB,gGAAgG;IAChG,OAAO,CAAC,IAAI;IAYZ;;;OAGG;IACI,SAAS,IAAI,MAAM,EAAE;CAgB/B;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,aAAa,SAAM,GAAG,MAAM,EAAE,CA4BpF"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Pure, browser-and-node-safe helpers for the CLIENT-DIRECT realtime recorder:
|
|
3
|
+
* encoding accumulated Float32 PCM into a seekable 16-bit PCM **WAV** container and computing a
|
|
4
|
+
* bounded, downsampled waveform **peak** array at capture time.
|
|
5
|
+
*
|
|
6
|
+
* These functions are deliberately free of any browser API (`AudioContext`, `Blob`, …) so they can
|
|
7
|
+
* be unit-tested in a plain Node environment. {@link RealtimeAudioRecorder} owns the live audio
|
|
8
|
+
* graph and feeds the captured samples here.
|
|
9
|
+
*
|
|
10
|
+
* Why WAV (PCM) over webm/opus: a RIFF/WAVE header carries the exact duration and maps a byte
|
|
11
|
+
* offset linearly to a time offset, so HTTP-range seeking is exact (no client-side duration nudge),
|
|
12
|
+
* and peak extraction is trivial. The tradeoff is size — PCM WAV is larger than opus — which is
|
|
13
|
+
* acceptable for these short session recordings.
|
|
14
|
+
*
|
|
15
|
+
* @module @memberjunction/ng-conversations/realtime-pcm-wav
|
|
16
|
+
*/
|
|
17
|
+
/** Lowest value representable by signed 16-bit PCM. */
|
|
18
|
+
const PCM16_MIN = -32768;
|
|
19
|
+
/** Highest value representable by signed 16-bit PCM. */
|
|
20
|
+
const PCM16_MAX = 32767;
|
|
21
|
+
/** Canonical WAV/PCM header size in bytes (RIFF + fmt + data chunk headers). */
|
|
22
|
+
export const WAV_HEADER_BYTES = 44;
|
|
23
|
+
/**
|
|
24
|
+
* Converts one Float32 sample (nominally in `[-1, 1]`) to a clamped signed 16-bit integer.
|
|
25
|
+
* Out-of-range values (a hot mix can briefly exceed unity) are clamped, not wrapped.
|
|
26
|
+
*/
|
|
27
|
+
function floatToPcm16(sample) {
|
|
28
|
+
const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;
|
|
29
|
+
// Asymmetric scaling: negative full-scale is -32768, positive is +32767.
|
|
30
|
+
const scaled = clamped < 0 ? clamped * -PCM16_MIN : clamped * PCM16_MAX;
|
|
31
|
+
const rounded = Math.round(scaled);
|
|
32
|
+
return rounded < PCM16_MIN ? PCM16_MIN : rounded > PCM16_MAX ? PCM16_MAX : rounded;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Encodes mono Float32 PCM samples as a canonical single-chunk 16-bit PCM WAV (RIFF/WAVE).
|
|
36
|
+
* The returned `ArrayBuffer` is `WAV_HEADER_BYTES + samples.length * 2` bytes — a proper
|
|
37
|
+
* 44-byte header followed by little-endian PCM16 data, so it is seekable and self-describing.
|
|
38
|
+
*
|
|
39
|
+
* @param samples Mono Float32 PCM in `[-1, 1]` (downmixed by the caller).
|
|
40
|
+
* @param sampleRate Sample rate in Hz (from the capturing `AudioContext`).
|
|
41
|
+
* @returns A standalone `ArrayBuffer` containing the full WAV file.
|
|
42
|
+
*/
|
|
43
|
+
export function encodePcm16Wav(samples, sampleRate) {
|
|
44
|
+
const numChannels = 1;
|
|
45
|
+
const bitsPerSample = 16;
|
|
46
|
+
const bytesPerSample = bitsPerSample / 8;
|
|
47
|
+
const blockAlign = numChannels * bytesPerSample;
|
|
48
|
+
const byteRate = sampleRate * blockAlign;
|
|
49
|
+
const dataSize = samples.length * bytesPerSample;
|
|
50
|
+
const buffer = new ArrayBuffer(WAV_HEADER_BYTES + dataSize);
|
|
51
|
+
const view = new DataView(buffer);
|
|
52
|
+
writeAscii(view, 0, 'RIFF');
|
|
53
|
+
view.setUint32(4, 36 + dataSize, true); // ChunkSize = 36 + Subchunk2Size
|
|
54
|
+
writeAscii(view, 8, 'WAVE');
|
|
55
|
+
writeAscii(view, 12, 'fmt ');
|
|
56
|
+
view.setUint32(16, 16, true); // Subchunk1Size (16 for PCM)
|
|
57
|
+
view.setUint16(20, 1, true); // AudioFormat = PCM
|
|
58
|
+
view.setUint16(22, numChannels, true);
|
|
59
|
+
view.setUint32(24, sampleRate, true);
|
|
60
|
+
view.setUint32(28, byteRate, true);
|
|
61
|
+
view.setUint16(32, blockAlign, true);
|
|
62
|
+
view.setUint16(34, bitsPerSample, true);
|
|
63
|
+
writeAscii(view, 36, 'data');
|
|
64
|
+
view.setUint32(40, dataSize, true);
|
|
65
|
+
let offset = WAV_HEADER_BYTES;
|
|
66
|
+
for (let i = 0; i < samples.length; i++) {
|
|
67
|
+
view.setInt16(offset, floatToPcm16(samples[i]), true);
|
|
68
|
+
offset += bytesPerSample;
|
|
69
|
+
}
|
|
70
|
+
return buffer;
|
|
71
|
+
}
|
|
72
|
+
/** Writes an ASCII string into a {@link DataView} byte-by-byte at `offset`. */
|
|
73
|
+
function writeAscii(view, offset, text) {
|
|
74
|
+
for (let i = 0; i < text.length; i++) {
|
|
75
|
+
view.setUint8(offset + i, text.charCodeAt(i));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* A bounded, streaming waveform-peak accumulator. It maintains a fixed number of buckets
|
|
80
|
+
* (`targetBuckets`) of max-absolute amplitude across the WHOLE recording regardless of length:
|
|
81
|
+
* once every bucket has absorbed `samplesPerBucket` samples, the buckets are halved (pairwise
|
|
82
|
+
* max-merged) and the per-bucket capacity doubles — so memory + cost stay O(targetBuckets) for an
|
|
83
|
+
* arbitrarily long call. {@link Normalize} returns the final 0..1 peaks.
|
|
84
|
+
*/
|
|
85
|
+
export class PeakAccumulator {
|
|
86
|
+
/** Target (max) number of buckets in the produced peak array. */
|
|
87
|
+
targetBuckets;
|
|
88
|
+
/** Current max-abs amplitude per bucket (length grows up to `2 * targetBuckets` before folding). */
|
|
89
|
+
buckets = [];
|
|
90
|
+
/** How many samples each bucket currently absorbs before a new bucket opens. */
|
|
91
|
+
samplesPerBucket = 1;
|
|
92
|
+
/** Samples absorbed into the current (last) bucket so far. */
|
|
93
|
+
samplesInCurrent = 0;
|
|
94
|
+
/**
|
|
95
|
+
* @param targetBuckets Desired bucket count (waveform resolution). Clamped to >= 1.
|
|
96
|
+
* ~600 gives a smooth overview waveform at trivial cost.
|
|
97
|
+
*/
|
|
98
|
+
constructor(targetBuckets = 600) {
|
|
99
|
+
this.targetBuckets = Math.max(1, Math.floor(targetBuckets));
|
|
100
|
+
}
|
|
101
|
+
/** Number of buckets currently held (for tests/inspection). */
|
|
102
|
+
get BucketCount() {
|
|
103
|
+
return this.buckets.length;
|
|
104
|
+
}
|
|
105
|
+
/** Absorbs a block of Float32 PCM samples, updating the running per-bucket max-abs. */
|
|
106
|
+
Push(samples) {
|
|
107
|
+
for (let i = 0; i < samples.length; i++) {
|
|
108
|
+
this.pushSample(samples[i]);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** Absorbs one sample into the current bucket, opening/folding buckets as capacity is reached. */
|
|
112
|
+
pushSample(sample) {
|
|
113
|
+
if (this.buckets.length === 0) {
|
|
114
|
+
this.buckets.push(0);
|
|
115
|
+
this.samplesInCurrent = 0;
|
|
116
|
+
}
|
|
117
|
+
const abs = sample < 0 ? -sample : sample;
|
|
118
|
+
const last = this.buckets.length - 1;
|
|
119
|
+
if (abs > this.buckets[last]) {
|
|
120
|
+
this.buckets[last] = abs;
|
|
121
|
+
}
|
|
122
|
+
this.samplesInCurrent++;
|
|
123
|
+
if (this.samplesInCurrent >= this.samplesPerBucket) {
|
|
124
|
+
this.buckets.push(0);
|
|
125
|
+
this.samplesInCurrent = 0;
|
|
126
|
+
// Keep the bucket array bounded: once it reaches 2x the target, fold pairwise so the
|
|
127
|
+
// resolution stays under the cap while the per-bucket sample capacity doubles.
|
|
128
|
+
if (this.buckets.length >= this.targetBuckets * 2) {
|
|
129
|
+
this.fold();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Pairwise max-merges adjacent buckets, halving the count and doubling per-bucket capacity. */
|
|
134
|
+
fold() {
|
|
135
|
+
const folded = [];
|
|
136
|
+
for (let i = 0; i < this.buckets.length; i += 2) {
|
|
137
|
+
const a = this.buckets[i];
|
|
138
|
+
const b = i + 1 < this.buckets.length ? this.buckets[i + 1] : 0;
|
|
139
|
+
folded.push(a > b ? a : b);
|
|
140
|
+
}
|
|
141
|
+
this.buckets = folded;
|
|
142
|
+
this.samplesPerBucket *= 2;
|
|
143
|
+
this.samplesInCurrent = 0;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Produces the final normalized peak array (each value 0..1, divided by the global max).
|
|
147
|
+
* Trailing empty buckets are trimmed; an all-silent / empty recording yields `[]`.
|
|
148
|
+
*/
|
|
149
|
+
Normalize() {
|
|
150
|
+
// Drop a trailing freshly-opened empty bucket that absorbed nothing.
|
|
151
|
+
const raw = this.buckets.length > 0 && this.samplesInCurrent === 0 && this.buckets.length > 1
|
|
152
|
+
? this.buckets.slice(0, -1)
|
|
153
|
+
: this.buckets.slice();
|
|
154
|
+
let max = 0;
|
|
155
|
+
for (const v of raw) {
|
|
156
|
+
if (v > max) {
|
|
157
|
+
max = v;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (max <= 0) {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
return raw.map(v => v / max);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* One-shot peak downsampling of a complete Float32 PCM buffer into `targetBuckets` normalized
|
|
168
|
+
* max-abs peaks (0..1). The streaming {@link PeakAccumulator} is the production path; this is the
|
|
169
|
+
* direct, allocation-light equivalent used where the whole buffer is already in hand (and in tests).
|
|
170
|
+
*
|
|
171
|
+
* @param samples The full mono Float32 PCM buffer.
|
|
172
|
+
* @param targetBuckets Desired bucket count (clamped to >= 1). Buckets beyond the sample count are
|
|
173
|
+
* not produced — a short buffer yields at most `samples.length` peaks.
|
|
174
|
+
* @returns Normalized peaks; `[]` for an empty or all-silent buffer.
|
|
175
|
+
*/
|
|
176
|
+
export function downsamplePeaks(samples, targetBuckets = 600) {
|
|
177
|
+
const target = Math.max(1, Math.floor(targetBuckets));
|
|
178
|
+
if (samples.length === 0) {
|
|
179
|
+
return [];
|
|
180
|
+
}
|
|
181
|
+
const buckets = Math.min(target, samples.length);
|
|
182
|
+
const samplesPerBucket = samples.length / buckets;
|
|
183
|
+
const peaks = new Array(buckets).fill(0);
|
|
184
|
+
let globalMax = 0;
|
|
185
|
+
for (let b = 0; b < buckets; b++) {
|
|
186
|
+
const start = Math.floor(b * samplesPerBucket);
|
|
187
|
+
const end = b === buckets - 1 ? samples.length : Math.floor((b + 1) * samplesPerBucket);
|
|
188
|
+
let localMax = 0;
|
|
189
|
+
for (let i = start; i < end; i++) {
|
|
190
|
+
const abs = samples[i] < 0 ? -samples[i] : samples[i];
|
|
191
|
+
if (abs > localMax) {
|
|
192
|
+
localMax = abs;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
peaks[b] = localMax;
|
|
196
|
+
if (localMax > globalMax) {
|
|
197
|
+
globalMax = localMax;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (globalMax <= 0) {
|
|
201
|
+
return [];
|
|
202
|
+
}
|
|
203
|
+
return peaks.map(v => v / globalMax);
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=realtime-pcm-wav.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-pcm-wav.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-pcm-wav.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Pure, browser-and-node-safe helpers for the CLIENT-DIRECT realtime recorder:\n * encoding accumulated Float32 PCM into a seekable 16-bit PCM **WAV** container and computing a\n * bounded, downsampled waveform **peak** array at capture time.\n *\n * These functions are deliberately free of any browser API (`AudioContext`, `Blob`, …) so they can\n * be unit-tested in a plain Node environment. {@link RealtimeAudioRecorder} owns the live audio\n * graph and feeds the captured samples here.\n *\n * Why WAV (PCM) over webm/opus: a RIFF/WAVE header carries the exact duration and maps a byte\n * offset linearly to a time offset, so HTTP-range seeking is exact (no client-side duration nudge),\n * and peak extraction is trivial. The tradeoff is size — PCM WAV is larger than opus — which is\n * acceptable for these short session recordings.\n *\n * @module @memberjunction/ng-conversations/realtime-pcm-wav\n */\n\n/** Lowest value representable by signed 16-bit PCM. */\nconst PCM16_MIN = -32768;\n/** Highest value representable by signed 16-bit PCM. */\nconst PCM16_MAX = 32767;\n/** Canonical WAV/PCM header size in bytes (RIFF + fmt + data chunk headers). */\nexport const WAV_HEADER_BYTES = 44;\n\n/**\n * Converts one Float32 sample (nominally in `[-1, 1]`) to a clamped signed 16-bit integer.\n * Out-of-range values (a hot mix can briefly exceed unity) are clamped, not wrapped.\n */\nfunction floatToPcm16(sample: number): number {\n const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;\n // Asymmetric scaling: negative full-scale is -32768, positive is +32767.\n const scaled = clamped < 0 ? clamped * -PCM16_MIN : clamped * PCM16_MAX;\n const rounded = Math.round(scaled);\n return rounded < PCM16_MIN ? PCM16_MIN : rounded > PCM16_MAX ? PCM16_MAX : rounded;\n}\n\n/**\n * Encodes mono Float32 PCM samples as a canonical single-chunk 16-bit PCM WAV (RIFF/WAVE).\n * The returned `ArrayBuffer` is `WAV_HEADER_BYTES + samples.length * 2` bytes — a proper\n * 44-byte header followed by little-endian PCM16 data, so it is seekable and self-describing.\n *\n * @param samples Mono Float32 PCM in `[-1, 1]` (downmixed by the caller).\n * @param sampleRate Sample rate in Hz (from the capturing `AudioContext`).\n * @returns A standalone `ArrayBuffer` containing the full WAV file.\n */\nexport function encodePcm16Wav(samples: Float32Array, sampleRate: number): ArrayBuffer {\n const numChannels = 1;\n const bitsPerSample = 16;\n const bytesPerSample = bitsPerSample / 8;\n const blockAlign = numChannels * bytesPerSample;\n const byteRate = sampleRate * blockAlign;\n const dataSize = samples.length * bytesPerSample;\n\n const buffer = new ArrayBuffer(WAV_HEADER_BYTES + dataSize);\n const view = new DataView(buffer);\n\n writeAscii(view, 0, 'RIFF');\n view.setUint32(4, 36 + dataSize, true); // ChunkSize = 36 + Subchunk2Size\n writeAscii(view, 8, 'WAVE');\n\n writeAscii(view, 12, 'fmt ');\n view.setUint32(16, 16, true); // Subchunk1Size (16 for PCM)\n view.setUint16(20, 1, true); // AudioFormat = PCM\n view.setUint16(22, numChannels, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, byteRate, true);\n view.setUint16(32, blockAlign, true);\n view.setUint16(34, bitsPerSample, true);\n\n writeAscii(view, 36, 'data');\n view.setUint32(40, dataSize, true);\n\n let offset = WAV_HEADER_BYTES;\n for (let i = 0; i < samples.length; i++) {\n view.setInt16(offset, floatToPcm16(samples[i]), true);\n offset += bytesPerSample;\n }\n\n return buffer;\n}\n\n/** Writes an ASCII string into a {@link DataView} byte-by-byte at `offset`. */\nfunction writeAscii(view: DataView, offset: number, text: string): void {\n for (let i = 0; i < text.length; i++) {\n view.setUint8(offset + i, text.charCodeAt(i));\n }\n}\n\n/**\n * A bounded, streaming waveform-peak accumulator. It maintains a fixed number of buckets\n * (`targetBuckets`) of max-absolute amplitude across the WHOLE recording regardless of length:\n * once every bucket has absorbed `samplesPerBucket` samples, the buckets are halved (pairwise\n * max-merged) and the per-bucket capacity doubles — so memory + cost stay O(targetBuckets) for an\n * arbitrarily long call. {@link Normalize} returns the final 0..1 peaks.\n */\nexport class PeakAccumulator {\n /** Target (max) number of buckets in the produced peak array. */\n private readonly targetBuckets: number;\n /** Current max-abs amplitude per bucket (length grows up to `2 * targetBuckets` before folding). */\n private buckets: number[] = [];\n /** How many samples each bucket currently absorbs before a new bucket opens. */\n private samplesPerBucket = 1;\n /** Samples absorbed into the current (last) bucket so far. */\n private samplesInCurrent = 0;\n\n /**\n * @param targetBuckets Desired bucket count (waveform resolution). Clamped to >= 1.\n * ~600 gives a smooth overview waveform at trivial cost.\n */\n constructor(targetBuckets = 600) {\n this.targetBuckets = Math.max(1, Math.floor(targetBuckets));\n }\n\n /** Number of buckets currently held (for tests/inspection). */\n public get BucketCount(): number {\n return this.buckets.length;\n }\n\n /** Absorbs a block of Float32 PCM samples, updating the running per-bucket max-abs. */\n public Push(samples: Float32Array): void {\n for (let i = 0; i < samples.length; i++) {\n this.pushSample(samples[i]);\n }\n }\n\n /** Absorbs one sample into the current bucket, opening/folding buckets as capacity is reached. */\n private pushSample(sample: number): void {\n if (this.buckets.length === 0) {\n this.buckets.push(0);\n this.samplesInCurrent = 0;\n }\n const abs = sample < 0 ? -sample : sample;\n const last = this.buckets.length - 1;\n if (abs > this.buckets[last]) {\n this.buckets[last] = abs;\n }\n this.samplesInCurrent++;\n if (this.samplesInCurrent >= this.samplesPerBucket) {\n this.buckets.push(0);\n this.samplesInCurrent = 0;\n // Keep the bucket array bounded: once it reaches 2x the target, fold pairwise so the\n // resolution stays under the cap while the per-bucket sample capacity doubles.\n if (this.buckets.length >= this.targetBuckets * 2) {\n this.fold();\n }\n }\n }\n\n /** Pairwise max-merges adjacent buckets, halving the count and doubling per-bucket capacity. */\n private fold(): void {\n const folded: number[] = [];\n for (let i = 0; i < this.buckets.length; i += 2) {\n const a = this.buckets[i];\n const b = i + 1 < this.buckets.length ? this.buckets[i + 1] : 0;\n folded.push(a > b ? a : b);\n }\n this.buckets = folded;\n this.samplesPerBucket *= 2;\n this.samplesInCurrent = 0;\n }\n\n /**\n * Produces the final normalized peak array (each value 0..1, divided by the global max).\n * Trailing empty buckets are trimmed; an all-silent / empty recording yields `[]`.\n */\n public Normalize(): number[] {\n // Drop a trailing freshly-opened empty bucket that absorbed nothing.\n const raw = this.buckets.length > 0 && this.samplesInCurrent === 0 && this.buckets.length > 1\n ? this.buckets.slice(0, -1)\n : this.buckets.slice();\n let max = 0;\n for (const v of raw) {\n if (v > max) {\n max = v;\n }\n }\n if (max <= 0) {\n return [];\n }\n return raw.map(v => v / max);\n }\n}\n\n/**\n * One-shot peak downsampling of a complete Float32 PCM buffer into `targetBuckets` normalized\n * max-abs peaks (0..1). The streaming {@link PeakAccumulator} is the production path; this is the\n * direct, allocation-light equivalent used where the whole buffer is already in hand (and in tests).\n *\n * @param samples The full mono Float32 PCM buffer.\n * @param targetBuckets Desired bucket count (clamped to >= 1). Buckets beyond the sample count are\n * not produced — a short buffer yields at most `samples.length` peaks.\n * @returns Normalized peaks; `[]` for an empty or all-silent buffer.\n */\nexport function downsamplePeaks(samples: Float32Array, targetBuckets = 600): number[] {\n const target = Math.max(1, Math.floor(targetBuckets));\n if (samples.length === 0) {\n return [];\n }\n const buckets = Math.min(target, samples.length);\n const samplesPerBucket = samples.length / buckets;\n const peaks = new Array<number>(buckets).fill(0);\n let globalMax = 0;\n for (let b = 0; b < buckets; b++) {\n const start = Math.floor(b * samplesPerBucket);\n const end = b === buckets - 1 ? samples.length : Math.floor((b + 1) * samplesPerBucket);\n let localMax = 0;\n for (let i = start; i < end; i++) {\n const abs = samples[i] < 0 ? -samples[i] : samples[i];\n if (abs > localMax) {\n localMax = abs;\n }\n }\n peaks[b] = localMax;\n if (localMax > globalMax) {\n globalMax = localMax;\n }\n }\n if (globalMax <= 0) {\n return [];\n }\n return peaks.map(v => v / globalMax);\n}\n"]}
|
|
@@ -8,14 +8,31 @@ import * as i0 from "@angular/core";
|
|
|
8
8
|
* legacy row was closed before the column existed.
|
|
9
9
|
*/
|
|
10
10
|
export type RealtimeReviewCloseReason = 'Error' | 'Explicit' | 'Janitor' | 'Shutdown';
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* One historical caption turn of a reviewed session (a persisted `MJ: Conversation Details` row).
|
|
13
|
+
*
|
|
14
|
+
* Carries BOTH the thread-rendering fields (`Role`/`Text`/`At`) AND the raw fields the time-aligned
|
|
15
|
+
* evidence player reads (`ID`, `Message`, `__mj_CreatedAt`, `UtteranceStartMs`, `UtteranceEndMs`) so
|
|
16
|
+
* a review's turns can be handed straight to {@link RealtimeEvidencePlaybackComponent} for the
|
|
17
|
+
* Recording tab — this shape structurally satisfies that player's `EvidencePlaybackTurn` input.
|
|
18
|
+
*/
|
|
12
19
|
export interface RealtimeSessionReviewTurn {
|
|
20
|
+
/** `MJ: Conversation Details.ID` — the player's `@for` track key. */
|
|
21
|
+
ID: string;
|
|
13
22
|
/** Who spoke the turn. Persisted `AI` rows map to `Assistant`. */
|
|
14
23
|
Role: 'User' | 'Assistant';
|
|
15
24
|
/** The transcript text. */
|
|
16
25
|
Text: string;
|
|
26
|
+
/** The raw transcript text (mirrors {@link Text}) — the player reads `Message`. */
|
|
27
|
+
Message: string | null;
|
|
28
|
+
/** When the turn was persisted (`__mj_CreatedAt`), or null when unknown. Aliases {@link At}. */
|
|
29
|
+
__mj_CreatedAt: Date | null;
|
|
17
30
|
/** When the turn was persisted (`__mj_CreatedAt`), or null when unknown. */
|
|
18
31
|
At: Date | null;
|
|
32
|
+
/** Precise media-relative start (ms from recording t0), or null when the driver supplied no timing. */
|
|
33
|
+
UtteranceStartMs: number | null;
|
|
34
|
+
/** Precise media-relative end (ms from recording t0), or null. */
|
|
35
|
+
UtteranceEndMs: number | null;
|
|
19
36
|
}
|
|
20
37
|
/**
|
|
21
38
|
* A compact preview of one DELEGATED agent run the reviewed session spawned (an
|
|
@@ -108,6 +125,16 @@ export interface RealtimeSessionReview {
|
|
|
108
125
|
StartedAt: Date | null;
|
|
109
126
|
LastActiveAt: Date | null;
|
|
110
127
|
ClosedAt: Date | null;
|
|
128
|
+
/**
|
|
129
|
+
* The `MJ: Files` id of the reviewed session's recorded audio, or null when nothing was recorded.
|
|
130
|
+
* When set, review mode resolves a signed download URL and shows a Recording tab with the
|
|
131
|
+
* time-aligned evidence player. From the PRIMARY (reviewed) leg only.
|
|
132
|
+
*/
|
|
133
|
+
RecordingFileID: string | null;
|
|
134
|
+
/** Recording alignment origin (t0), used by the playback transcript sync. From the primary leg. */
|
|
135
|
+
RecordingStartedAt: Date | null;
|
|
136
|
+
/** What was captured (`Audio` / `AudioVideo`), or null. From the primary leg. */
|
|
137
|
+
RecordingMedia: string | null;
|
|
111
138
|
/** Chronological caption turns (oldest first) — ALL legs of the chain, flattened. */
|
|
112
139
|
Turns: RealtimeSessionReviewTurn[];
|
|
113
140
|
/** Delegated run previews (oldest first, all legs), minus each leg's co-agent observability run. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-session-review.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-session-review.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAoC,MAAM,sBAAsB,CAAC;AAE3F,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AAC7G,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;;AAEtE;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;AAEtF
|
|
1
|
+
{"version":3,"file":"realtime-session-review.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-session-review.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,8 +33,8 @@ export function MergeChainChannelStates(legChannelStates) {
|
|
|
33
33
|
}
|
|
34
34
|
return [...byName.values()];
|
|
35
35
|
}
|
|
36
|
-
const SESSION_FIELDS = ['ID', 'AgentID', 'Agent', 'Status', 'ConversationID', 'Config', 'LastSessionID', 'LastActiveAt', 'ClosedAt', 'CloseReason', '__mj_CreatedAt'];
|
|
37
|
-
const DETAIL_FIELDS = ['ID', 'Role', 'Message', 'HiddenToUser', '__mj_CreatedAt'];
|
|
36
|
+
const SESSION_FIELDS = ['ID', 'AgentID', 'Agent', 'Status', 'ConversationID', 'Config', 'LastSessionID', 'LastActiveAt', 'ClosedAt', 'CloseReason', 'RecordingFileID', 'RecordingStartedAt', 'RecordingMedia', '__mj_CreatedAt'];
|
|
37
|
+
const DETAIL_FIELDS = ['ID', 'Role', 'Message', 'HiddenToUser', 'UserID', 'Status', 'UtteranceStartMs', 'UtteranceEndMs', '__mj_CreatedAt'];
|
|
38
38
|
const RUN_FIELDS = ['ID', 'AgentID', 'Agent', 'Status', 'Success', 'Message', 'ErrorMessage', 'FinalStep', 'StartedAt', 'CompletedAt'];
|
|
39
39
|
const CHANNEL_FIELDS = ['ID', 'Channel', 'Config'];
|
|
40
40
|
const JUNCTION_FIELDS = ['ID', 'ConversationDetailID', 'ArtifactVersionID'];
|
|
@@ -326,6 +326,9 @@ export class RealtimeSessionReviewService {
|
|
|
326
326
|
StartedAt: this.toDate(session.__mj_CreatedAt),
|
|
327
327
|
LastActiveAt: this.toDate(session.LastActiveAt),
|
|
328
328
|
ClosedAt: this.toDate(session.ClosedAt),
|
|
329
|
+
RecordingFileID: session.RecordingFileID ?? null,
|
|
330
|
+
RecordingStartedAt: this.toDate(session.RecordingStartedAt),
|
|
331
|
+
RecordingMedia: session.RecordingMedia ?? null,
|
|
329
332
|
Turns: legs.flatMap(l => l.Turns),
|
|
330
333
|
DelegatedRuns: legs.flatMap(l => l.DelegatedRuns),
|
|
331
334
|
// Multi-leg: newest leg with a SAVED state wins per channel — a final leg that
|
|
@@ -355,10 +358,16 @@ export class RealtimeSessionReviewService {
|
|
|
355
358
|
if (row.HiddenToUser || text.length === 0 || (row.Role !== 'User' && row.Role !== 'AI')) {
|
|
356
359
|
continue;
|
|
357
360
|
}
|
|
361
|
+
const createdAt = this.toDate(row.__mj_CreatedAt);
|
|
358
362
|
turns.push({
|
|
363
|
+
ID: row.ID,
|
|
359
364
|
Role: row.Role === 'AI' ? 'Assistant' : 'User',
|
|
360
365
|
Text: text,
|
|
361
|
-
|
|
366
|
+
Message: text,
|
|
367
|
+
__mj_CreatedAt: createdAt,
|
|
368
|
+
At: createdAt,
|
|
369
|
+
UtteranceStartMs: row.UtteranceStartMs ?? null,
|
|
370
|
+
UtteranceEndMs: row.UtteranceEndMs ?? null
|
|
362
371
|
});
|
|
363
372
|
}
|
|
364
373
|
return turns;
|