Skip to content
This repository was archived by the owner on Mar 24, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/app/api/vexa/[...path]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ async function proxyRequest(

const { path } = await params;
const pathString = path.join("/");
const url = `${VEXA_API_URL}/${pathString}`;
const search = request.nextUrl.search; // preserve query string (e.g. ?meeting_id=113)
const url = `${VEXA_API_URL}/${pathString}${search}`;

const headers: HeadersInit = {
"Content-Type": "application/json",
Expand Down
11 changes: 6 additions & 5 deletions src/app/meetings/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ export default function MeetingDetailPage() {
currentMeeting?.platform &&
currentMeeting?.platform_specific_id
) {
fetchTranscripts(currentMeeting.platform, currentMeeting.platform_specific_id);
fetchTranscripts(currentMeeting.platform, currentMeeting.platform_specific_id, String(currentMeeting.id));
}
}, [fetchMeeting, fetchTranscripts, meetingId, currentMeeting?.platform, currentMeeting?.platform_specific_id]);

Expand All @@ -267,7 +267,7 @@ export default function MeetingDetailPage() {
// Optimistic transition to post-meeting UI immediately after stop is accepted.
setForcePostMeetingMode(true);
updateMeetingStatus(String(currentMeeting.id), "stopping");
fetchTranscripts(currentMeeting.platform, currentMeeting.platform_specific_id);
fetchTranscripts(currentMeeting.platform, currentMeeting.platform_specific_id, String(currentMeeting.id));
toast.success("Bot stopped", {
description: "The transcription has been stopped.",
});
Expand Down Expand Up @@ -557,22 +557,23 @@ export default function MeetingDetailPage() {
// Use specific properties as dependencies to avoid unnecessary refetches
const meetingPlatform = currentMeeting?.platform;
const meetingNativeId = currentMeeting?.platform_specific_id;
const meetingDbId = currentMeeting?.id != null ? String(currentMeeting.id) : undefined;
const meetingStatus = currentMeeting?.status;

useEffect(() => {
// Always refresh transcript/recording artifacts when entering post-meeting flow.
if ((meetingStatus === "stopping" || meetingStatus === "completed") && meetingPlatform && meetingNativeId) {
fetchTranscripts(meetingPlatform, meetingNativeId);
fetchTranscripts(meetingPlatform, meetingNativeId, meetingDbId);
fetchChatMessages(meetingPlatform, meetingNativeId);
return;
}

// During non-WS states, use REST fetch as source of truth.
if (!shouldUseWebSocket && meetingPlatform && meetingNativeId) {
fetchTranscripts(meetingPlatform, meetingNativeId);
fetchTranscripts(meetingPlatform, meetingNativeId, meetingDbId);
fetchChatMessages(meetingPlatform, meetingNativeId);
}
}, [meetingStatus, shouldUseWebSocket, meetingPlatform, meetingNativeId, fetchTranscripts, fetchChatMessages]);
}, [meetingStatus, shouldUseWebSocket, meetingPlatform, meetingNativeId, meetingDbId, fetchTranscripts, fetchChatMessages]);

// Also fetch chat messages for active meetings (WS handles real-time, REST bootstraps)
useEffect(() => {
Expand Down
8 changes: 6 additions & 2 deletions src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,13 @@ export const vexaAPI = {
// Get meeting info with transcripts - returns full meeting data from transcripts endpoint
async getMeetingWithTranscripts(
platform: Platform,
nativeId: string
nativeId: string,
dbMeetingId?: string
): Promise<{ meeting: Meeting; segments: TranscriptSegment[]; recordings: RecordingData[] }> {
const response = await fetch(`/api/vexa/transcripts/${platform}/${nativeId}`);
const url = dbMeetingId
? `/api/vexa/transcripts/${platform}/${nativeId}?meeting_id=${dbMeetingId}`
: `/api/vexa/transcripts/${platform}/${nativeId}`;
const response = await fetch(url);
interface RawSegment {
start: number;
end: number;
Expand Down
6 changes: 3 additions & 3 deletions src/stores/meetings-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ interface MeetingsState {
fetchMeetings: () => Promise<void>;
fetchMeeting: (id: string, options?: { silent?: boolean }) => Promise<void>;
refreshMeeting: (id: string) => Promise<void>;
fetchTranscripts: (platform: Platform, nativeId: string) => Promise<void>;
fetchTranscripts: (platform: Platform, nativeId: string, dbMeetingId?: string) => Promise<void>;
updateMeetingData: (platform: Platform, nativeId: string, data: MeetingDataUpdate) => Promise<void>;
deleteMeeting: (platform: Platform, nativeId: string, meetingId?: string) => Promise<void>;
setCurrentMeeting: (meeting: Meeting | null) => void;
Expand Down Expand Up @@ -156,10 +156,10 @@ export const useMeetingsStore = create<MeetingsState>((set, get) => ({
},

// Fetch transcripts for a meeting
fetchTranscripts: async (platform: Platform, nativeId: string) => {
fetchTranscripts: async (platform: Platform, nativeId: string, dbMeetingId?: string) => {
set({ isLoadingTranscripts: true, error: null });
try {
const result = await vexaAPI.getMeetingWithTranscripts(platform, nativeId);
const result = await vexaAPI.getMeetingWithTranscripts(platform, nativeId, dbMeetingId);
// Reuse the same canonical pipeline as WS/bootstraps:
// - filter invalid
// - sort by absolute_start_time
Expand Down