@vivix-ai/ivi-frontend-sdk 0.3.6 → 0.3.7
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 +10 -3
- package/dist/index.cjs +165 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +165 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -628,6 +628,12 @@ interface IVIVolumeControlProps {
|
|
|
628
628
|
|
|
629
629
|
type IviSubtitleRole = IviRuntimeConversationItem["role"];
|
|
630
630
|
type IviSubtitleSource = "conversation" | "response_audio_transcript";
|
|
631
|
+
type IviSubtitleCompletedReason = "conversation_done" | "response_done";
|
|
632
|
+
type IviCompletedSubtitleDecision = "keep" | "remove" | {
|
|
633
|
+
removeAfterMs: number;
|
|
634
|
+
};
|
|
635
|
+
type IviCompletedSubtitleDecisionResult = IviCompletedSubtitleDecision | void | Promise<IviCompletedSubtitleDecision | void>;
|
|
636
|
+
declare const DEFAULT_HIDE_COMPLETED_SUBTITLE_AFTER_MS = 3000;
|
|
631
637
|
interface IviSubtitleItem {
|
|
632
638
|
id: string;
|
|
633
639
|
role: IviSubtitleRole;
|
|
@@ -649,6 +655,15 @@ interface IviSubtitleItem {
|
|
|
649
655
|
/** 最近一次字幕内容或状态更新的时间戳。 */
|
|
650
656
|
updatedAt: number;
|
|
651
657
|
}
|
|
658
|
+
interface IviSubtitleCompletedContext {
|
|
659
|
+
/** 当前字幕队列快照。 */
|
|
660
|
+
entries: readonly IviSubtitleItem[];
|
|
661
|
+
/** 本次完成态来自 conversation 完成还是 response 完成。 */
|
|
662
|
+
reason: IviSubtitleCompletedReason;
|
|
663
|
+
/** 当字幕被移除、会话结束、配置变化或组件卸载时触发。 */
|
|
664
|
+
signal: AbortSignal;
|
|
665
|
+
}
|
|
666
|
+
type IviSubtitleCompletedHandler = (item: IviSubtitleItem, context: IviSubtitleCompletedContext) => IviCompletedSubtitleDecisionResult;
|
|
652
667
|
interface IviUseSubtitlesOptions {
|
|
653
668
|
/** 要收集的发言人角色,默认 ["user"]。传单个字符串或数组均可。 */
|
|
654
669
|
roles?: IviSubtitleRole | IviSubtitleRole[];
|
|
@@ -660,6 +675,16 @@ interface IviUseSubtitlesOptions {
|
|
|
660
675
|
* 只有 response.done 才会把这一轮 model 字幕标记为 done。
|
|
661
676
|
*/
|
|
662
677
|
useModelStreamingTranscript?: boolean;
|
|
678
|
+
/**
|
|
679
|
+
* 字幕进入完成态后多久自动移除,默认 3000ms;传 false 可恢复为一直保留直到被 maxItems 裁剪。
|
|
680
|
+
* 自定义 onSubtitleCompleted 时,此配置仅作为未提供自定义策略时的默认策略。
|
|
681
|
+
*/
|
|
682
|
+
hideCompletedAfterMs?: number | false;
|
|
683
|
+
/**
|
|
684
|
+
* 字幕进入完成态时调用一次。返回 "remove" 立即删除,返回 { removeAfterMs } 延迟删除,
|
|
685
|
+
* 返回 "keep" 或 undefined 则保留。异步策略可通过 context.signal 响应取消。
|
|
686
|
+
*/
|
|
687
|
+
onSubtitleCompleted?: IviSubtitleCompletedHandler;
|
|
663
688
|
}
|
|
664
689
|
/**
|
|
665
690
|
* 监听 runtime 中的 conversation/response 事件,并维护当前应展示的字幕队列。
|
|
@@ -689,6 +714,10 @@ interface IVISubtitleOverlayProps {
|
|
|
689
714
|
* 当 roles 包含 "model" 时,是否使用 response.output_audio_transcript.* 事件作为 model 字幕来源。
|
|
690
715
|
*/
|
|
691
716
|
useModelStreamingTranscript?: boolean;
|
|
717
|
+
/** 字幕进入完成态后多久自动移除,默认 3000ms;传 false 可关闭自动移除。 */
|
|
718
|
+
hideCompletedAfterMs?: IviUseSubtitlesOptions["hideCompletedAfterMs"];
|
|
719
|
+
/** 字幕进入完成态时的自定义保留/删除策略,优先于 hideCompletedAfterMs。 */
|
|
720
|
+
onSubtitleCompleted?: IviUseSubtitlesOptions["onSubtitleCompleted"];
|
|
692
721
|
/** 样式配置 */
|
|
693
722
|
subtitleStyle?: IVISubtitleOverlayStyle;
|
|
694
723
|
/** 自定义类名 */
|
|
@@ -773,4 +802,4 @@ declare function useManagedIviRuntime(config: IviManagedRuntimeConfig): IviRunti
|
|
|
773
802
|
|
|
774
803
|
declare function useIviStageView(): IviStageViewContextValue;
|
|
775
804
|
|
|
776
|
-
export { EMPTY_RUNTIME_STATE, IVILivekitPlayer, type IVILivekitPlayerProps, IVIStageView, type IVIStageViewProps, IVISubtitleOverlay, type IVISubtitleOverlayProps, type IVISubtitleOverlayStyle, IVITrackSlot, type IVITrackSlotProps, IVITrtcPlayer, type IVITrtcPlayerProps, type IviFrontendClientConfig, IviFrontendSdk, type IviManagedRuntimeConfig, type IviManagedRuntimeLogCallback, type IviManagedRuntimeLogEntry, type IviManagedRuntimeLogLevel, type IviManagedRuntimeLogSource, type IviRuntimeConversationItem, type IviRuntimeConversationLifecycle, type IviRuntimeConversationStatus, IviRuntimeCoordinator, type IviRuntimeCoordinatorConfig, IviRuntimeDispatcher, type IviRuntimeDispatcherConfig, type IviRuntimeEventListener, type IviRuntimeLogCallback, type IviRuntimeLogEntry, type IviRuntimeLogLevel, type IviRuntimeSource, type IviRuntimeSourcePreloadState, type IviRuntimeState, type IviRuntimeStatus, type IviRuntimeStream, type IviRuntimeTrtcAIDenoiserMode, type IviRuntimeTrtcAIDenoiserOptions, type IviRuntimeTrtcEvent, type IviRuntimeTrtcEventListener, type IviRuntimeTrtcEventType, type IviRuntimeUserTextToResponseCallbacks, type IviRuntimeUserTextToResponseOptions, type IviRuntimeUserTextToResponseResult, type IviSourcePlaybackLivekit, type IviSourcePlaybackLivekitDescriptor, type IviStageSlotBinding, type IviStageViewContextValue, type IviSubtitleItem, type IviSubtitleRole, type IviSubtitleSource, type IviUseSubtitlesOptions, LivekitSourceManager, TrtcSourceManager, isLivekitSourcePlayback, isReadyLivekitRuntimeSource, isSameLivekitConfig, useIviStageView, useIviSubtitles, useManagedIviRuntime, useRuntimeState };
|
|
805
|
+
export { DEFAULT_HIDE_COMPLETED_SUBTITLE_AFTER_MS, EMPTY_RUNTIME_STATE, IVILivekitPlayer, type IVILivekitPlayerProps, IVIStageView, type IVIStageViewProps, IVISubtitleOverlay, type IVISubtitleOverlayProps, type IVISubtitleOverlayStyle, IVITrackSlot, type IVITrackSlotProps, IVITrtcPlayer, type IVITrtcPlayerProps, type IviCompletedSubtitleDecision, type IviCompletedSubtitleDecisionResult, type IviFrontendClientConfig, IviFrontendSdk, type IviManagedRuntimeConfig, type IviManagedRuntimeLogCallback, type IviManagedRuntimeLogEntry, type IviManagedRuntimeLogLevel, type IviManagedRuntimeLogSource, type IviRuntimeConversationItem, type IviRuntimeConversationLifecycle, type IviRuntimeConversationStatus, IviRuntimeCoordinator, type IviRuntimeCoordinatorConfig, IviRuntimeDispatcher, type IviRuntimeDispatcherConfig, type IviRuntimeEventListener, type IviRuntimeLogCallback, type IviRuntimeLogEntry, type IviRuntimeLogLevel, type IviRuntimeSource, type IviRuntimeSourcePreloadState, type IviRuntimeState, type IviRuntimeStatus, type IviRuntimeStream, type IviRuntimeTrtcAIDenoiserMode, type IviRuntimeTrtcAIDenoiserOptions, type IviRuntimeTrtcEvent, type IviRuntimeTrtcEventListener, type IviRuntimeTrtcEventType, type IviRuntimeUserTextToResponseCallbacks, type IviRuntimeUserTextToResponseOptions, type IviRuntimeUserTextToResponseResult, type IviSourcePlaybackLivekit, type IviSourcePlaybackLivekitDescriptor, type IviStageSlotBinding, type IviStageViewContextValue, type IviSubtitleCompletedContext, type IviSubtitleCompletedHandler, type IviSubtitleCompletedReason, type IviSubtitleItem, type IviSubtitleRole, type IviSubtitleSource, type IviUseSubtitlesOptions, LivekitSourceManager, TrtcSourceManager, isLivekitSourcePlayback, isReadyLivekitRuntimeSource, isSameLivekitConfig, useIviStageView, useIviSubtitles, useManagedIviRuntime, useRuntimeState };
|
package/dist/index.d.ts
CHANGED
|
@@ -628,6 +628,12 @@ interface IVIVolumeControlProps {
|
|
|
628
628
|
|
|
629
629
|
type IviSubtitleRole = IviRuntimeConversationItem["role"];
|
|
630
630
|
type IviSubtitleSource = "conversation" | "response_audio_transcript";
|
|
631
|
+
type IviSubtitleCompletedReason = "conversation_done" | "response_done";
|
|
632
|
+
type IviCompletedSubtitleDecision = "keep" | "remove" | {
|
|
633
|
+
removeAfterMs: number;
|
|
634
|
+
};
|
|
635
|
+
type IviCompletedSubtitleDecisionResult = IviCompletedSubtitleDecision | void | Promise<IviCompletedSubtitleDecision | void>;
|
|
636
|
+
declare const DEFAULT_HIDE_COMPLETED_SUBTITLE_AFTER_MS = 3000;
|
|
631
637
|
interface IviSubtitleItem {
|
|
632
638
|
id: string;
|
|
633
639
|
role: IviSubtitleRole;
|
|
@@ -649,6 +655,15 @@ interface IviSubtitleItem {
|
|
|
649
655
|
/** 最近一次字幕内容或状态更新的时间戳。 */
|
|
650
656
|
updatedAt: number;
|
|
651
657
|
}
|
|
658
|
+
interface IviSubtitleCompletedContext {
|
|
659
|
+
/** 当前字幕队列快照。 */
|
|
660
|
+
entries: readonly IviSubtitleItem[];
|
|
661
|
+
/** 本次完成态来自 conversation 完成还是 response 完成。 */
|
|
662
|
+
reason: IviSubtitleCompletedReason;
|
|
663
|
+
/** 当字幕被移除、会话结束、配置变化或组件卸载时触发。 */
|
|
664
|
+
signal: AbortSignal;
|
|
665
|
+
}
|
|
666
|
+
type IviSubtitleCompletedHandler = (item: IviSubtitleItem, context: IviSubtitleCompletedContext) => IviCompletedSubtitleDecisionResult;
|
|
652
667
|
interface IviUseSubtitlesOptions {
|
|
653
668
|
/** 要收集的发言人角色,默认 ["user"]。传单个字符串或数组均可。 */
|
|
654
669
|
roles?: IviSubtitleRole | IviSubtitleRole[];
|
|
@@ -660,6 +675,16 @@ interface IviUseSubtitlesOptions {
|
|
|
660
675
|
* 只有 response.done 才会把这一轮 model 字幕标记为 done。
|
|
661
676
|
*/
|
|
662
677
|
useModelStreamingTranscript?: boolean;
|
|
678
|
+
/**
|
|
679
|
+
* 字幕进入完成态后多久自动移除,默认 3000ms;传 false 可恢复为一直保留直到被 maxItems 裁剪。
|
|
680
|
+
* 自定义 onSubtitleCompleted 时,此配置仅作为未提供自定义策略时的默认策略。
|
|
681
|
+
*/
|
|
682
|
+
hideCompletedAfterMs?: number | false;
|
|
683
|
+
/**
|
|
684
|
+
* 字幕进入完成态时调用一次。返回 "remove" 立即删除,返回 { removeAfterMs } 延迟删除,
|
|
685
|
+
* 返回 "keep" 或 undefined 则保留。异步策略可通过 context.signal 响应取消。
|
|
686
|
+
*/
|
|
687
|
+
onSubtitleCompleted?: IviSubtitleCompletedHandler;
|
|
663
688
|
}
|
|
664
689
|
/**
|
|
665
690
|
* 监听 runtime 中的 conversation/response 事件,并维护当前应展示的字幕队列。
|
|
@@ -689,6 +714,10 @@ interface IVISubtitleOverlayProps {
|
|
|
689
714
|
* 当 roles 包含 "model" 时,是否使用 response.output_audio_transcript.* 事件作为 model 字幕来源。
|
|
690
715
|
*/
|
|
691
716
|
useModelStreamingTranscript?: boolean;
|
|
717
|
+
/** 字幕进入完成态后多久自动移除,默认 3000ms;传 false 可关闭自动移除。 */
|
|
718
|
+
hideCompletedAfterMs?: IviUseSubtitlesOptions["hideCompletedAfterMs"];
|
|
719
|
+
/** 字幕进入完成态时的自定义保留/删除策略,优先于 hideCompletedAfterMs。 */
|
|
720
|
+
onSubtitleCompleted?: IviUseSubtitlesOptions["onSubtitleCompleted"];
|
|
692
721
|
/** 样式配置 */
|
|
693
722
|
subtitleStyle?: IVISubtitleOverlayStyle;
|
|
694
723
|
/** 自定义类名 */
|
|
@@ -773,4 +802,4 @@ declare function useManagedIviRuntime(config: IviManagedRuntimeConfig): IviRunti
|
|
|
773
802
|
|
|
774
803
|
declare function useIviStageView(): IviStageViewContextValue;
|
|
775
804
|
|
|
776
|
-
export { EMPTY_RUNTIME_STATE, IVILivekitPlayer, type IVILivekitPlayerProps, IVIStageView, type IVIStageViewProps, IVISubtitleOverlay, type IVISubtitleOverlayProps, type IVISubtitleOverlayStyle, IVITrackSlot, type IVITrackSlotProps, IVITrtcPlayer, type IVITrtcPlayerProps, type IviFrontendClientConfig, IviFrontendSdk, type IviManagedRuntimeConfig, type IviManagedRuntimeLogCallback, type IviManagedRuntimeLogEntry, type IviManagedRuntimeLogLevel, type IviManagedRuntimeLogSource, type IviRuntimeConversationItem, type IviRuntimeConversationLifecycle, type IviRuntimeConversationStatus, IviRuntimeCoordinator, type IviRuntimeCoordinatorConfig, IviRuntimeDispatcher, type IviRuntimeDispatcherConfig, type IviRuntimeEventListener, type IviRuntimeLogCallback, type IviRuntimeLogEntry, type IviRuntimeLogLevel, type IviRuntimeSource, type IviRuntimeSourcePreloadState, type IviRuntimeState, type IviRuntimeStatus, type IviRuntimeStream, type IviRuntimeTrtcAIDenoiserMode, type IviRuntimeTrtcAIDenoiserOptions, type IviRuntimeTrtcEvent, type IviRuntimeTrtcEventListener, type IviRuntimeTrtcEventType, type IviRuntimeUserTextToResponseCallbacks, type IviRuntimeUserTextToResponseOptions, type IviRuntimeUserTextToResponseResult, type IviSourcePlaybackLivekit, type IviSourcePlaybackLivekitDescriptor, type IviStageSlotBinding, type IviStageViewContextValue, type IviSubtitleItem, type IviSubtitleRole, type IviSubtitleSource, type IviUseSubtitlesOptions, LivekitSourceManager, TrtcSourceManager, isLivekitSourcePlayback, isReadyLivekitRuntimeSource, isSameLivekitConfig, useIviStageView, useIviSubtitles, useManagedIviRuntime, useRuntimeState };
|
|
805
|
+
export { DEFAULT_HIDE_COMPLETED_SUBTITLE_AFTER_MS, EMPTY_RUNTIME_STATE, IVILivekitPlayer, type IVILivekitPlayerProps, IVIStageView, type IVIStageViewProps, IVISubtitleOverlay, type IVISubtitleOverlayProps, type IVISubtitleOverlayStyle, IVITrackSlot, type IVITrackSlotProps, IVITrtcPlayer, type IVITrtcPlayerProps, type IviCompletedSubtitleDecision, type IviCompletedSubtitleDecisionResult, type IviFrontendClientConfig, IviFrontendSdk, type IviManagedRuntimeConfig, type IviManagedRuntimeLogCallback, type IviManagedRuntimeLogEntry, type IviManagedRuntimeLogLevel, type IviManagedRuntimeLogSource, type IviRuntimeConversationItem, type IviRuntimeConversationLifecycle, type IviRuntimeConversationStatus, IviRuntimeCoordinator, type IviRuntimeCoordinatorConfig, IviRuntimeDispatcher, type IviRuntimeDispatcherConfig, type IviRuntimeEventListener, type IviRuntimeLogCallback, type IviRuntimeLogEntry, type IviRuntimeLogLevel, type IviRuntimeSource, type IviRuntimeSourcePreloadState, type IviRuntimeState, type IviRuntimeStatus, type IviRuntimeStream, type IviRuntimeTrtcAIDenoiserMode, type IviRuntimeTrtcAIDenoiserOptions, type IviRuntimeTrtcEvent, type IviRuntimeTrtcEventListener, type IviRuntimeTrtcEventType, type IviRuntimeUserTextToResponseCallbacks, type IviRuntimeUserTextToResponseOptions, type IviRuntimeUserTextToResponseResult, type IviSourcePlaybackLivekit, type IviSourcePlaybackLivekitDescriptor, type IviStageSlotBinding, type IviStageViewContextValue, type IviSubtitleCompletedContext, type IviSubtitleCompletedHandler, type IviSubtitleCompletedReason, type IviSubtitleItem, type IviSubtitleRole, type IviSubtitleSource, type IviUseSubtitlesOptions, LivekitSourceManager, TrtcSourceManager, isLivekitSourcePlayback, isReadyLivekitRuntimeSource, isSameLivekitConfig, useIviStageView, useIviSubtitles, useManagedIviRuntime, useRuntimeState };
|
package/dist/index.js
CHANGED
|
@@ -3078,9 +3078,12 @@ function useApplyVolumeToSlot(containerRef, volume, enabled, activeSourceId) {
|
|
|
3078
3078
|
return () => observer.disconnect();
|
|
3079
3079
|
}, [containerRef, volume, enabled, activeSourceId]);
|
|
3080
3080
|
}
|
|
3081
|
+
var DEFAULT_HIDE_COMPLETED_SUBTITLE_AFTER_MS = 3e3;
|
|
3081
3082
|
function useIviSubtitles(runtime, options = {}) {
|
|
3082
3083
|
const roles = options.roles ?? "user";
|
|
3083
3084
|
const maxItems = normalizeMaxItems(options.maxItems);
|
|
3085
|
+
const hideCompletedAfterMs = normalizeHideCompletedAfterMs(options.hideCompletedAfterMs);
|
|
3086
|
+
const onSubtitleCompleted = options.onSubtitleCompleted;
|
|
3084
3087
|
const roleKey = Array.isArray(roles) ? roles.join("\0") : roles;
|
|
3085
3088
|
const roleSet = useMemo(
|
|
3086
3089
|
() => new Set(roleKey.split("\0")),
|
|
@@ -3090,9 +3093,14 @@ function useIviSubtitles(runtime, options = {}) {
|
|
|
3090
3093
|
const [subtitles, setSubtitles] = useState([]);
|
|
3091
3094
|
const seenIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
3092
3095
|
const initializedRef = useRef(false);
|
|
3096
|
+
const completedSubtitleIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
3097
|
+
const completionControllersRef = useRef(/* @__PURE__ */ new Map());
|
|
3098
|
+
const completionPolicyRef = useRef(null);
|
|
3093
3099
|
useEffect(() => {
|
|
3094
3100
|
seenIdsRef.current = /* @__PURE__ */ new Set();
|
|
3095
3101
|
initializedRef.current = false;
|
|
3102
|
+
completedSubtitleIdsRef.current = /* @__PURE__ */ new Set();
|
|
3103
|
+
abortCompletedSubtitleTasks(completionControllersRef.current);
|
|
3096
3104
|
setSubtitles([]);
|
|
3097
3105
|
if (!runtime) {
|
|
3098
3106
|
return;
|
|
@@ -3148,6 +3156,8 @@ function useIviSubtitles(runtime, options = {}) {
|
|
|
3148
3156
|
if (event.type === "session.ended") {
|
|
3149
3157
|
seenIdsRef.current = /* @__PURE__ */ new Set();
|
|
3150
3158
|
initializedRef.current = false;
|
|
3159
|
+
completedSubtitleIdsRef.current = /* @__PURE__ */ new Set();
|
|
3160
|
+
abortCompletedSubtitleTasks(completionControllersRef.current);
|
|
3151
3161
|
setSubtitles([]);
|
|
3152
3162
|
return;
|
|
3153
3163
|
}
|
|
@@ -3165,6 +3175,78 @@ function useIviSubtitles(runtime, options = {}) {
|
|
|
3165
3175
|
syncConversations(state.conversations);
|
|
3166
3176
|
});
|
|
3167
3177
|
}, [runtime, roleSet, maxItems, useModelStreamingTranscript]);
|
|
3178
|
+
useEffect(() => {
|
|
3179
|
+
return () => {
|
|
3180
|
+
completedSubtitleIdsRef.current = /* @__PURE__ */ new Set();
|
|
3181
|
+
abortCompletedSubtitleTasks(completionControllersRef.current);
|
|
3182
|
+
};
|
|
3183
|
+
}, []);
|
|
3184
|
+
useEffect(() => {
|
|
3185
|
+
const previousPolicy = completionPolicyRef.current;
|
|
3186
|
+
const policyChanged = Boolean(
|
|
3187
|
+
previousPolicy && (previousPolicy.hideCompletedAfterMs !== hideCompletedAfterMs || previousPolicy.onSubtitleCompleted !== onSubtitleCompleted)
|
|
3188
|
+
);
|
|
3189
|
+
completionPolicyRef.current = { hideCompletedAfterMs, onSubtitleCompleted };
|
|
3190
|
+
if (policyChanged) {
|
|
3191
|
+
completedSubtitleIdsRef.current = /* @__PURE__ */ new Set();
|
|
3192
|
+
abortCompletedSubtitleTasks(completionControllersRef.current);
|
|
3193
|
+
}
|
|
3194
|
+
const subtitleById = new Map(subtitles.map((item) => [item.id, item]));
|
|
3195
|
+
const completedIds = completedSubtitleIdsRef.current;
|
|
3196
|
+
const controllers = completionControllersRef.current;
|
|
3197
|
+
for (const [id, controller] of Array.from(controllers)) {
|
|
3198
|
+
const item = subtitleById.get(id);
|
|
3199
|
+
if (!item || !isCompletedSubtitle(item)) {
|
|
3200
|
+
controller.abort();
|
|
3201
|
+
controllers.delete(id);
|
|
3202
|
+
completedIds.delete(id);
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
for (const id of Array.from(completedIds)) {
|
|
3206
|
+
const item = subtitleById.get(id);
|
|
3207
|
+
if (!item || !isCompletedSubtitle(item)) {
|
|
3208
|
+
completedIds.delete(id);
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
for (const item of subtitles) {
|
|
3212
|
+
if (!isCompletedSubtitle(item) || completedIds.has(item.id)) {
|
|
3213
|
+
continue;
|
|
3214
|
+
}
|
|
3215
|
+
completedIds.add(item.id);
|
|
3216
|
+
const controller = new AbortController();
|
|
3217
|
+
controllers.set(item.id, controller);
|
|
3218
|
+
const context = {
|
|
3219
|
+
entries: subtitles,
|
|
3220
|
+
reason: getSubtitleCompletedReason(item),
|
|
3221
|
+
signal: controller.signal
|
|
3222
|
+
};
|
|
3223
|
+
let decisionResult;
|
|
3224
|
+
try {
|
|
3225
|
+
decisionResult = onSubtitleCompleted ? onSubtitleCompleted(item, context) : getDefaultCompletedSubtitleDecision(hideCompletedAfterMs);
|
|
3226
|
+
} catch {
|
|
3227
|
+
decisionResult = "keep";
|
|
3228
|
+
}
|
|
3229
|
+
void Promise.resolve(decisionResult).then((decision) => {
|
|
3230
|
+
applyCompletedSubtitleDecision(
|
|
3231
|
+
item.id,
|
|
3232
|
+
decision,
|
|
3233
|
+
controller,
|
|
3234
|
+
controllers,
|
|
3235
|
+
completedIds,
|
|
3236
|
+
(id) => setSubtitles((previous) => removeSubtitleById(previous, id))
|
|
3237
|
+
);
|
|
3238
|
+
}).catch(() => {
|
|
3239
|
+
applyCompletedSubtitleDecision(
|
|
3240
|
+
item.id,
|
|
3241
|
+
"keep",
|
|
3242
|
+
controller,
|
|
3243
|
+
controllers,
|
|
3244
|
+
completedIds,
|
|
3245
|
+
(id) => setSubtitles((previous) => removeSubtitleById(previous, id))
|
|
3246
|
+
);
|
|
3247
|
+
});
|
|
3248
|
+
}
|
|
3249
|
+
}, [subtitles, hideCompletedAfterMs, onSubtitleCompleted]);
|
|
3168
3250
|
return subtitles;
|
|
3169
3251
|
}
|
|
3170
3252
|
function normalizeMaxItems(maxItems) {
|
|
@@ -3176,6 +3258,35 @@ function normalizeMaxItems(maxItems) {
|
|
|
3176
3258
|
}
|
|
3177
3259
|
return Math.max(0, Math.floor(maxItems));
|
|
3178
3260
|
}
|
|
3261
|
+
function normalizeHideCompletedAfterMs(hideCompletedAfterMs) {
|
|
3262
|
+
if (hideCompletedAfterMs === false) {
|
|
3263
|
+
return false;
|
|
3264
|
+
}
|
|
3265
|
+
if (hideCompletedAfterMs === void 0 || !Number.isFinite(hideCompletedAfterMs)) {
|
|
3266
|
+
return DEFAULT_HIDE_COMPLETED_SUBTITLE_AFTER_MS;
|
|
3267
|
+
}
|
|
3268
|
+
return Math.max(0, Math.floor(hideCompletedAfterMs));
|
|
3269
|
+
}
|
|
3270
|
+
function getDefaultCompletedSubtitleDecision(hideCompletedAfterMs) {
|
|
3271
|
+
if (hideCompletedAfterMs === false) {
|
|
3272
|
+
return "keep";
|
|
3273
|
+
}
|
|
3274
|
+
return hideCompletedAfterMs === 0 ? "remove" : { removeAfterMs: hideCompletedAfterMs };
|
|
3275
|
+
}
|
|
3276
|
+
function normalizeCompletedSubtitleDecision(decision) {
|
|
3277
|
+
if (decision === "keep" || decision === "remove") {
|
|
3278
|
+
return decision;
|
|
3279
|
+
}
|
|
3280
|
+
if (decision && typeof decision === "object" && "removeAfterMs" in decision) {
|
|
3281
|
+
const removeAfterMs = Number(decision.removeAfterMs);
|
|
3282
|
+
if (!Number.isFinite(removeAfterMs)) {
|
|
3283
|
+
return "keep";
|
|
3284
|
+
}
|
|
3285
|
+
const normalized = Math.max(0, Math.floor(removeAfterMs));
|
|
3286
|
+
return normalized === 0 ? "remove" : { removeAfterMs: normalized };
|
|
3287
|
+
}
|
|
3288
|
+
return "keep";
|
|
3289
|
+
}
|
|
3179
3290
|
function shouldUseConversationRole(role, roleSet, useModelStreamingTranscript) {
|
|
3180
3291
|
if (!roleSet.has(role)) {
|
|
3181
3292
|
return false;
|
|
@@ -3189,6 +3300,54 @@ function trimSubtitleItems(items, maxItems) {
|
|
|
3189
3300
|
const sorted = [...items].sort((a, b) => a.timestamp - b.timestamp);
|
|
3190
3301
|
return sorted.length > maxItems ? sorted.slice(sorted.length - maxItems) : sorted;
|
|
3191
3302
|
}
|
|
3303
|
+
function isCompletedSubtitle(item) {
|
|
3304
|
+
return item.lifecycle === "done" || item.status === "completed" || item.status === "incomplete";
|
|
3305
|
+
}
|
|
3306
|
+
function getSubtitleCompletedReason(item) {
|
|
3307
|
+
return item.source === "response_audio_transcript" || item.role === "model" ? "response_done" : "conversation_done";
|
|
3308
|
+
}
|
|
3309
|
+
function abortCompletedSubtitleTasks(controllers) {
|
|
3310
|
+
for (const controller of controllers.values()) {
|
|
3311
|
+
controller.abort();
|
|
3312
|
+
}
|
|
3313
|
+
controllers.clear();
|
|
3314
|
+
}
|
|
3315
|
+
function applyCompletedSubtitleDecision(itemId, decision, controller, controllers, completedIds, removeSubtitle) {
|
|
3316
|
+
if (controller.signal.aborted) {
|
|
3317
|
+
return;
|
|
3318
|
+
}
|
|
3319
|
+
const normalizedDecision = normalizeCompletedSubtitleDecision(decision);
|
|
3320
|
+
if (normalizedDecision === "keep") {
|
|
3321
|
+
controllers.delete(itemId);
|
|
3322
|
+
return;
|
|
3323
|
+
}
|
|
3324
|
+
const remove = () => {
|
|
3325
|
+
if (controller.signal.aborted) {
|
|
3326
|
+
return;
|
|
3327
|
+
}
|
|
3328
|
+
controllers.delete(itemId);
|
|
3329
|
+
completedIds.delete(itemId);
|
|
3330
|
+
removeSubtitle(itemId);
|
|
3331
|
+
};
|
|
3332
|
+
if (normalizedDecision === "remove") {
|
|
3333
|
+
remove();
|
|
3334
|
+
return;
|
|
3335
|
+
}
|
|
3336
|
+
const timeout = setTimeout(remove, normalizedDecision.removeAfterMs);
|
|
3337
|
+
controller.signal.addEventListener(
|
|
3338
|
+
"abort",
|
|
3339
|
+
() => {
|
|
3340
|
+
clearTimeout(timeout);
|
|
3341
|
+
},
|
|
3342
|
+
{ once: true }
|
|
3343
|
+
);
|
|
3344
|
+
}
|
|
3345
|
+
function removeSubtitleById(items, itemId) {
|
|
3346
|
+
if (!items.some((item) => item.id === itemId)) {
|
|
3347
|
+
return items;
|
|
3348
|
+
}
|
|
3349
|
+
return items.filter((item) => item.id !== itemId);
|
|
3350
|
+
}
|
|
3192
3351
|
function getDisplayText(item) {
|
|
3193
3352
|
return item.text || item.transcript;
|
|
3194
3353
|
}
|
|
@@ -3314,6 +3473,8 @@ function IVISubtitleOverlay(props) {
|
|
|
3314
3473
|
maxItems,
|
|
3315
3474
|
maxVisible,
|
|
3316
3475
|
useModelStreamingTranscript,
|
|
3476
|
+
hideCompletedAfterMs,
|
|
3477
|
+
onSubtitleCompleted,
|
|
3317
3478
|
subtitleStyle,
|
|
3318
3479
|
className,
|
|
3319
3480
|
style
|
|
@@ -3321,7 +3482,9 @@ function IVISubtitleOverlay(props) {
|
|
|
3321
3482
|
const entries = useIviSubtitles(runtime, {
|
|
3322
3483
|
roles,
|
|
3323
3484
|
maxItems: maxItems ?? maxVisible,
|
|
3324
|
-
useModelStreamingTranscript
|
|
3485
|
+
useModelStreamingTranscript,
|
|
3486
|
+
hideCompletedAfterMs,
|
|
3487
|
+
onSubtitleCompleted
|
|
3325
3488
|
});
|
|
3326
3489
|
if (entries.length === 0) return null;
|
|
3327
3490
|
const fontFamily = subtitleStyle?.fontFamily ?? "system-ui, -apple-system, sans-serif";
|
|
@@ -4412,6 +4575,6 @@ function getClientLogTag(category) {
|
|
|
4412
4575
|
return "[IVI-CLIENT]";
|
|
4413
4576
|
}
|
|
4414
4577
|
|
|
4415
|
-
export { EMPTY_RUNTIME_STATE, IVILivekitPlayer, IVIStageView, IVISubtitleOverlay, IVITrackSlot, IVITrtcPlayer, IviFrontendSdk, IviRuntimeCoordinator, IviRuntimeDispatcher, LivekitSourceManager, TrtcSourceManager, isLivekitSourcePlayback, isReadyLivekitRuntimeSource, isSameLivekitConfig, useIviStageView, useIviSubtitles, useManagedIviRuntime, useRuntimeState };
|
|
4578
|
+
export { DEFAULT_HIDE_COMPLETED_SUBTITLE_AFTER_MS, EMPTY_RUNTIME_STATE, IVILivekitPlayer, IVIStageView, IVISubtitleOverlay, IVITrackSlot, IVITrtcPlayer, IviFrontendSdk, IviRuntimeCoordinator, IviRuntimeDispatcher, LivekitSourceManager, TrtcSourceManager, isLivekitSourcePlayback, isReadyLivekitRuntimeSource, isSameLivekitConfig, useIviStageView, useIviSubtitles, useManagedIviRuntime, useRuntimeState };
|
|
4416
4579
|
//# sourceMappingURL=index.js.map
|
|
4417
4580
|
//# sourceMappingURL=index.js.map
|