diff --git a/src/api/posthogClient.ts b/src/api/posthogClient.ts index 73105d79c..56fe5a5c0 100644 --- a/src/api/posthogClient.ts +++ b/src/api/posthogClient.ts @@ -321,25 +321,6 @@ export class PostHogAPIClient { return await response.json(); } - async getDesktopRecordingTranscript(recordingId: string) { - this.validateRecordingId(recordingId); - const teamId = await this.getTeamId(); - const url = new URL( - `${this.api.baseUrl}/api/environments/${teamId}/desktop_recordings/${recordingId}/transcript/`, - ); - const response = await this.api.fetcher.fetch({ - method: "get", - url, - path: `/api/environments/${teamId}/desktop_recordings/${recordingId}/transcript/`, - }); - - if (!response.ok) { - throw new Error(`Failed to fetch transcript: ${response.statusText}`); - } - - return await response.json(); - } - async listDesktopRecordings(filters?: { platform?: string; status?: string; @@ -405,28 +386,18 @@ export class PostHogAPIClient { return data; } - async updateDesktopRecordingTranscript( + async appendSegments( recordingId: string, - updates: { - segments?: Array<{ - timestamp_ms: number; - speaker: string | null; - text: string; - confidence: number | null; - is_final: boolean; - }>; - full_text?: string; - }, - ) { + segments: Array, + ): Promise { this.validateRecordingId(recordingId); const teamId = await this.getTeamId(); const data = await this.api.post( - //@ts-expect-error not in the generated client - "/api/environments/{project_id}/desktop_recordings/{id}/transcript/", + "/api/environments/{project_id}/desktop_recordings/{id}/append_segments/", { path: { project_id: teamId.toString(), id: recordingId }, - body: updates as any, + body: { segments } as Schemas.AppendSegments, }, ); diff --git a/src/main/services/recallRecording.ts b/src/main/services/recallRecording.ts index 23b6ec09c..05d7fc7c6 100644 --- a/src/main/services/recallRecording.ts +++ b/src/main/services/recallRecording.ts @@ -94,6 +94,12 @@ export function initializeRecallSDK( posthogKey: string, posthogHost: string, ) { + console.log("[Recall SDK] initializeRecallSDK called with:", { + recallApiUrl, + posthogHost, + hasKey: !!posthogKey, + }); + if (sdkInitialized) { console.warn("[Recall SDK] Already initialized, skipping"); return; @@ -106,28 +112,17 @@ export function initializeRecallSDK( return; } - console.log("[Recall SDK] Initializing..."); - - sdkInitialized = true; - posthogClient = new PostHogAPIClient(posthogKey, posthogHost); - - RecallAiSdk.init({ - apiUrl: recallApiUrl, - acquirePermissionsOnStartup: [ - "accessibility", - "screen-capture", - "microphone", - ], - restartOnError: true, - }); + console.log("[Recall SDK] Setting up event listeners..."); - console.log("[Recall SDK] Ready. Listening for meetings..."); + // IMPORTANT: Register ALL event listeners BEFORE calling init() + // This is required by Recall SDK RecallAiSdk.addEventListener("permissions-granted", async () => { console.log("[Recall SDK] Permissions granted"); }); RecallAiSdk.addEventListener("permission-status", async (evt) => { + console.log("[Recall SDK] Permission status:", evt.permission, evt.status); if (evt.status === "denied" || evt.status === "error") { console.warn(`[Recall SDK] Permission ${evt.permission}: ${evt.status}`); } @@ -385,6 +380,34 @@ export function initializeRecallSDK( ); } }); + + console.log("[Recall SDK] All event listeners registered"); + + // NOW initialize the SDK (after all event listeners are set up) + console.log("[Recall SDK] Initializing SDK..."); + sdkInitialized = true; + posthogClient = new PostHogAPIClient(posthogKey, posthogHost); + console.log("[Recall SDK] PostHog client created"); + + try { + RecallAiSdk.init({ + apiUrl: recallApiUrl, + acquirePermissionsOnStartup: [ + "accessibility", + "screen-capture", + "microphone", + ], + restartOnError: true, + }); + console.log("[Recall SDK] RecallAiSdk.init() completed successfully"); + } catch (error) { + console.error("[Recall SDK] Failed to initialize SDK:", error); + sdkInitialized = false; + posthogClient = null; + throw error; + } + + console.log("[Recall SDK] ✓ Ready. Listening for meetings..."); } export function requestRecallPermission( @@ -398,18 +421,37 @@ export function shutdownRecallSDK() { } export function registerRecallIPCHandlers() { + console.log("[Recall SDK] Registering IPC handlers..."); + ipcMain.handle( "recall:initialize", async (_event, recallApiUrl, posthogKey, posthogHost) => { - initializeRecallSDK(recallApiUrl, posthogKey, posthogHost); + console.log("[Recall SDK] IPC handler 'recall:initialize' called"); + try { + initializeRecallSDK(recallApiUrl, posthogKey, posthogHost); + console.log("[Recall SDK] IPC handler 'recall:initialize' completed"); + } catch (error) { + console.error( + "[Recall SDK] IPC handler 'recall:initialize' error:", + error, + ); + throw error; + } }, ); ipcMain.handle("recall:request-permission", async (_event, permission) => { + console.log( + "[Recall SDK] IPC handler 'recall:request-permission' called:", + permission, + ); requestRecallPermission(permission); }); ipcMain.handle("recall:shutdown", async () => { + console.log("[Recall SDK] IPC handler 'recall:shutdown' called"); shutdownRecallSDK(); }); + + console.log("[Recall SDK] IPC handlers registered successfully"); } diff --git a/src/renderer/features/auth/stores/authStore.ts b/src/renderer/features/auth/stores/authStore.ts index dfb446749..be54e914a 100644 --- a/src/renderer/features/auth/stores/authStore.ts +++ b/src/renderer/features/auth/stores/authStore.ts @@ -11,6 +11,29 @@ import { const RECALL_API_URL = "https://us-west-2.recall.ai"; +// Helper function to initialize Recall SDK +async function initializeRecallSDK( + accessToken: string, + apiHost: string, +): Promise { + try { + console.log("[Auth] Calling recallInitialize with:", { + url: RECALL_API_URL, + host: apiHost, + hasToken: !!accessToken, + }); + await window.electronAPI.recallInitialize( + RECALL_API_URL, + accessToken, + apiHost, + ); + console.log("[Auth] recallInitialize completed successfully"); + } catch (error) { + console.error("[Auth] Failed to initialize Recall SDK:", error); + // Don't throw - Recall SDK failure shouldn't block authentication + } +} + interface AuthState { // OAuth state oauthAccessToken: string | null; @@ -137,19 +160,8 @@ export const useAuthStore = create()( throw new Error("Failed to authenticate with PostHog"); } - try { - window.electronAPI - .recallInitialize( - RECALL_API_URL, - tokenResponse.access_token, - apiHost, - ) - .catch((error) => { - console.error("[Auth] Failed to initialize Recall SDK:", error); - }); - } catch (_error) { - throw new Error("Invalid API key or host"); - } + // Initialize Recall SDK for meeting detection + await initializeRecallSDK(tokenResponse.access_token, apiHost); }, refreshAccessToken: async () => { @@ -332,6 +344,9 @@ export const useAuthStore = create()( } } + // Initialize Recall SDK for meeting detection (session restore) + await initializeRecallSDK(tokens.accessToken, apiHost); + return true; } catch (error) { console.error("Failed to validate OAuth session:", error); diff --git a/src/renderer/features/notetaker/components/RecordingView.tsx b/src/renderer/features/notetaker/components/RecordingView.tsx index e6c126c9c..cfb42d8e0 100644 --- a/src/renderer/features/notetaker/components/RecordingView.tsx +++ b/src/renderer/features/notetaker/components/RecordingView.tsx @@ -14,20 +14,12 @@ export function RecordingView({ recordingItem }: RecordingViewProps) { const segments: TranscriptSegment[] = recordingItem.type === "active" ? recordingItem.recording.segments || [] - : ( - recordingItem.recording.transcript_segments as Array<{ - timestamp_ms: number; - speaker: string | null; - text: string; - confidence: number | null; - is_final: boolean; - }> - )?.map((seg) => ({ - timestamp: seg.timestamp_ms, - speaker: seg.speaker, + : recordingItem.recording.transcript_segments?.map((seg) => ({ + timestamp: seg.timestamp ?? 0, + speaker: seg.speaker ?? null, text: seg.text, - confidence: seg.confidence, - is_final: seg.is_final, + confidence: seg.confidence ?? null, + is_final: seg.is_final ?? false, })) || []; useEffect(() => { diff --git a/src/renderer/services/recordingService.ts b/src/renderer/services/recordingService.ts index dbb94879b..053be354f 100644 --- a/src/renderer/services/recordingService.ts +++ b/src/renderer/services/recordingService.ts @@ -173,15 +173,16 @@ async function uploadPendingSegments(recordingId: string): Promise { throw new Error("PostHog client not initialized"); } - await client.updateDesktopRecordingTranscript(recordingId, { - segments: pendingSegments.map((seg) => ({ - timestamp_ms: seg.timestamp, + await client.appendSegments( + recordingId, + pendingSegments.map((seg) => ({ + timestamp: seg.timestamp, speaker: seg.speaker, text: seg.text, confidence: seg.confidence, is_final: seg.is_final, })), - }); + ); const newIndex = recording.lastUploadedSegmentIndex + pendingSegments.length;