Fix voice clone: use absolute API URL for audio (not relative) so requests hit Render backend instead of Vercel SPA

This commit is contained in:
ajaysi
2026-04-22 15:00:54 +05:30
parent d7319c981e
commit fbbfe81ed7
3 changed files with 13 additions and 7 deletions

View File

@@ -10,7 +10,7 @@ import {
import { createAvatarVideoAsync } from '../../../../api/videoStudioApi'; import { createAvatarVideoAsync } from '../../../../api/videoStudioApi';
import { useVideoGenerationPolling } from '../../../../hooks/usePolling'; import { useVideoGenerationPolling } from '../../../../hooks/usePolling';
import { fetchMediaBlobUrl } from '../../../../utils/fetchMediaBlobUrl'; 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 { VideoCameraFront, SkipNext, PlayArrow, InfoOutlined, Close as CloseIcon, HelpOutline, Refresh, RestartAlt, Undo } from '@mui/icons-material';
import { VideoGenerationLoader } from '../../../shared/VideoGenerationLoader'; import { VideoGenerationLoader } from '../../../shared/VideoGenerationLoader';
import { OperationButton } from '../../../shared/OperationButton'; import { OperationButton } from '../../../shared/OperationButton';
@@ -49,8 +49,9 @@ export const TestPersonaModal: React.FC<TestPersonaModalProps> = ({
if (tokenGetter) { if (tokenGetter) {
const token = await tokenGetter(); const token = await tokenGetter();
if (token && !cancelled) { if (token && !cancelled) {
const sep = voiceUrl.includes('?') ? '&' : '?'; const absoluteUrl = voiceUrl.startsWith('/') ? `${getApiUrl()}${voiceUrl}` : voiceUrl;
setAuthenticatedVoiceUrl(`${voiceUrl}${sep}token=${encodeURIComponent(token)}`); const sep = absoluteUrl.includes('?') ? '&' : '?';
setAuthenticatedVoiceUrl(`${absoluteUrl}${sep}token=${encodeURIComponent(token)}`);
return; return;
} }
} }

View File

@@ -3,7 +3,7 @@ import { Box, Typography, Paper, Stack, Button, Alert, TextField, CircularProgre
import { keyframes } from '@mui/system'; 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 { 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 { createVoiceClone, createVoiceDesign, getLatestVoiceClone, setBrandVoice } from '../../../../api/brandAssets';
import { getAuthTokenGetter } from '../../../../api/client'; import { getAuthTokenGetter, getApiUrl } from '../../../../api/client';
import { OperationButton } from '../../../shared/OperationButton'; import { OperationButton } from '../../../shared/OperationButton';
const pulse = keyframes` const pulse = keyframes`
@@ -114,8 +114,9 @@ export const VoiceAvatarPlaceholder: React.FC<{ domainName?: string; onVoiceSet?
const token = await tokenGetter(); const token = await tokenGetter();
console.log('[VoiceClone] Got token:', token ? 'yes' : 'no'); console.log('[VoiceClone] Got token:', token ? 'yes' : 'no');
if (token && !cancelled) { if (token && !cancelled) {
const sep = resultAudioUrl.includes('?') ? '&' : '?'; const absoluteUrl = resultAudioUrl.startsWith('/') ? `${getApiUrl()}${resultAudioUrl}` : resultAudioUrl;
const authUrl = `${resultAudioUrl}${sep}token=${encodeURIComponent(token)}`; const sep = absoluteUrl.includes('?') ? '&' : '?';
const authUrl = `${absoluteUrl}${sep}token=${encodeURIComponent(token)}`;
console.log('[VoiceClone] Setting authenticatedAudioUrl:', authUrl); console.log('[VoiceClone] Setting authenticatedAudioUrl:', authUrl);
setAuthenticatedAudioUrl(authUrl); setAuthenticatedAudioUrl(authUrl);
return; return;

View File

@@ -43,7 +43,7 @@ import {
Category, Category,
} from "@mui/icons-material"; } from "@mui/icons-material";
import { getLatestVoiceClone, VoiceCloneResponse } from "../../api/brandAssets"; import { getLatestVoiceClone, VoiceCloneResponse } from "../../api/brandAssets";
import { getAuthTokenGetter } from "../../api/client"; import { getAuthTokenGetter, getApiUrl } from "../../api/client";
import { VoiceAvatarPlaceholder } from "../OnboardingWizard/PersonalizationStep/components/VoiceAvatarPlaceholder"; import { VoiceAvatarPlaceholder } from "../OnboardingWizard/PersonalizationStep/components/VoiceAvatarPlaceholder";
export type VoiceOption = { export type VoiceOption = {
@@ -250,6 +250,10 @@ export const VoiceSelector: React.FC<VoiceSelectorProps> = ({
// Append auth token for endpoints that require it (e.g. /api/assets/) // Append auth token for endpoints that require it (e.g. /api/assets/)
let previewUrl = voice.previewUrl; let previewUrl = voice.previewUrl;
// Convert relative URLs to absolute (pointing to backend, not Vercel)
if (previewUrl.startsWith('/')) {
previewUrl = `${getApiUrl()}${previewUrl}`;
}
try { try {
const tokenGetter = getAuthTokenGetter(); const tokenGetter = getAuthTokenGetter();
if (tokenGetter) { if (tokenGetter) {