@memberjunction/ng-conversations 6.2.0-edge.3 → 6.2.0-edge.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -7
- package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-view.component.js +1 -0
- package/dist/lib/components/collection/collection-view.component.js.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.d.ts +14 -2
- package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.js +35 -4
- package/dist/lib/components/composer/ai-composer.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +588 -51
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +2654 -665
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/forks-popover.component.d.ts +37 -0
- package/dist/lib/components/conversation/forks-popover.component.d.ts.map +1 -0
- package/dist/lib/components/conversation/forks-popover.component.js +164 -0
- package/dist/lib/components/conversation/forks-popover.component.js.map +1 -0
- package/dist/lib/components/export/export-modal.component.d.ts +7 -2
- package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
- package/dist/lib/components/export/export-modal.component.js +16 -3
- package/dist/lib/components/export/export-modal.component.js.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.js +11 -9
- package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +96 -11
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +244 -103
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +171 -4
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +899 -298
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +82 -21
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +299 -52
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts +34 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js +75 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts +80 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js +202 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts +45 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js +123 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts +90 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.js +223 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts +98 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.js +161 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts +48 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js +205 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts +19 -2
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/client-context-channel.js +83 -9
- package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -1
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +30 -9
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +78 -14
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -1
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts +71 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js +259 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts +129 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.js +373 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.js.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts +77 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js +420 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.d.ts +83 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.js +292 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts +39 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.js +152 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts +109 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.js +146 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts +19 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.js +39 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts +183 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js +761 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts +25 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.js +57 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts +40 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js +97 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts +144 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.js +57 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts +36 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.js +55 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts +55 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js +210 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts +32 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js +90 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts +7 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/media/media-channel.js +28 -1
- package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +8 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.js +89 -71
- package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts +21 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.js +49 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +44 -11
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.js +162 -50
- package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +8 -2
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.js +14 -18
- package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.d.ts +42 -2
- package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.js +137 -102
- package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts +71 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.js +221 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +264 -22
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.js +851 -135
- package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts +14 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.js +14 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts +74 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.js +171 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +71 -13
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js +232 -73
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +5 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js +8 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.d.ts +12 -2
- package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.js +5 -1
- package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +10 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +42 -2
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts +20 -3
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js +44 -10
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +28 -44
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +76 -162
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
- 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 +25 -12
- package/dist/lib/components/search/search-panel.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +22 -31
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +50 -63
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/conversations.module.d.ts +30 -29
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +27 -5
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/events/chat-events.d.ts +25 -0
- package/dist/lib/events/chat-events.d.ts.map +1 -1
- package/dist/lib/events/chat-events.js +36 -0
- package/dist/lib/events/chat-events.js.map +1 -1
- package/dist/lib/models/agent-turn.model.d.ts +5 -0
- package/dist/lib/models/agent-turn.model.d.ts.map +1 -1
- package/dist/lib/models/agent-turn.model.js.map +1 -1
- package/dist/lib/services/agent-state.service.d.ts +34 -8
- package/dist/lib/services/agent-state.service.d.ts.map +1 -1
- package/dist/lib/services/agent-state.service.js +82 -29
- package/dist/lib/services/agent-state.service.js.map +1 -1
- package/dist/lib/services/artifact-state.service.d.ts +0 -9
- package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-state.service.js +1 -32
- package/dist/lib/services/artifact-state.service.js.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.d.ts +12 -0
- package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.js +19 -0
- package/dist/lib/services/browser-realtime-media-host.js.map +1 -1
- package/dist/lib/services/browser-recording-unload-guard.d.ts +30 -0
- package/dist/lib/services/browser-recording-unload-guard.d.ts.map +1 -0
- package/dist/lib/services/browser-recording-unload-guard.js +43 -0
- package/dist/lib/services/browser-recording-unload-guard.js.map +1 -0
- package/dist/lib/services/conversation-agent.service.d.ts +35 -11
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +65 -20
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-detail-window.store.d.ts +22 -4
- package/dist/lib/services/conversation-detail-window.store.d.ts.map +1 -1
- package/dist/lib/services/conversation-detail-window.store.js +50 -9
- package/dist/lib/services/conversation-detail-window.store.js.map +1 -1
- package/dist/lib/services/conversation-naming.d.ts +72 -22
- package/dist/lib/services/conversation-naming.d.ts.map +1 -1
- package/dist/lib/services/conversation-naming.js +84 -10
- package/dist/lib/services/conversation-naming.js.map +1 -1
- package/dist/lib/services/data-cache.service.d.ts +13 -5
- package/dist/lib/services/data-cache.service.d.ts.map +1 -1
- package/dist/lib/services/data-cache.service.js +39 -19
- package/dist/lib/services/data-cache.service.js.map +1 -1
- package/dist/lib/services/export.service.d.ts +26 -9
- package/dist/lib/services/export.service.d.ts.map +1 -1
- package/dist/lib/services/export.service.js +61 -18
- package/dist/lib/services/export.service.js.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.d.ts +33 -5
- package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.js +71 -11
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
- package/dist/lib/services/realtime-pairing.d.ts +10 -5
- package/dist/lib/services/realtime-pairing.d.ts.map +1 -1
- package/dist/lib/services/realtime-pairing.js +15 -6
- package/dist/lib/services/realtime-pairing.js.map +1 -1
- package/dist/lib/services/realtime-session.service.d.ts +3 -2
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session.service.js +7 -2
- package/dist/lib/services/realtime-session.service.js.map +1 -1
- package/dist/lib/services/search.service.d.ts +7 -2
- package/dist/lib/services/search.service.d.ts.map +1 -1
- package/dist/lib/services/search.service.js +13 -4
- package/dist/lib/services/search.service.js.map +1 -1
- package/dist/lib/utils/conversation-branching.d.ts +4 -0
- package/dist/lib/utils/conversation-branching.d.ts.map +1 -0
- package/dist/lib/utils/conversation-branching.js +5 -0
- package/dist/lib/utils/conversation-branching.js.map +1 -0
- package/dist/lib/utils/conversation-forks.d.ts +315 -0
- package/dist/lib/utils/conversation-forks.d.ts.map +1 -0
- package/dist/lib/utils/conversation-forks.js +456 -0
- package/dist/lib/utils/conversation-forks.js.map +1 -0
- package/dist/public-api.d.ts +23 -1
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +30 -1
- package/dist/public-api.js.map +1 -1
- package/package.json +37 -33
- package/dist/lib/components/thread/thread-panel.component.d.ts +0 -126
- package/dist/lib/components/thread/thread-panel.component.d.ts.map +0 -1
- package/dist/lib/components/thread/thread-panel.component.js +0 -440
- package/dist/lib/components/thread/thread-panel.component.js.map +0 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Type } from '@angular/core';
|
|
2
|
+
import type { RealtimeTrackDescriptor } from '@memberjunction/ai';
|
|
3
|
+
import { type RealtimeChannelDescriptor } from '@memberjunction/ai-core-plus';
|
|
4
|
+
import { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';
|
|
5
|
+
import { RealtimeAvatarSurfaceComponent } from './realtime-avatar-surface.component';
|
|
6
|
+
/** The registry keys (`MJ: AI Agent Channels` → `Name` and `ClientPluginClass`) of the Avatar channel. */
|
|
7
|
+
export declare const REALTIME_AVATAR_CHANNEL_NAME = "Avatar";
|
|
8
|
+
export declare const REALTIME_AVATAR_CHANNEL_CLASS = "RealtimeAvatarChannel";
|
|
9
|
+
/**
|
|
10
|
+
* The AVATAR channel: the agent's video, when the model sends it (an avatar).
|
|
11
|
+
*
|
|
12
|
+
* **In every call, inert without video.** It is open from the start of every call (`all-sessions`, `open-on-start`) and
|
|
13
|
+
* gives the agent nothing: no verbs, no nouns and no instructions, so the agent's channel note leaves it out, and it
|
|
14
|
+
* shows the agent nothing (`MaxExposure: 'none'`). It sinks outbound video, so the session requests the agent's video
|
|
15
|
+
* when it connects; a model that sends none reports that track unsupported, and the channel stays out of sight. When the
|
|
16
|
+
* video arrives, the runtime marks the channel as used, so the host shows its surface where its registry row places it.
|
|
17
|
+
*
|
|
18
|
+
* Its server half is the generic `ClientOnlyChannelServer`.
|
|
19
|
+
*/
|
|
20
|
+
export declare class RealtimeAvatarChannel extends BaseRealtimeChannelClient<RealtimeAvatarSurfaceComponent> {
|
|
21
|
+
get ChannelName(): string;
|
|
22
|
+
get TabTitle(): string;
|
|
23
|
+
get TabIcon(): string;
|
|
24
|
+
GetDescriptor(): RealtimeChannelDescriptor;
|
|
25
|
+
GetSunkTracks(): readonly RealtimeTrackDescriptor[];
|
|
26
|
+
GetSurfaceComponent(): Type<RealtimeAvatarSurfaceComponent>;
|
|
27
|
+
BindSurface(instance: RealtimeAvatarSurfaceComponent): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Tree-shaking prevention: the channel is resolved through the ClassFactory by its registry row's `ClientPluginClass`
|
|
31
|
+
* key, so this static call keeps its `@RegisterClass` side effect alive.
|
|
32
|
+
*/
|
|
33
|
+
export declare function LoadRealtimeAvatarChannel(): void;
|
|
34
|
+
//# sourceMappingURL=realtime-avatar-channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-avatar-channel.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/avatar/realtime-avatar-channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAqC,KAAK,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACjH,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAC7E,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AAErF,0GAA0G;AAC1G,eAAO,MAAM,4BAA4B,WAAW,CAAC;AACrD,eAAO,MAAM,6BAA6B,0BAA0B,CAAC;AAKrE;;;;;;;;;;GAUG;AACH,qBACa,qBAAsB,SAAQ,yBAAyB,CAAC,8BAA8B,CAAC;IAClG,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,IAAoB,QAAQ,IAAI,MAAM,CAErC;IAED,IAAoB,OAAO,IAAI,MAAM,CAEpC;IAEe,aAAa,IAAI,yBAAyB;IAe1C,aAAa,IAAI,SAAS,uBAAuB,EAAE;IAInD,mBAAmB,IAAI,IAAI,CAAC,8BAA8B,CAAC;IAI3D,WAAW,CAAC,QAAQ,EAAE,8BAA8B,GAAG,IAAI;CAM5E;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
8
|
+
import { REALTIME_CHANNEL_CONTRACT_VERSION } from '@memberjunction/ai-core-plus';
|
|
9
|
+
import { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';
|
|
10
|
+
import { RealtimeAvatarSurfaceComponent } from './realtime-avatar-surface.component';
|
|
11
|
+
/** The registry keys (`MJ: AI Agent Channels` → `Name` and `ClientPluginClass`) of the Avatar channel. */
|
|
12
|
+
export const REALTIME_AVATAR_CHANNEL_NAME = 'Avatar';
|
|
13
|
+
export const REALTIME_AVATAR_CHANNEL_CLASS = 'RealtimeAvatarChannel';
|
|
14
|
+
/** What the Avatar channel sinks: the agent's video, in whatever encoding the model sends. */
|
|
15
|
+
const AGENT_VIDEO_TRACK = { Modality: 'video', Direction: 'outbound' };
|
|
16
|
+
/**
|
|
17
|
+
* The AVATAR channel: the agent's video, when the model sends it (an avatar).
|
|
18
|
+
*
|
|
19
|
+
* **In every call, inert without video.** It is open from the start of every call (`all-sessions`, `open-on-start`) and
|
|
20
|
+
* gives the agent nothing: no verbs, no nouns and no instructions, so the agent's channel note leaves it out, and it
|
|
21
|
+
* shows the agent nothing (`MaxExposure: 'none'`). It sinks outbound video, so the session requests the agent's video
|
|
22
|
+
* when it connects; a model that sends none reports that track unsupported, and the channel stays out of sight. When the
|
|
23
|
+
* video arrives, the runtime marks the channel as used, so the host shows its surface where its registry row places it.
|
|
24
|
+
*
|
|
25
|
+
* Its server half is the generic `ClientOnlyChannelServer`.
|
|
26
|
+
*/
|
|
27
|
+
let RealtimeAvatarChannel = class RealtimeAvatarChannel extends BaseRealtimeChannelClient {
|
|
28
|
+
get ChannelName() {
|
|
29
|
+
return REALTIME_AVATAR_CHANNEL_NAME;
|
|
30
|
+
}
|
|
31
|
+
get TabTitle() {
|
|
32
|
+
return 'Avatar';
|
|
33
|
+
}
|
|
34
|
+
get TabIcon() {
|
|
35
|
+
return 'fa-solid fa-circle-user';
|
|
36
|
+
}
|
|
37
|
+
GetDescriptor() {
|
|
38
|
+
return {
|
|
39
|
+
Key: REALTIME_AVATAR_CHANNEL_NAME,
|
|
40
|
+
Version: REALTIME_CHANNEL_CONTRACT_VERSION,
|
|
41
|
+
DisplayName: 'Avatar',
|
|
42
|
+
OwningPackage: '@memberjunction/ng-conversations',
|
|
43
|
+
Instructions: '',
|
|
44
|
+
Nouns: [],
|
|
45
|
+
Verbs: [],
|
|
46
|
+
DisplayPolicy: 'open-on-start',
|
|
47
|
+
DefaultAvailability: 'all-sessions',
|
|
48
|
+
MaxExposure: 'none',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
GetSunkTracks() {
|
|
52
|
+
return [AGENT_VIDEO_TRACK];
|
|
53
|
+
}
|
|
54
|
+
GetSurfaceComponent() {
|
|
55
|
+
return RealtimeAvatarSurfaceComponent;
|
|
56
|
+
}
|
|
57
|
+
BindSurface(instance) {
|
|
58
|
+
instance.AgentName = this.Context?.AgentName ?? 'The assistant';
|
|
59
|
+
instance.Video$ = this.Context?.AgentVideo$ ?? null;
|
|
60
|
+
instance.State$ = this.Context?.ConnectionState$ ?? null;
|
|
61
|
+
instance.Resuming$ = this.Context?.Resuming$ ?? null;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
RealtimeAvatarChannel = __decorate([
|
|
65
|
+
RegisterClass(BaseRealtimeChannelClient, REALTIME_AVATAR_CHANNEL_CLASS)
|
|
66
|
+
], RealtimeAvatarChannel);
|
|
67
|
+
export { RealtimeAvatarChannel };
|
|
68
|
+
/**
|
|
69
|
+
* Tree-shaking prevention: the channel is resolved through the ClassFactory by its registry row's `ClientPluginClass`
|
|
70
|
+
* key, so this static call keeps its `@RegisterClass` side effect alive.
|
|
71
|
+
*/
|
|
72
|
+
export function LoadRealtimeAvatarChannel() {
|
|
73
|
+
// intentional no-op: the import side effect performs the registration
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=realtime-avatar-channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-avatar-channel.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/avatar/realtime-avatar-channel.ts"],"names":[],"mappings":";;;;;;AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,EAAE,iCAAiC,EAAkC,MAAM,8BAA8B,CAAC;AACjH,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAC7E,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AAErF,0GAA0G;AAC1G,MAAM,CAAC,MAAM,4BAA4B,GAAG,QAAQ,CAAC;AACrD,MAAM,CAAC,MAAM,6BAA6B,GAAG,uBAAuB,CAAC;AAErE,8FAA8F;AAC9F,MAAM,iBAAiB,GAA4B,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;AAEhG;;;;;;;;;;GAUG;AAEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,yBAAyD;IAClG,IAAW,WAAW;QACpB,OAAO,4BAA4B,CAAC;IACtC,CAAC;IAED,IAAoB,QAAQ;QAC1B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAoB,OAAO;QACzB,OAAO,yBAAyB,CAAC;IACnC,CAAC;IAEe,aAAa;QAC3B,OAAO;YACL,GAAG,EAAE,4BAA4B;YACjC,OAAO,EAAE,iCAAiC;YAC1C,WAAW,EAAE,QAAQ;YACrB,aAAa,EAAE,kCAAkC;YACjD,YAAY,EAAE,EAAE;YAChB,KAAK,EAAE,EAAE;YACT,KAAK,EAAE,EAAE;YACT,aAAa,EAAE,eAAe;YAC9B,mBAAmB,EAAE,cAAc;YACnC,WAAW,EAAE,MAAM;SACpB,CAAC;IACJ,CAAC;IAEe,aAAa;QAC3B,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC7B,CAAC;IAEe,mBAAmB;QACjC,OAAO,8BAA8B,CAAC;IACxC,CAAC;IAEe,WAAW,CAAC,QAAwC;QAClE,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,IAAI,eAAe,CAAC;QAChE,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,IAAI,IAAI,CAAC;QACpD,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,gBAAgB,IAAI,IAAI,CAAC;QACzD,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC;IACvD,CAAC;CACF,CAAA;AA1CY,qBAAqB;IADjC,aAAa,CAAC,yBAAyB,EAAE,6BAA6B,CAAC;GAC3D,qBAAqB,CA0CjC;;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB;IACvC,sEAAsE;AACxE,CAAC","sourcesContent":["import type { Type } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport type { RealtimeTrackDescriptor } from '@memberjunction/ai';\nimport { REALTIME_CHANNEL_CONTRACT_VERSION, type RealtimeChannelDescriptor } from '@memberjunction/ai-core-plus';\nimport { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';\nimport { RealtimeAvatarSurfaceComponent } from './realtime-avatar-surface.component';\n\n/** The registry keys (`MJ: AI Agent Channels` → `Name` and `ClientPluginClass`) of the Avatar channel. */\nexport const REALTIME_AVATAR_CHANNEL_NAME = 'Avatar';\nexport const REALTIME_AVATAR_CHANNEL_CLASS = 'RealtimeAvatarChannel';\n\n/** What the Avatar channel sinks: the agent's video, in whatever encoding the model sends. */\nconst AGENT_VIDEO_TRACK: RealtimeTrackDescriptor = { Modality: 'video', Direction: 'outbound' };\n\n/**\n * The AVATAR channel: the agent's video, when the model sends it (an avatar).\n *\n * **In every call, inert without video.** It is open from the start of every call (`all-sessions`, `open-on-start`) and\n * gives the agent nothing: no verbs, no nouns and no instructions, so the agent's channel note leaves it out, and it\n * shows the agent nothing (`MaxExposure: 'none'`). It sinks outbound video, so the session requests the agent's video\n * when it connects; a model that sends none reports that track unsupported, and the channel stays out of sight. When the\n * video arrives, the runtime marks the channel as used, so the host shows its surface where its registry row places it.\n *\n * Its server half is the generic `ClientOnlyChannelServer`.\n */\n@RegisterClass(BaseRealtimeChannelClient, REALTIME_AVATAR_CHANNEL_CLASS)\nexport class RealtimeAvatarChannel extends BaseRealtimeChannelClient<RealtimeAvatarSurfaceComponent> {\n public get ChannelName(): string {\n return REALTIME_AVATAR_CHANNEL_NAME;\n }\n\n public override get TabTitle(): string {\n return 'Avatar';\n }\n\n public override get TabIcon(): string {\n return 'fa-solid fa-circle-user';\n }\n\n public override GetDescriptor(): RealtimeChannelDescriptor {\n return {\n Key: REALTIME_AVATAR_CHANNEL_NAME,\n Version: REALTIME_CHANNEL_CONTRACT_VERSION,\n DisplayName: 'Avatar',\n OwningPackage: '@memberjunction/ng-conversations',\n Instructions: '',\n Nouns: [],\n Verbs: [],\n DisplayPolicy: 'open-on-start',\n DefaultAvailability: 'all-sessions',\n MaxExposure: 'none',\n };\n }\n\n public override GetSunkTracks(): readonly RealtimeTrackDescriptor[] {\n return [AGENT_VIDEO_TRACK];\n }\n\n public override GetSurfaceComponent(): Type<RealtimeAvatarSurfaceComponent> {\n return RealtimeAvatarSurfaceComponent;\n }\n\n public override BindSurface(instance: RealtimeAvatarSurfaceComponent): void {\n instance.AgentName = this.Context?.AgentName ?? 'The assistant';\n instance.Video$ = this.Context?.AgentVideo$ ?? null;\n instance.State$ = this.Context?.ConnectionState$ ?? null;\n instance.Resuming$ = this.Context?.Resuming$ ?? null;\n }\n}\n\n/**\n * Tree-shaking prevention: the channel is resolved through the ClassFactory by its registry row's `ClientPluginClass`\n * key, so this static call keeps its `@RegisterClass` side effect alive.\n */\nexport function LoadRealtimeAvatarChannel(): void {\n // intentional no-op: the import side effect performs the registration\n}\n"]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { OnDestroy } from '@angular/core';
|
|
2
|
+
import type { Observable } from 'rxjs';
|
|
3
|
+
import type { MediaParticipant, MediaVideoSource } from '@memberjunction/ai-realtime-client/media';
|
|
4
|
+
import type { RealtimeConnectionState } from '@memberjunction/realtime-runtime';
|
|
5
|
+
import { type RealtimeAgentOrbState } from '../realtime-agent-orb.component';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
/** After this long without a frame, the agent's video gives way to its placeholder (plan §5: about a second). */
|
|
8
|
+
export declare const AGENT_VIDEO_STALL_MS = 1000;
|
|
9
|
+
/**
|
|
10
|
+
* How long the agent's last frame can hold while the call resumes on a new connection, from the resume's start, before
|
|
11
|
+
* the orb takes its place (plan §5). New video came about 3 s after each move in the live runs on Vertex AI.
|
|
12
|
+
*/
|
|
13
|
+
export declare const AGENT_VIDEO_RESUME_HOLD_MS = 5000;
|
|
14
|
+
/**
|
|
15
|
+
* `mj-realtime-avatar-surface`: the Avatar channel's surface. The agent's video (an avatar) in a media tile, with the
|
|
16
|
+
* agent's name and the "AI-generated video" label the tile shows while it plays an avatar, and a chip that says what the
|
|
17
|
+
* agent is doing. A ring frames the tile while the agent speaks, following its voice where the call overlay meters it.
|
|
18
|
+
* Until the video's first frame, and after {@link AGENT_VIDEO_STALL_MS} without one, the call's orb takes its place,
|
|
19
|
+
* following the agent's turn. While the call resumes on a new connection, the last frame holds instead, until new
|
|
20
|
+
* frames come, {@link AGENT_VIDEO_RESUME_HOLD_MS} pass, or the call fails or ends.
|
|
21
|
+
*/
|
|
22
|
+
export declare class RealtimeAvatarSurfaceComponent implements OnDestroy {
|
|
23
|
+
private readonly cdr;
|
|
24
|
+
private agentName;
|
|
25
|
+
private video;
|
|
26
|
+
private video$;
|
|
27
|
+
private videoSub;
|
|
28
|
+
private state$;
|
|
29
|
+
private stateSub;
|
|
30
|
+
private resuming$;
|
|
31
|
+
private resumingSub;
|
|
32
|
+
/** The last value {@link Resuming$} gave: a hold starts when a resume does. */
|
|
33
|
+
private resuming;
|
|
34
|
+
/** Ends the hold {@link AGENT_VIDEO_RESUME_HOLD_MS} after the resume started. */
|
|
35
|
+
private holdTimer;
|
|
36
|
+
/** The agent's turn, as the orb shows it. */
|
|
37
|
+
OrbState: RealtimeAgentOrbState;
|
|
38
|
+
/** What the tile's chip says the agent is doing, or `null` before the call's state is known. */
|
|
39
|
+
StatusLabel: string | null;
|
|
40
|
+
/** The agent as the tile shows it. */
|
|
41
|
+
Agent: MediaParticipant;
|
|
42
|
+
/** How long without a frame the tile waits before showing the placeholder. */
|
|
43
|
+
readonly StallAfterMs = 1000;
|
|
44
|
+
/**
|
|
45
|
+
* Whether the tile keeps the agent's last frame on show while the video is out of frames: from the start of a resume
|
|
46
|
+
* until new frames come, {@link AGENT_VIDEO_RESUME_HOLD_MS} pass, or the call fails or ends.
|
|
47
|
+
*/
|
|
48
|
+
HoldLastFrame: boolean;
|
|
49
|
+
/** The agent's name, shown on the tile. */
|
|
50
|
+
set AgentName(value: string);
|
|
51
|
+
get AgentName(): string;
|
|
52
|
+
/** The agent's video, now and on every change (the session's `AgentVideo$`). */
|
|
53
|
+
set Video$(value: Observable<MediaVideoSource | null> | null);
|
|
54
|
+
get Video$(): Observable<MediaVideoSource | null> | null;
|
|
55
|
+
/**
|
|
56
|
+
* The call's state, now and on every change (the session's `ConnectionState$`): the orb follows the agent's turn, and
|
|
57
|
+
* an error or the call's end stops holding the last frame.
|
|
58
|
+
*/
|
|
59
|
+
set State$(value: Observable<RealtimeConnectionState> | null);
|
|
60
|
+
get State$(): Observable<RealtimeConnectionState> | null;
|
|
61
|
+
/**
|
|
62
|
+
* Whether the call is resuming on a new connection, now and on every change (the session's `Resuming$`): a resume's
|
|
63
|
+
* start holds the agent's last frame ({@link HoldLastFrame}).
|
|
64
|
+
*/
|
|
65
|
+
set Resuming$(value: Observable<boolean> | null);
|
|
66
|
+
get Resuming$(): Observable<boolean> | null;
|
|
67
|
+
/** The tile's frames stopped or came back: frames that come back end a hold. */
|
|
68
|
+
OnFramesFlowingChange(flowing: boolean): void;
|
|
69
|
+
ngOnDestroy(): void;
|
|
70
|
+
/** A resume that starts holds the last frame; the hold ends on its own terms, not when the resume does. */
|
|
71
|
+
private onResuming;
|
|
72
|
+
/** Holds the last frame for up to {@link AGENT_VIDEO_RESUME_HOLD_MS}, counted again from a new resume's start. */
|
|
73
|
+
private startHold;
|
|
74
|
+
/** Stops holding the last frame: the orb shows if the video is still out of frames. */
|
|
75
|
+
private endHold;
|
|
76
|
+
private clearHoldTimer;
|
|
77
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeAvatarSurfaceComponent, never>;
|
|
78
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeAvatarSurfaceComponent, "mj-realtime-avatar-surface", never, { "AgentName": { "alias": "AgentName"; "required": false; }; "Video$": { "alias": "Video$"; "required": false; }; "State$": { "alias": "State$"; "required": false; }; "Resuming$": { "alias": "Resuming$"; "required": false; }; }, {}, never, never, true, never>;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=realtime-avatar-surface.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-avatar-surface.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/avatar/realtime-avatar-surface.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgE,SAAS,EAAU,MAAM,eAAe,CAAC;AAChH,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,MAAM,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACnG,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAEhF,OAAO,EAA+C,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;;AAE1H,iHAAiH;AACjH,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC;;;GAGG;AACH,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C;;;;;;;GAOG;AACH,qBAQa,8BAA+B,YAAW,SAAS;IAC9D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IACjD,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,MAAM,CAAoD;IAClE,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,MAAM,CAAoD;IAClE,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,WAAW,CAA6B;IAChD,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAAS;IACzB,iFAAiF;IACjF,OAAO,CAAC,SAAS,CAA8C;IAE/D,6CAA6C;IACtC,QAAQ,EAAE,qBAAqB,CAAe;IAErD,gGAAgG;IACzF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEzC,sCAAsC;IAC/B,KAAK,EAAE,gBAAgB,CAA0C;IAExE,8EAA8E;IAC9E,SAAgB,YAAY,QAAwB;IAEpD;;;OAGG;IACI,aAAa,UAAS;IAE7B,2CAA2C;IAC3C,IACW,SAAS,CAAC,KAAK,EAAE,MAAM,EAGjC;IACD,IAAW,SAAS,IAAI,MAAM,CAE7B;IAED,gFAAgF;IAChF,IACW,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,IAAI,EAYlE;IACD,IAAW,MAAM,IAAI,UAAU,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,IAAI,CAE9D;IAED;;;OAGG;IACH,IACW,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,uBAAuB,CAAC,GAAG,IAAI,EAelE;IACD,IAAW,MAAM,IAAI,UAAU,CAAC,uBAAuB,CAAC,GAAG,IAAI,CAE9D;IAED;;;OAGG;IACH,IACW,SAAS,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,EAQrD;IACD,IAAW,SAAS,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAEjD;IAED,gFAAgF;IACzE,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAM7C,WAAW,IAAI,IAAI;IAU1B,2GAA2G;IAC3G,OAAO,CAAC,UAAU;IAOlB,kHAAkH;IAClH,OAAO,CAAC,SAAS;IAOjB,uFAAuF;IACvF,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,cAAc;yCAnJX,8BAA8B;2CAA9B,8BAA8B;CAyJ1C"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, inject } from '@angular/core';
|
|
2
|
+
import { MediaTileComponent, MediaTilePlaceholderDirective } from '@memberjunction/ng-realtime-media';
|
|
3
|
+
import { AgentOrbStateFor, RealtimeAgentOrbComponent } from '../realtime-agent-orb.component';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/** After this long without a frame, the agent's video gives way to its placeholder (plan §5: about a second). */
|
|
6
|
+
export const AGENT_VIDEO_STALL_MS = 1000;
|
|
7
|
+
/**
|
|
8
|
+
* How long the agent's last frame can hold while the call resumes on a new connection, from the resume's start, before
|
|
9
|
+
* the orb takes its place (plan §5). New video came about 3 s after each move in the live runs on Vertex AI.
|
|
10
|
+
*/
|
|
11
|
+
export const AGENT_VIDEO_RESUME_HOLD_MS = 5000;
|
|
12
|
+
/**
|
|
13
|
+
* `mj-realtime-avatar-surface`: the Avatar channel's surface. The agent's video (an avatar) in a media tile, with the
|
|
14
|
+
* agent's name and the "AI-generated video" label the tile shows while it plays an avatar, and a chip that says what the
|
|
15
|
+
* agent is doing. A ring frames the tile while the agent speaks, following its voice where the call overlay meters it.
|
|
16
|
+
* Until the video's first frame, and after {@link AGENT_VIDEO_STALL_MS} without one, the call's orb takes its place,
|
|
17
|
+
* following the agent's turn. While the call resumes on a new connection, the last frame holds instead, until new
|
|
18
|
+
* frames come, {@link AGENT_VIDEO_RESUME_HOLD_MS} pass, or the call fails or ends.
|
|
19
|
+
*/
|
|
20
|
+
export class RealtimeAvatarSurfaceComponent {
|
|
21
|
+
cdr = inject(ChangeDetectorRef);
|
|
22
|
+
agentName = 'The assistant';
|
|
23
|
+
video = null;
|
|
24
|
+
video$ = null;
|
|
25
|
+
videoSub = null;
|
|
26
|
+
state$ = null;
|
|
27
|
+
stateSub = null;
|
|
28
|
+
resuming$ = null;
|
|
29
|
+
resumingSub = null;
|
|
30
|
+
/** The last value {@link Resuming$} gave: a hold starts when a resume does. */
|
|
31
|
+
resuming = false;
|
|
32
|
+
/** Ends the hold {@link AGENT_VIDEO_RESUME_HOLD_MS} after the resume started. */
|
|
33
|
+
holdTimer = null;
|
|
34
|
+
/** The agent's turn, as the orb shows it. */
|
|
35
|
+
OrbState = 'listening';
|
|
36
|
+
/** What the tile's chip says the agent is doing, or `null` before the call's state is known. */
|
|
37
|
+
StatusLabel = null;
|
|
38
|
+
/** The agent as the tile shows it. */
|
|
39
|
+
Agent = agentParticipant(this.agentName, null);
|
|
40
|
+
/** How long without a frame the tile waits before showing the placeholder. */
|
|
41
|
+
StallAfterMs = AGENT_VIDEO_STALL_MS;
|
|
42
|
+
/**
|
|
43
|
+
* Whether the tile keeps the agent's last frame on show while the video is out of frames: from the start of a resume
|
|
44
|
+
* until new frames come, {@link AGENT_VIDEO_RESUME_HOLD_MS} pass, or the call fails or ends.
|
|
45
|
+
*/
|
|
46
|
+
HoldLastFrame = false;
|
|
47
|
+
/** The agent's name, shown on the tile. */
|
|
48
|
+
set AgentName(value) {
|
|
49
|
+
this.agentName = value;
|
|
50
|
+
this.Agent = agentParticipant(value, this.video);
|
|
51
|
+
}
|
|
52
|
+
get AgentName() {
|
|
53
|
+
return this.agentName;
|
|
54
|
+
}
|
|
55
|
+
/** The agent's video, now and on every change (the session's `AgentVideo$`). */
|
|
56
|
+
set Video$(value) {
|
|
57
|
+
if (value === this.video$) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this.videoSub?.unsubscribe();
|
|
61
|
+
this.video$ = value;
|
|
62
|
+
this.videoSub =
|
|
63
|
+
value?.subscribe((video) => {
|
|
64
|
+
this.video = video;
|
|
65
|
+
this.Agent = agentParticipant(this.agentName, video);
|
|
66
|
+
this.cdr.markForCheck();
|
|
67
|
+
}) ?? null;
|
|
68
|
+
}
|
|
69
|
+
get Video$() {
|
|
70
|
+
return this.video$;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The call's state, now and on every change (the session's `ConnectionState$`): the orb follows the agent's turn, and
|
|
74
|
+
* an error or the call's end stops holding the last frame.
|
|
75
|
+
*/
|
|
76
|
+
set State$(value) {
|
|
77
|
+
if (value === this.state$) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
this.stateSub?.unsubscribe();
|
|
81
|
+
this.state$ = value;
|
|
82
|
+
this.stateSub =
|
|
83
|
+
value?.subscribe((state) => {
|
|
84
|
+
this.OrbState = AgentOrbStateFor(state);
|
|
85
|
+
this.StatusLabel = statusLabelFor(state);
|
|
86
|
+
if (state === 'error' || state === 'closed') {
|
|
87
|
+
this.endHold();
|
|
88
|
+
}
|
|
89
|
+
this.cdr.markForCheck();
|
|
90
|
+
}) ?? null;
|
|
91
|
+
}
|
|
92
|
+
get State$() {
|
|
93
|
+
return this.state$;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Whether the call is resuming on a new connection, now and on every change (the session's `Resuming$`): a resume's
|
|
97
|
+
* start holds the agent's last frame ({@link HoldLastFrame}).
|
|
98
|
+
*/
|
|
99
|
+
set Resuming$(value) {
|
|
100
|
+
if (value === this.resuming$) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
this.resumingSub?.unsubscribe();
|
|
104
|
+
this.resuming$ = value;
|
|
105
|
+
this.resuming = false;
|
|
106
|
+
this.resumingSub = value?.subscribe((resuming) => this.onResuming(resuming)) ?? null;
|
|
107
|
+
}
|
|
108
|
+
get Resuming$() {
|
|
109
|
+
return this.resuming$;
|
|
110
|
+
}
|
|
111
|
+
/** The tile's frames stopped or came back: frames that come back end a hold. */
|
|
112
|
+
OnFramesFlowingChange(flowing) {
|
|
113
|
+
if (flowing) {
|
|
114
|
+
this.endHold();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
ngOnDestroy() {
|
|
118
|
+
this.videoSub?.unsubscribe();
|
|
119
|
+
this.videoSub = null;
|
|
120
|
+
this.stateSub?.unsubscribe();
|
|
121
|
+
this.stateSub = null;
|
|
122
|
+
this.resumingSub?.unsubscribe();
|
|
123
|
+
this.resumingSub = null;
|
|
124
|
+
this.clearHoldTimer();
|
|
125
|
+
}
|
|
126
|
+
/** A resume that starts holds the last frame; the hold ends on its own terms, not when the resume does. */
|
|
127
|
+
onResuming(resuming) {
|
|
128
|
+
if (resuming && !this.resuming) {
|
|
129
|
+
this.startHold();
|
|
130
|
+
}
|
|
131
|
+
this.resuming = resuming;
|
|
132
|
+
}
|
|
133
|
+
/** Holds the last frame for up to {@link AGENT_VIDEO_RESUME_HOLD_MS}, counted again from a new resume's start. */
|
|
134
|
+
startHold() {
|
|
135
|
+
this.clearHoldTimer();
|
|
136
|
+
this.HoldLastFrame = true;
|
|
137
|
+
this.holdTimer = setTimeout(() => this.endHold(), AGENT_VIDEO_RESUME_HOLD_MS);
|
|
138
|
+
this.cdr.markForCheck();
|
|
139
|
+
}
|
|
140
|
+
/** Stops holding the last frame: the orb shows if the video is still out of frames. */
|
|
141
|
+
endHold() {
|
|
142
|
+
this.clearHoldTimer();
|
|
143
|
+
if (this.HoldLastFrame) {
|
|
144
|
+
this.HoldLastFrame = false;
|
|
145
|
+
this.cdr.markForCheck();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
clearHoldTimer() {
|
|
149
|
+
if (this.holdTimer !== null) {
|
|
150
|
+
clearTimeout(this.holdTimer);
|
|
151
|
+
this.holdTimer = null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
static ɵfac = function RealtimeAvatarSurfaceComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RealtimeAvatarSurfaceComponent)(); };
|
|
155
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeAvatarSurfaceComponent, selectors: [["mj-realtime-avatar-surface"]], inputs: { AgentName: "AgentName", Video$: "Video$", State$: "State$", Resuming$: "Resuming$" }, decls: 3, vars: 10, consts: [[1, "avatar"], [1, "avatar__tile", 3, "FramesFlowingChange", "Participant", "ShowMeter", "ShowConnectionQuality", "ShowActiveSpeakerRing", "StallAfterMs", "HoldLastFrame", "Status"], ["mjMediaTilePlaceholder", "", 1, "avatar__orb", 3, "State"]], template: function RealtimeAvatarSurfaceComponent_Template(rf, ctx) { if (rf & 1) {
|
|
156
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "mj-media-tile", 1);
|
|
157
|
+
i0.ɵɵlistener("FramesFlowingChange", function RealtimeAvatarSurfaceComponent_Template_mj_media_tile_FramesFlowingChange_1_listener($event) { return ctx.OnFramesFlowingChange($event); });
|
|
158
|
+
i0.ɵɵelement(2, "mj-realtime-agent-orb", 2);
|
|
159
|
+
i0.ɵɵelementEnd()();
|
|
160
|
+
} if (rf & 2) {
|
|
161
|
+
i0.ɵɵclassProp("avatar--speaking", ctx.OrbState === "speaking");
|
|
162
|
+
i0.ɵɵadvance();
|
|
163
|
+
i0.ɵɵproperty("Participant", ctx.Agent)("ShowMeter", false)("ShowConnectionQuality", false)("ShowActiveSpeakerRing", false)("StallAfterMs", ctx.StallAfterMs)("HoldLastFrame", ctx.HoldLastFrame)("Status", ctx.StatusLabel);
|
|
164
|
+
i0.ɵɵadvance();
|
|
165
|
+
i0.ɵɵproperty("State", ctx.OrbState);
|
|
166
|
+
} }, dependencies: [MediaTileComponent, MediaTilePlaceholderDirective, RealtimeAgentOrbComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n \n container-type: size;\n}\n\n.avatar[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n height: 100%;\n border-radius: 12px;\n}\n\n\n\n.avatar[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n transition: box-shadow 140ms ease;\n}\n\n.avatar--speaking[_ngcontent-%COMP%]::after {\n box-shadow: inset 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 70%, transparent);\n}\n\n\n.call-overlay[data-audio-live='true'][_nghost-%COMP%] .avatar--speaking[_ngcontent-%COMP%]::after, .call-overlay[data-audio-live='true'] [_nghost-%COMP%] .avatar--speaking[_ngcontent-%COMP%]::after {\n box-shadow: inset 0 0 0 calc(2px + var(--voice-out, 0) * 6px) color-mix(in srgb, var(--mj-brand-primary) 70%, transparent);\n transition: box-shadow 70ms linear;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .avatar[_ngcontent-%COMP%]::after {\n transition: none;\n }\n}\n\n\n.avatar__orb[_ngcontent-%COMP%] {\n --mj-realtime-orb-size: 30cqmin;\n}"], changeDetection: 0 });
|
|
167
|
+
}
|
|
168
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeAvatarSurfaceComponent, [{
|
|
169
|
+
type: Component,
|
|
170
|
+
args: [{ standalone: true, selector: 'mj-realtime-avatar-surface', imports: [MediaTileComponent, MediaTilePlaceholderDirective, RealtimeAgentOrbComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"avatar\" [class.avatar--speaking]=\"OrbState === 'speaking'\">\n <mj-media-tile\n class=\"avatar__tile\"\n [Participant]=\"Agent\"\n [ShowMeter]=\"false\"\n [ShowConnectionQuality]=\"false\"\n [ShowActiveSpeakerRing]=\"false\"\n [StallAfterMs]=\"StallAfterMs\"\n [HoldLastFrame]=\"HoldLastFrame\"\n [Status]=\"StatusLabel\"\n (FramesFlowingChange)=\"OnFramesFlowingChange($event)\">\n <mj-realtime-agent-orb mjMediaTilePlaceholder class=\"avatar__orb\" [State]=\"OrbState\"></mj-realtime-agent-orb>\n </mj-media-tile>\n</div>\n", styles: [":host {\n display: block;\n width: 100%;\n height: 100%;\n /* The orb sizes itself to this surface, wherever it is placed. */\n container-type: size;\n}\n\n.avatar {\n position: relative;\n width: 100%;\n height: 100%;\n border-radius: 12px;\n}\n\n/* The ring that frames the agent's tile while it speaks: inside the tile's edge, so the box the stage gives the surface\n never clips it. */\n.avatar::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n transition: box-shadow 140ms ease;\n}\n\n.avatar--speaking::after {\n box-shadow: inset 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 70%, transparent);\n}\n\n/* Where the call overlay meters the agent's voice, the ring follows it (--voice-out, inherited). */\n:host-context(.call-overlay[data-audio-live='true']) .avatar--speaking::after {\n box-shadow: inset 0 0 0 calc(2px + var(--voice-out, 0) * 6px) color-mix(in srgb, var(--mj-brand-primary) 70%, transparent);\n transition: box-shadow 70ms linear;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .avatar::after {\n transition: none;\n }\n}\n\n/* The orb's diameter: about a third of the surface's shorter side, so its rings fit. */\n.avatar__orb {\n --mj-realtime-orb-size: 30cqmin;\n}\n"] }]
|
|
171
|
+
}], null, { AgentName: [{
|
|
172
|
+
type: Input
|
|
173
|
+
}], Video$: [{
|
|
174
|
+
type: Input
|
|
175
|
+
}], State$: [{
|
|
176
|
+
type: Input
|
|
177
|
+
}], Resuming$: [{
|
|
178
|
+
type: Input
|
|
179
|
+
}] }); })();
|
|
180
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RealtimeAvatarSurfaceComponent, { className: "RealtimeAvatarSurfaceComponent", filePath: "src/lib/components/realtime/avatar/realtime-avatar-surface.component.ts", lineNumber: 33 }); })();
|
|
181
|
+
/** What the tile's chip says for a state of the call, or `null` for none (the call has ended). */
|
|
182
|
+
function statusLabelFor(state) {
|
|
183
|
+
switch (state) {
|
|
184
|
+
case 'speaking':
|
|
185
|
+
return 'Speaking';
|
|
186
|
+
case 'thinking':
|
|
187
|
+
return 'Thinking';
|
|
188
|
+
case 'listening':
|
|
189
|
+
return 'Listening';
|
|
190
|
+
case 'connecting':
|
|
191
|
+
return 'Connecting';
|
|
192
|
+
case 'error':
|
|
193
|
+
return 'Connection error';
|
|
194
|
+
default:
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/** The agent as a media tile shows it: its name, and its video as the avatar when there is one. */
|
|
199
|
+
function agentParticipant(name, video) {
|
|
200
|
+
return { Identity: 'agent', DisplayName: name, Role: 'agent', IsSpeaking: false, Video: video ? { avatar: video } : {} };
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=realtime-avatar-surface.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-avatar-surface.component.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/avatar/realtime-avatar-surface.component.ts","../../../../../src/lib/components/realtime/avatar/realtime-avatar-surface.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, inject } from '@angular/core';\nimport type { Observable, Subscription } from 'rxjs';\nimport type { MediaParticipant, MediaVideoSource } from '@memberjunction/ai-realtime-client/media';\nimport type { RealtimeConnectionState } from '@memberjunction/realtime-runtime';\nimport { MediaTileComponent, MediaTilePlaceholderDirective } from '@memberjunction/ng-realtime-media';\nimport { AgentOrbStateFor, RealtimeAgentOrbComponent, type RealtimeAgentOrbState } from '../realtime-agent-orb.component';\n\n/** After this long without a frame, the agent's video gives way to its placeholder (plan §5: about a second). */\nexport const AGENT_VIDEO_STALL_MS = 1000;\n\n/**\n * How long the agent's last frame can hold while the call resumes on a new connection, from the resume's start, before\n * the orb takes its place (plan §5). New video came about 3 s after each move in the live runs on Vertex AI.\n */\nexport const AGENT_VIDEO_RESUME_HOLD_MS = 5000;\n\n/**\n * `mj-realtime-avatar-surface`: the Avatar channel's surface. The agent's video (an avatar) in a media tile, with the\n * agent's name and the \"AI-generated video\" label the tile shows while it plays an avatar, and a chip that says what the\n * agent is doing. A ring frames the tile while the agent speaks, following its voice where the call overlay meters it.\n * Until the video's first frame, and after {@link AGENT_VIDEO_STALL_MS} without one, the call's orb takes its place,\n * following the agent's turn. While the call resumes on a new connection, the last frame holds instead, until new\n * frames come, {@link AGENT_VIDEO_RESUME_HOLD_MS} pass, or the call fails or ends.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-avatar-surface',\n imports: [MediaTileComponent, MediaTilePlaceholderDirective, RealtimeAgentOrbComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './realtime-avatar-surface.component.html',\n styleUrls: ['./realtime-avatar-surface.component.css'],\n})\nexport class RealtimeAvatarSurfaceComponent implements OnDestroy {\n private readonly cdr = inject(ChangeDetectorRef);\n private agentName = 'The assistant';\n private video: MediaVideoSource | null = null;\n private video$: Observable<MediaVideoSource | null> | null = null;\n private videoSub: Subscription | null = null;\n private state$: Observable<RealtimeConnectionState> | null = null;\n private stateSub: Subscription | null = null;\n private resuming$: Observable<boolean> | null = null;\n private resumingSub: Subscription | null = null;\n /** The last value {@link Resuming$} gave: a hold starts when a resume does. */\n private resuming = false;\n /** Ends the hold {@link AGENT_VIDEO_RESUME_HOLD_MS} after the resume started. */\n private holdTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** The agent's turn, as the orb shows it. */\n public OrbState: RealtimeAgentOrbState = 'listening';\n\n /** What the tile's chip says the agent is doing, or `null` before the call's state is known. */\n public StatusLabel: string | null = null;\n\n /** The agent as the tile shows it. */\n public Agent: MediaParticipant = agentParticipant(this.agentName, null);\n\n /** How long without a frame the tile waits before showing the placeholder. */\n public readonly StallAfterMs = AGENT_VIDEO_STALL_MS;\n\n /**\n * Whether the tile keeps the agent's last frame on show while the video is out of frames: from the start of a resume\n * until new frames come, {@link AGENT_VIDEO_RESUME_HOLD_MS} pass, or the call fails or ends.\n */\n public HoldLastFrame = false;\n\n /** The agent's name, shown on the tile. */\n @Input()\n public set AgentName(value: string) {\n this.agentName = value;\n this.Agent = agentParticipant(value, this.video);\n }\n public get AgentName(): string {\n return this.agentName;\n }\n\n /** The agent's video, now and on every change (the session's `AgentVideo$`). */\n @Input()\n public set Video$(value: Observable<MediaVideoSource | null> | null) {\n if (value === this.video$) {\n return;\n }\n this.videoSub?.unsubscribe();\n this.video$ = value;\n this.videoSub =\n value?.subscribe((video) => {\n this.video = video;\n this.Agent = agentParticipant(this.agentName, video);\n this.cdr.markForCheck();\n }) ?? null;\n }\n public get Video$(): Observable<MediaVideoSource | null> | null {\n return this.video$;\n }\n\n /**\n * The call's state, now and on every change (the session's `ConnectionState$`): the orb follows the agent's turn, and\n * an error or the call's end stops holding the last frame.\n */\n @Input()\n public set State$(value: Observable<RealtimeConnectionState> | null) {\n if (value === this.state$) {\n return;\n }\n this.stateSub?.unsubscribe();\n this.state$ = value;\n this.stateSub =\n value?.subscribe((state) => {\n this.OrbState = AgentOrbStateFor(state);\n this.StatusLabel = statusLabelFor(state);\n if (state === 'error' || state === 'closed') {\n this.endHold();\n }\n this.cdr.markForCheck();\n }) ?? null;\n }\n public get State$(): Observable<RealtimeConnectionState> | null {\n return this.state$;\n }\n\n /**\n * Whether the call is resuming on a new connection, now and on every change (the session's `Resuming$`): a resume's\n * start holds the agent's last frame ({@link HoldLastFrame}).\n */\n @Input()\n public set Resuming$(value: Observable<boolean> | null) {\n if (value === this.resuming$) {\n return;\n }\n this.resumingSub?.unsubscribe();\n this.resuming$ = value;\n this.resuming = false;\n this.resumingSub = value?.subscribe((resuming) => this.onResuming(resuming)) ?? null;\n }\n public get Resuming$(): Observable<boolean> | null {\n return this.resuming$;\n }\n\n /** The tile's frames stopped or came back: frames that come back end a hold. */\n public OnFramesFlowingChange(flowing: boolean): void {\n if (flowing) {\n this.endHold();\n }\n }\n\n public ngOnDestroy(): void {\n this.videoSub?.unsubscribe();\n this.videoSub = null;\n this.stateSub?.unsubscribe();\n this.stateSub = null;\n this.resumingSub?.unsubscribe();\n this.resumingSub = null;\n this.clearHoldTimer();\n }\n\n /** A resume that starts holds the last frame; the hold ends on its own terms, not when the resume does. */\n private onResuming(resuming: boolean): void {\n if (resuming && !this.resuming) {\n this.startHold();\n }\n this.resuming = resuming;\n }\n\n /** Holds the last frame for up to {@link AGENT_VIDEO_RESUME_HOLD_MS}, counted again from a new resume's start. */\n private startHold(): void {\n this.clearHoldTimer();\n this.HoldLastFrame = true;\n this.holdTimer = setTimeout(() => this.endHold(), AGENT_VIDEO_RESUME_HOLD_MS);\n this.cdr.markForCheck();\n }\n\n /** Stops holding the last frame: the orb shows if the video is still out of frames. */\n private endHold(): void {\n this.clearHoldTimer();\n if (this.HoldLastFrame) {\n this.HoldLastFrame = false;\n this.cdr.markForCheck();\n }\n }\n\n private clearHoldTimer(): void {\n if (this.holdTimer !== null) {\n clearTimeout(this.holdTimer);\n this.holdTimer = null;\n }\n }\n}\n\n/** What the tile's chip says for a state of the call, or `null` for none (the call has ended). */\nfunction statusLabelFor(state: RealtimeConnectionState): string | null {\n switch (state) {\n case 'speaking':\n return 'Speaking';\n case 'thinking':\n return 'Thinking';\n case 'listening':\n return 'Listening';\n case 'connecting':\n return 'Connecting';\n case 'error':\n return 'Connection error';\n default:\n return null;\n }\n}\n\n/** The agent as a media tile shows it: its name, and its video as the avatar when there is one. */\nfunction agentParticipant(name: string, video: MediaVideoSource | null): MediaParticipant {\n return { Identity: 'agent', DisplayName: name, Role: 'agent', IsSpeaking: false, Video: video ? { avatar: video } : {} };\n}\n","<div class=\"avatar\" [class.avatar--speaking]=\"OrbState === 'speaking'\">\n <mj-media-tile\n class=\"avatar__tile\"\n [Participant]=\"Agent\"\n [ShowMeter]=\"false\"\n [ShowConnectionQuality]=\"false\"\n [ShowActiveSpeakerRing]=\"false\"\n [StallAfterMs]=\"StallAfterMs\"\n [HoldLastFrame]=\"HoldLastFrame\"\n [Status]=\"StatusLabel\"\n (FramesFlowingChange)=\"OnFramesFlowingChange($event)\">\n <mj-realtime-agent-orb mjMediaTilePlaceholder class=\"avatar__orb\" [State]=\"OrbState\"></mj-realtime-agent-orb>\n </mj-media-tile>\n</div>\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { EventEmitter } from '@angular/core';
|
|
2
|
+
import type { MediaDevice, MediaDeviceSelection, MediaVideoSource } from '@memberjunction/ai-realtime-client/media';
|
|
3
|
+
import type { RealtimeCaptureState } from '@memberjunction/realtime-runtime';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* `mj-realtime-camera-check-card`: the camera check over the call. The first time the user turns the camera on in a call,
|
|
7
|
+
* the camera opens for them alone ({@link RealtimeCaptureState.Checking}) and this card shows it, mirrored, with the
|
|
8
|
+
* cameras to choose from. It checks the camera only: it gives `mj-camera-check` no microphones, no level and no buttons. "Turn on camera" lets the agent see it ({@link Confirmed}); "Not now", the close button,
|
|
9
|
+
* Escape and a click outside turn it off ({@link Declined}).
|
|
10
|
+
*
|
|
11
|
+
* Presentational: the overlay gives it the camera's state and a way to {@link Switch} cameras, and calls the session for
|
|
12
|
+
* each answer.
|
|
13
|
+
*/
|
|
14
|
+
export declare class RealtimeCameraCheckCardComponent {
|
|
15
|
+
private readonly cdr;
|
|
16
|
+
private camera;
|
|
17
|
+
private source;
|
|
18
|
+
/** The camera being switched to, while the switch runs. */
|
|
19
|
+
private switchingTo;
|
|
20
|
+
/** Who the user is about to show the camera to. */
|
|
21
|
+
AgentName: string;
|
|
22
|
+
/** Moves the camera to another device and resolves once it has, or has gone back to the one in use. */
|
|
23
|
+
Switch: ((deviceId: string) => Promise<unknown>) | null;
|
|
24
|
+
/** The camera being checked: its stream, the camera in use and the cameras to choose from. */
|
|
25
|
+
set Camera(value: RealtimeCaptureState | null);
|
|
26
|
+
get Camera(): RealtimeCaptureState | null;
|
|
27
|
+
/** The user turned the camera on for the agent. */
|
|
28
|
+
Confirmed: EventEmitter<void>;
|
|
29
|
+
/** The user said not now. */
|
|
30
|
+
Declined: EventEmitter<void>;
|
|
31
|
+
/** The preview: the camera's stream, the same object while the stream is the same. */
|
|
32
|
+
get Source(): MediaVideoSource | null;
|
|
33
|
+
/** The cameras to choose from. */
|
|
34
|
+
get Devices(): readonly MediaDevice[];
|
|
35
|
+
/** The picker's camera: the one being switched to, else the one in use. */
|
|
36
|
+
get SelectedCameraID(): string | null;
|
|
37
|
+
/**
|
|
38
|
+
* A camera picked in the check. The picker shows it while the camera switches, then the camera in use: the new one, or
|
|
39
|
+
* the old one when the new one could not open. A pick of the camera in use changes nothing.
|
|
40
|
+
*/
|
|
41
|
+
OnDeviceSelected(selection: MediaDeviceSelection): Promise<void>;
|
|
42
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeCameraCheckCardComponent, never>;
|
|
43
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeCameraCheckCardComponent, "mj-realtime-camera-check-card", never, { "AgentName": { "alias": "AgentName"; "required": false; }; "Switch": { "alias": "Switch"; "required": false; }; "Camera": { "alias": "Camera"; "required": false; }; }, { "Confirmed": "Confirmed"; "Declined": "Declined"; }, never, never, true, never>;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=realtime-camera-check-card.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-camera-check-card.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/capture/realtime-camera-check-card.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyD,YAAY,EAAyB,MAAM,eAAe,CAAC;AAG3H,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACpH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;;AAE7E;;;;;;;;GAQG;AACH,qBAyBa,gCAAgC;IAC3C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IACjD,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,MAAM,CAAiC;IAC/C,2DAA2D;IAC3D,OAAO,CAAC,WAAW,CAAuB;IAE1C,mDAAmD;IACnC,SAAS,SAAmB;IAE5C,uGAAuG;IACvF,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,CAAQ;IAE/E,8FAA8F;IAC9F,IACW,MAAM,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,EAGnD;IACD,IAAW,MAAM,IAAI,oBAAoB,GAAG,IAAI,CAE/C;IAED,mDAAmD;IAClC,SAAS,qBAA4B;IACtD,6BAA6B;IACZ,QAAQ,qBAA4B;IAErD,sFAAsF;IACtF,IAAW,MAAM,IAAI,gBAAgB,GAAG,IAAI,CAE3C;IAED,kCAAkC;IAClC,IAAW,OAAO,IAAI,SAAS,WAAW,EAAE,CAE3C;IAED,2EAA2E;IAC3E,IAAW,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAE3C;IAED;;;OAGG;IACU,gBAAgB,CAAC,SAAS,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;yCA/ClE,gCAAgC;2CAAhC,gCAAgC;CA4D5C"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, inject } from '@angular/core';
|
|
2
|
+
import { MJDialogComponent } from '@memberjunction/ng-ui-components';
|
|
3
|
+
import { CameraCheckComponent } from '@memberjunction/ng-realtime-media';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* `mj-realtime-camera-check-card`: the camera check over the call. The first time the user turns the camera on in a call,
|
|
7
|
+
* the camera opens for them alone ({@link RealtimeCaptureState.Checking}) and this card shows it, mirrored, with the
|
|
8
|
+
* cameras to choose from. It checks the camera only: it gives `mj-camera-check` no microphones, no level and no buttons. "Turn on camera" lets the agent see it ({@link Confirmed}); "Not now", the close button,
|
|
9
|
+
* Escape and a click outside turn it off ({@link Declined}).
|
|
10
|
+
*
|
|
11
|
+
* Presentational: the overlay gives it the camera's state and a way to {@link Switch} cameras, and calls the session for
|
|
12
|
+
* each answer.
|
|
13
|
+
*/
|
|
14
|
+
export class RealtimeCameraCheckCardComponent {
|
|
15
|
+
cdr = inject(ChangeDetectorRef);
|
|
16
|
+
camera = null;
|
|
17
|
+
source = null;
|
|
18
|
+
/** The camera being switched to, while the switch runs. */
|
|
19
|
+
switchingTo = null;
|
|
20
|
+
/** Who the user is about to show the camera to. */
|
|
21
|
+
AgentName = 'The assistant';
|
|
22
|
+
/** Moves the camera to another device and resolves once it has, or has gone back to the one in use. */
|
|
23
|
+
Switch = null;
|
|
24
|
+
/** The camera being checked: its stream, the camera in use and the cameras to choose from. */
|
|
25
|
+
set Camera(value) {
|
|
26
|
+
this.camera = value;
|
|
27
|
+
this.source = sourceFor(value?.Stream ?? null, this.source);
|
|
28
|
+
}
|
|
29
|
+
get Camera() {
|
|
30
|
+
return this.camera;
|
|
31
|
+
}
|
|
32
|
+
/** The user turned the camera on for the agent. */
|
|
33
|
+
Confirmed = new EventEmitter();
|
|
34
|
+
/** The user said not now. */
|
|
35
|
+
Declined = new EventEmitter();
|
|
36
|
+
/** The preview: the camera's stream, the same object while the stream is the same. */
|
|
37
|
+
get Source() {
|
|
38
|
+
return this.source;
|
|
39
|
+
}
|
|
40
|
+
/** The cameras to choose from. */
|
|
41
|
+
get Devices() {
|
|
42
|
+
return this.camera?.Devices ?? [];
|
|
43
|
+
}
|
|
44
|
+
/** The picker's camera: the one being switched to, else the one in use. */
|
|
45
|
+
get SelectedCameraID() {
|
|
46
|
+
return this.switchingTo ?? this.camera?.DeviceID ?? null;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A camera picked in the check. The picker shows it while the camera switches, then the camera in use: the new one, or
|
|
50
|
+
* the old one when the new one could not open. A pick of the camera in use changes nothing.
|
|
51
|
+
*/
|
|
52
|
+
async OnDeviceSelected(selection) {
|
|
53
|
+
if (selection.Kind !== 'camera' || selection.DeviceID === this.camera?.DeviceID || !this.Switch) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
this.switchingTo = selection.DeviceID;
|
|
57
|
+
this.cdr.markForCheck();
|
|
58
|
+
try {
|
|
59
|
+
await this.Switch(selection.DeviceID);
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
this.switchingTo = null;
|
|
63
|
+
this.cdr.markForCheck();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
static ɵfac = function RealtimeCameraCheckCardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RealtimeCameraCheckCardComponent)(); };
|
|
67
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeCameraCheckCardComponent, selectors: [["mj-realtime-camera-check-card"]], inputs: { AgentName: "AgentName", Switch: "Switch", Camera: "Camera" }, outputs: { Confirmed: "Confirmed", Declined: "Declined" }, decls: 4, vars: 7, consts: [["Title", "Check your camera", "Size", "auto", 3, "Close", "Visible"], [1, "camera-check__note"], ["Heading", "", "ConfirmLabel", "Turn on camera", "CancelLabel", "Not now", 3, "Confirmed", "Cancelled", "DeviceSelected", "ShowControls", "CameraOn", "CameraSource", "Devices", "SelectedCameraID"]], template: function RealtimeCameraCheckCardComponent_Template(rf, ctx) { if (rf & 1) {
|
|
68
|
+
i0.ɵɵelementStart(0, "mj-dialog", 0);
|
|
69
|
+
i0.ɵɵlistener("Close", function RealtimeCameraCheckCardComponent_Template_mj_dialog_Close_0_listener() { return ctx.Declined.emit(); });
|
|
70
|
+
i0.ɵɵelementStart(1, "p", 1);
|
|
71
|
+
i0.ɵɵtext(2);
|
|
72
|
+
i0.ɵɵelementEnd();
|
|
73
|
+
i0.ɵɵelementStart(3, "mj-camera-check", 2);
|
|
74
|
+
i0.ɵɵlistener("Confirmed", function RealtimeCameraCheckCardComponent_Template_mj_camera_check_Confirmed_3_listener() { return ctx.Confirmed.emit(); })("Cancelled", function RealtimeCameraCheckCardComponent_Template_mj_camera_check_Cancelled_3_listener() { return ctx.Declined.emit(); })("DeviceSelected", function RealtimeCameraCheckCardComponent_Template_mj_camera_check_DeviceSelected_3_listener($event) { return ctx.OnDeviceSelected($event); });
|
|
75
|
+
i0.ɵɵelementEnd()();
|
|
76
|
+
} if (rf & 2) {
|
|
77
|
+
i0.ɵɵproperty("Visible", true);
|
|
78
|
+
i0.ɵɵadvance(2);
|
|
79
|
+
i0.ɵɵtextInterpolate1("", ctx.AgentName, " sees your camera once you turn it on.");
|
|
80
|
+
i0.ɵɵadvance();
|
|
81
|
+
i0.ɵɵproperty("ShowControls", false)("CameraOn", true)("CameraSource", ctx.Source)("Devices", ctx.Devices)("SelectedCameraID", ctx.SelectedCameraID);
|
|
82
|
+
} }, dependencies: [MJDialogComponent, CameraCheckComponent], styles: ["\n.camera-check__note[_ngcontent-%COMP%] {\n margin: 0 20px;\n font-size: 0.9rem;\n color: var(--mj-text-secondary);\n}"], changeDetection: 0 });
|
|
83
|
+
}
|
|
84
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeCameraCheckCardComponent, [{
|
|
85
|
+
type: Component,
|
|
86
|
+
args: [{ standalone: true, selector: 'mj-realtime-camera-check-card', imports: [MJDialogComponent, CameraCheckComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
87
|
+
<mj-dialog [Visible]="true" Title="Check your camera" Size="auto" (Close)="Declined.emit()">
|
|
88
|
+
<p class="camera-check__note">{{ AgentName }} sees your camera once you turn it on.</p>
|
|
89
|
+
<mj-camera-check
|
|
90
|
+
Heading=""
|
|
91
|
+
ConfirmLabel="Turn on camera"
|
|
92
|
+
CancelLabel="Not now"
|
|
93
|
+
[ShowControls]="false"
|
|
94
|
+
[CameraOn]="true"
|
|
95
|
+
[CameraSource]="Source"
|
|
96
|
+
[Devices]="Devices"
|
|
97
|
+
[SelectedCameraID]="SelectedCameraID"
|
|
98
|
+
(Confirmed)="Confirmed.emit()"
|
|
99
|
+
(Cancelled)="Declined.emit()"
|
|
100
|
+
(DeviceSelected)="OnDeviceSelected($event)"
|
|
101
|
+
></mj-camera-check>
|
|
102
|
+
</mj-dialog>
|
|
103
|
+
`, styles: ["/* Lines up with the check's own padding below it. */\n.camera-check__note {\n margin: 0 20px;\n font-size: 0.9rem;\n color: var(--mj-text-secondary);\n}\n"] }]
|
|
104
|
+
}], null, { AgentName: [{
|
|
105
|
+
type: Input
|
|
106
|
+
}], Switch: [{
|
|
107
|
+
type: Input
|
|
108
|
+
}], Camera: [{
|
|
109
|
+
type: Input
|
|
110
|
+
}], Confirmed: [{
|
|
111
|
+
type: Output
|
|
112
|
+
}], Declined: [{
|
|
113
|
+
type: Output
|
|
114
|
+
}] }); })();
|
|
115
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RealtimeCameraCheckCardComponent, { className: "RealtimeCameraCheckCardComponent", filePath: "src/lib/components/realtime/capture/realtime-camera-check-card.component.ts", lineNumber: 41 }); })();
|
|
116
|
+
/** The preview for a stream: the previous one while the stream is the same, so the check keeps its video bound. */
|
|
117
|
+
function sourceFor(stream, previous) {
|
|
118
|
+
if (!stream) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
return previous?.Kind === 'stream' && previous.Stream === stream ? previous : { Kind: 'stream', Stream: stream };
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=realtime-camera-check-card.component.js.map
|