diff --git a/.github/workflows/pr-prod-e2e.yml b/.github/workflows/pr-prod-e2e.yml index 885c9848..39bb2635 100644 --- a/.github/workflows/pr-prod-e2e.yml +++ b/.github/workflows/pr-prod-e2e.yml @@ -58,6 +58,7 @@ jobs: env: E2E_USER_APIKEY: ${{ secrets.E2E_USER_APIKEY }} VITE_CLIENT_KEY: ${{ secrets.VITE_CLIENT_KEY }} + ASSERT_CHAT_RESTART: 'false' run: yarn test:prod - name: Upload test results diff --git a/package.json b/package.json index 67112b5f..a3803e6d 100644 --- a/package.json +++ b/package.json @@ -1,48 +1,48 @@ { - "name": "@d-id/client-sdk", - "private": false, - "version": "1.1.7", - "type": "module", - "description": "d-id client sdk", - "repository": { - "type": "git", - "url": "https://github.com/de-id/agents-sdk" - }, - "keywords": [ - "d-id", - "sdk", - "client-sdk" - ], - "license": "MIT", - "author": "d-id", - "files": [ - "dist/*" - ], - "main": "./dist/index.umd.cjs", - "module": "./dist/index.js", - "types": "./dist/src/index.d.ts", - "scripts": { - "dev": "vite", - "build": "node ./infra/build.js -m production", - "build:dev": "node ./infra/build.js -m development", - "dev:prod": "export NODE_ENV=production && vite --mode production", - "deploy:prod": "node ./infra/deploy.js --version beta", - "preview": "vite preview", - "test-build": "node .infra/build.js -m development", - "build:docs": "typedoc" - }, - "devDependencies": { - "@preact/preset-vite": "^2.8.1", - "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@types/node": "^22.15.0", - "commander": "^11.1.0", - "glob": "^10.3.10", - "preact": "^10.19.6", - "prettier": "^3.2.5", - "prettier-plugin-organize-imports": "^3.2.4", - "typedoc": "^0.25.7", - "typescript": "^5.3.3", - "vite": "^5.1.4", - "vite-plugin-dts": "^3.7.3" - } + "name": "@d-id/client-sdk", + "private": false, + "version": "1.1.7", + "type": "module", + "description": "d-id client sdk", + "repository": { + "type": "git", + "url": "https://github.com/de-id/agents-sdk" + }, + "keywords": [ + "d-id", + "sdk", + "client-sdk" + ], + "license": "MIT", + "author": "d-id", + "files": [ + "dist/*" + ], + "main": "./dist/index.umd.cjs", + "module": "./dist/index.js", + "types": "./dist/src/index.d.ts", + "scripts": { + "dev": "vite", + "build": "node ./infra/build.js -m production", + "build:dev": "node ./infra/build.js -m development", + "dev:prod": "export NODE_ENV=production && vite --mode production", + "deploy:prod": "node ./infra/deploy.js --version beta", + "preview": "vite preview", + "test-build": "node .infra/build.js -m development", + "build:docs": "typedoc" + }, + "devDependencies": { + "@preact/preset-vite": "^2.8.1", + "@trivago/prettier-plugin-sort-imports": "^4.3.0", + "@types/node": "^22.15.0", + "commander": "^11.1.0", + "glob": "^10.3.10", + "preact": "^10.19.6", + "prettier": "^3.2.5", + "prettier-plugin-organize-imports": "^3.2.4", + "typedoc": "^0.25.7", + "typescript": "^5.3.3", + "vite": "^5.1.4", + "vite-plugin-dts": "^3.7.3" + } } diff --git a/src/api/streams/index.ts b/src/api/streams/index.ts index 10dae593..c86188d1 100644 --- a/src/api/streams/index.ts +++ b/src/api/streams/index.ts @@ -1,2 +1 @@ -export * from './clipStream' -export * from './talkStream' \ No newline at end of file +export * from './streamApi'; diff --git a/src/api/streams/clipStream.ts b/src/api/streams/streamApi.ts similarity index 76% rename from src/api/streams/clipStream.ts rename to src/api/streams/streamApi.ts index 5a1ae93f..d4fd971e 100644 --- a/src/api/streams/clipStream.ts +++ b/src/api/streams/streamApi.ts @@ -1,16 +1,17 @@ import { Auth, - ClipStreamOptions, + CreateStreamOptions, ICreateStreamRequestResponse, IceCandidate, RtcApi, SendClipStreamPayload, SendStreamPayloadResponse, + SendTalkStreamPayload, Status, } from '$/types/index'; import { createClient } from '../apiClient'; -export function createClipApi( +export function createStreamApi( auth: Auth, host: string, agentId: string, @@ -19,14 +20,8 @@ export function createClipApi( const client = createClient(auth, `${host}/agents/${agentId}`, onError); return { - createStream(options: ClipStreamOptions) { - return client.post('/streams', { - output_resolution: options.output_resolution, - compatibility_mode: options.compatibility_mode, - stream_warmup: options.stream_warmup, - session_timeout: options.session_timeout, - fluent: options.fluent, - }); + createStream(options: CreateStreamOptions) { + return client.post('/streams', options); }, startConnection(streamId: string, answer: RTCSessionDescriptionInit, sessionId?: string) { return client.post(`/streams/${streamId}/sdp`, { @@ -40,7 +35,7 @@ export function createClipApi( ...candidate, }); }, - sendStreamRequest(streamId: string, sessionId: string, payload: SendClipStreamPayload) { + sendStreamRequest(streamId: string, sessionId: string, payload: SendClipStreamPayload | SendTalkStreamPayload) { return client.post(`/streams/${streamId}`, { session_id: sessionId, ...payload, diff --git a/src/api/streams/talkStream.ts b/src/api/streams/talkStream.ts deleted file mode 100644 index b6596f72..00000000 --- a/src/api/streams/talkStream.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { - Auth, - ICreateStreamRequestResponse, - IceCandidate, - RtcApi, - SendStreamPayloadResponse, - SendTalkStreamPayload, - Status, - TalkStreamOptions, -} from '$/types/index'; -import { createClient } from '../apiClient'; - -export function createTalkApi( - auth: Auth, - host: string, - agentId: string, - onError?: (error: Error, errorData: object) => void -): RtcApi { - const client = createClient(auth, `${host}/agents/${agentId}`, onError); - - return { - createStream(streamOptions: TalkStreamOptions, options?: RequestInit) { - return client.post( - '/streams', - { - driver_url: streamOptions.driver_url, - face: streamOptions.face, - config: streamOptions.config, - output_resolution: streamOptions.output_resolution, - compatibility_mode: streamOptions.compatibility_mode, - stream_warmup: streamOptions.stream_warmup, - session_timeout: streamOptions.session_timeout, - fluent: streamOptions.fluent, - }, - options - ); - }, - startConnection( - streamId: string, - answer: RTCSessionDescriptionInit, - sessionId?: string, - options?: RequestInit - ) { - return client.post(`/streams/${streamId}/sdp`, { session_id: sessionId, answer }, options); - }, - addIceCandidate(streamId: string, candidate: IceCandidate, sessionId: string, options?: RequestInit) { - return client.post(`/streams/${streamId}/ice`, { session_id: sessionId, ...candidate }, options); - }, - sendStreamRequest(streamId: string, sessionId: string, payload: SendTalkStreamPayload, options?: RequestInit) { - return client.post( - `/streams/${streamId}`, - { - session_id: sessionId, - ...payload, - }, - options - ); - }, - close(streamId: string, sessionId: string, options?: RequestInit) { - return client.delete(`/streams/${streamId}`, { session_id: sessionId }, options); - }, - }; -} diff --git a/src/services/agent-manager/connect-to-manager.ts b/src/services/agent-manager/connect-to-manager.ts index f7a7fd04..24fc9d49 100644 --- a/src/services/agent-manager/connect-to-manager.ts +++ b/src/services/agent-manager/connect-to-manager.ts @@ -12,17 +12,15 @@ import { StreamEvents, StreamType, StreamingState, - mapVideoType, } from '$/types'; import { Analytics } from '../analytics/mixpanel'; import { interruptTimestampTracker, latencyTimestampTracker } from '../analytics/timestamp-tracker'; import { createChat } from '../chat'; -function getAgentStreamArgs(agent: Agent, options?: AgentManagerOptions): CreateStreamOptions { +function getAgentStreamArgs(options?: AgentManagerOptions): CreateStreamOptions { const { streamOptions } = options ?? {}; return { - videoType: mapVideoType(agent.presenter.type), output_resolution: streamOptions?.outputResolution, session_timeout: streamOptions?.sessionTimeout, stream_warmup: streamOptions?.streamWarmup, @@ -142,7 +140,7 @@ function connectToManager( return new Promise(async (resolve, reject) => { try { - const streamingManager = await createStreamingManager(agent.id, getAgentStreamArgs(agent, options), { + const streamingManager = await createStreamingManager(agent.id, getAgentStreamArgs(options), { ...options, analytics, callbacks: { @@ -196,27 +194,25 @@ export async function initializeStreamAndChat( analytics: Analytics, chat?: Chat ): Promise<{ chat?: Chat; streamingManager?: StreamingManager }> { - const { chat: newChat, chatMode } = await createChat( - agent, - agentsApi, - analytics, - options.mode, - options.persistentChat, - chat - ); + const createChatPromise = createChat(agent, agentsApi, analytics, options.mode, options.persistentChat, chat); + const connectToManagerPromise = connectToManager(agent, options, analytics); + + const [chatResult, streamingManager] = await Promise.all([createChatPromise, connectToManagerPromise]); + + const { chat: newChat, chatMode } = chatResult; if (chatMode && chatMode !== options.mode) { options.mode = chatMode; options.callbacks.onModeChange?.(chatMode); - if (chatMode === ChatMode.TextOnly) { + if (chatMode !== ChatMode.Functional) { options.callbacks.onError?.(new ChatModeDowngraded(chatMode)); + streamingManager?.disconnect(); + return { chat: newChat }; } } - const streamingManager = await connectToManager(agent, options, analytics); - return { chat: newChat, streamingManager }; } diff --git a/src/services/analytics/mixpanel.ts b/src/services/analytics/mixpanel.ts index c2a993a1..ecbfceef 100644 --- a/src/services/analytics/mixpanel.ts +++ b/src/services/analytics/mixpanel.ts @@ -71,6 +71,7 @@ export function initializeAnalytics(config: AnalyticsOptions): Analytics { ...sendProps, agentId: this.agentId, source, + token: this.token, time: Date.now(), $insert_id: this.getRandom(), origin: window.location.href, diff --git a/src/services/streaming-manager/index.ts b/src/services/streaming-manager/index.ts index 478a3769..881ca1e4 100644 --- a/src/services/streaming-manager/index.ts +++ b/src/services/streaming-manager/index.ts @@ -1,4 +1,4 @@ -import { createClipApi, createTalkApi } from '$/api/streams'; +import { createStreamApi } from '$/api/streams'; import { didApiUrl } from '$/config/environment'; import { AgentActivityState, @@ -9,7 +9,6 @@ import { StreamType, StreamingManagerOptions, StreamingState, - VideoType, } from '$/types/index'; import { pollStats } from './stats/poll'; import { VideoRTCStatsReport } from './stats/report'; @@ -142,10 +141,12 @@ export async function createStreamingManager( let dataChannelSignal: StreamingState = StreamingState.Stop; let statsSignal: StreamingState = StreamingState.Stop; - const { startConnection, sendStreamRequest, close, createStream, addIceCandidate } = - agent.videoType === VideoType.Clip - ? createClipApi(auth, baseURL, agentId, callbacks.onError) - : createTalkApi(auth, baseURL, agentId, callbacks.onError); + const { startConnection, sendStreamRequest, close, createStream, addIceCandidate } = createStreamApi( + auth, + baseURL, + agentId, + callbacks.onError + ); const { id: streamIdFromServer, diff --git a/src/types/stream/stream.ts b/src/types/stream/stream.ts index e135f13b..d32b0f6d 100644 --- a/src/types/stream/stream.ts +++ b/src/types/stream/stream.ts @@ -1,7 +1,6 @@ import { Analytics } from '$/services/analytics/mixpanel'; import { VideoRTCStatsReport } from '$/services/streaming-manager/stats/report'; import { Auth } from '../auth'; -import { VideoType } from '../entities'; import { CreateClipStreamRequest, CreateTalkStreamRequest, SendClipStreamPayload, SendTalkStreamPayload } from './api'; import { ICreateStreamRequestResponse, IceCandidate, SendStreamPayloadResponse, Status } from './rtc'; @@ -67,12 +66,10 @@ export interface ManagerCallbacks { export type ManagerCallbackKeys = keyof ManagerCallbacks; export interface TalkStreamOptions extends CreateTalkStreamRequest { - videoType: VideoType.Talk; fluent?: boolean; } export interface ClipStreamOptions extends CreateClipStreamRequest { - videoType: VideoType.Clip; fluent?: boolean; }