diff --git a/frontend/src/components/OnboardingWizard/PersonalizationStep/components/TestPersonaModal.tsx b/frontend/src/components/OnboardingWizard/PersonalizationStep/components/TestPersonaModal.tsx index e9d65f0b..57d932e5 100644 --- a/frontend/src/components/OnboardingWizard/PersonalizationStep/components/TestPersonaModal.tsx +++ b/frontend/src/components/OnboardingWizard/PersonalizationStep/components/TestPersonaModal.tsx @@ -10,7 +10,7 @@ import { import { createAvatarVideoAsync } from '../../../../api/videoStudioApi'; import { useVideoGenerationPolling } from '../../../../hooks/usePolling'; import { fetchMediaBlobUrl } from '../../../../utils/fetchMediaBlobUrl'; -import { getAuthTokenGetter } from '../../../../api/client'; +import { getAuthTokenGetter, getApiUrl } from '../../../../api/client'; import { VideoCameraFront, SkipNext, PlayArrow, InfoOutlined, Close as CloseIcon, HelpOutline, Refresh, RestartAlt, Undo } from '@mui/icons-material'; import { VideoGenerationLoader } from '../../../shared/VideoGenerationLoader'; import { OperationButton } from '../../../shared/OperationButton'; @@ -49,8 +49,9 @@ export const TestPersonaModal: React.FC = ({ if (tokenGetter) { const token = await tokenGetter(); if (token && !cancelled) { - const sep = voiceUrl.includes('?') ? '&' : '?'; - setAuthenticatedVoiceUrl(`${voiceUrl}${sep}token=${encodeURIComponent(token)}`); + const absoluteUrl = voiceUrl.startsWith('/') ? `${getApiUrl()}${voiceUrl}` : voiceUrl; + const sep = absoluteUrl.includes('?') ? '&' : '?'; + setAuthenticatedVoiceUrl(`${absoluteUrl}${sep}token=${encodeURIComponent(token)}`); return; } } diff --git a/frontend/src/components/OnboardingWizard/PersonalizationStep/components/VoiceAvatarPlaceholder.tsx b/frontend/src/components/OnboardingWizard/PersonalizationStep/components/VoiceAvatarPlaceholder.tsx index 662d253f..74bed5cb 100644 --- a/frontend/src/components/OnboardingWizard/PersonalizationStep/components/VoiceAvatarPlaceholder.tsx +++ b/frontend/src/components/OnboardingWizard/PersonalizationStep/components/VoiceAvatarPlaceholder.tsx @@ -3,7 +3,7 @@ import { Box, Typography, Paper, Stack, Button, Alert, TextField, CircularProgre import { keyframes } from '@mui/system'; import { Mic, GraphicEq, Timer, CloudUpload, Stop, PlayArrow, InfoOutlined, TextFields, HelpOutline, AutoAwesome, Campaign, MicNone, Podcasts, RestartAlt, Undo, Headphones, Article, VideoLibrary, TrendingUp, CheckCircle, RecordVoiceOver, Settings } from '@mui/icons-material'; import { createVoiceClone, createVoiceDesign, getLatestVoiceClone, setBrandVoice } from '../../../../api/brandAssets'; -import { getAuthTokenGetter } from '../../../../api/client'; +import { getAuthTokenGetter, getApiUrl } from '../../../../api/client'; import { OperationButton } from '../../../shared/OperationButton'; const pulse = keyframes` @@ -114,8 +114,9 @@ export const VoiceAvatarPlaceholder: React.FC<{ domainName?: string; onVoiceSet? const token = await tokenGetter(); console.log('[VoiceClone] Got token:', token ? 'yes' : 'no'); if (token && !cancelled) { - const sep = resultAudioUrl.includes('?') ? '&' : '?'; - const authUrl = `${resultAudioUrl}${sep}token=${encodeURIComponent(token)}`; + const absoluteUrl = resultAudioUrl.startsWith('/') ? `${getApiUrl()}${resultAudioUrl}` : resultAudioUrl; + const sep = absoluteUrl.includes('?') ? '&' : '?'; + const authUrl = `${absoluteUrl}${sep}token=${encodeURIComponent(token)}`; console.log('[VoiceClone] Setting authenticatedAudioUrl:', authUrl); setAuthenticatedAudioUrl(authUrl); return; diff --git a/frontend/src/components/shared/VoiceSelector.tsx b/frontend/src/components/shared/VoiceSelector.tsx index 03332b23..4c4d8af6 100644 --- a/frontend/src/components/shared/VoiceSelector.tsx +++ b/frontend/src/components/shared/VoiceSelector.tsx @@ -43,7 +43,7 @@ import { Category, } from "@mui/icons-material"; import { getLatestVoiceClone, VoiceCloneResponse } from "../../api/brandAssets"; -import { getAuthTokenGetter } from "../../api/client"; +import { getAuthTokenGetter, getApiUrl } from "../../api/client"; import { VoiceAvatarPlaceholder } from "../OnboardingWizard/PersonalizationStep/components/VoiceAvatarPlaceholder"; export type VoiceOption = { @@ -250,6 +250,10 @@ export const VoiceSelector: React.FC = ({ // Append auth token for endpoints that require it (e.g. /api/assets/) let previewUrl = voice.previewUrl; + // Convert relative URLs to absolute (pointing to backend, not Vercel) + if (previewUrl.startsWith('/')) { + previewUrl = `${getApiUrl()}${previewUrl}`; + } try { const tokenGetter = getAuthTokenGetter(); if (tokenGetter) {