Skip to content

Commit

Permalink
feat: regenerate larger videos on the server
Browse files Browse the repository at this point in the history
  • Loading branch information
ccoreilly committed Nov 10, 2024
1 parent 9a1d535 commit a08c73a
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 9 deletions.
46 changes: 40 additions & 6 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import LoadingOverlay from './components/LoadingOverlay';
import { speakerService } from './services/SpeakerService';
import { Voice } from './types/Voice';
import { AudioTrack } from './types/AudioTrack';
import RegenerateModal from './components/RegenerateModal';

const GlobalStyle = createGlobalStyle`
body {
Expand Down Expand Up @@ -157,6 +158,7 @@ function App() {
const [backgroundLoadingMessage, setBackgroundLoadingMessage] = useState<string | null>(null);
const [isEditMode, setIsEditMode] = useState(false);
const [timelineVisible, setTimelineVisible] = useState(false);
const [showRegenerateModal, setShowRegenerateModal] = useState(false);

useEffect(() => {
const params = new URLSearchParams(window.location.search);
Expand Down Expand Up @@ -575,6 +577,17 @@ function App() {
}
};

const handleRegenerateVideo = async () => {
if (uuidParam) {
try {
await DubbingAPIService.regenerateVideo(uuidParam, tracks);
} catch (error) {
console.error('Error regenerating video:', error);
// You might want to show an error message to the user
}
}
};

return (
<>
<GlobalStyle />
Expand Down Expand Up @@ -606,12 +619,27 @@ function App() {
{t('edit')}
</Button>
)}
<Button
onClick={isEditMode ? handleDownloadClick : handleSimpleDownload}
disabled={isEditMode && !isMediaFullyLoaded}
>
{t('downloadResult')}
</Button>
{isEditMode ? (
advancedEditMode ? (
<Button
onClick={handleDownloadClick}
disabled={!isMediaFullyLoaded}
>
{t('downloadResult')}
</Button>
) : (
<Button
onClick={() => setShowRegenerateModal(true)}
disabled={!isMediaFullyLoaded}
>
{t('regenerate')}
</Button>
)
) : (
<Button onClick={handleSimpleDownload}>
{t('downloadResult')}
</Button>
)}
</>
)}
{!isDubbingService && (
Expand Down Expand Up @@ -748,6 +776,12 @@ function App() {
/>
)}
{isRebuilding && <LoadingOverlay message={t('rebuildingMedia')} />}
{showRegenerateModal && (
<RegenerateModal
onClose={() => setShowRegenerateModal(false)}
onRegenerate={handleRegenerateVideo}
/>
)}
</>
);
}
Expand Down
75 changes: 75 additions & 0 deletions src/components/RegenerateModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import { useTranslation } from 'react-i18next';
import { Button, ModalOverlay } from '../styles/designSystem';

const ModalContent = styled.div`
background: white;
padding: 20px;
border-radius: 8px;
max-width: 500px;
width: 90%;
`;

const ButtonContainer = styled.div`
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 20px;
`;

const Message = styled.p`
margin: 0 0 20px 0;
line-height: 1.5;
`;

interface RegenerateModalProps {
onClose: () => void;
onRegenerate: () => Promise<void>;
}

const RegenerateModal: React.FC<RegenerateModalProps> = ({ onClose, onRegenerate }) => {
const { t } = useTranslation();
const [isRegenerating, setIsRegenerating] = useState(false);
const [isComplete, setIsComplete] = useState(false);

const handleRegenerate = async () => {
setIsRegenerating(true);
try {
await onRegenerate();
setIsComplete(true);
} catch (error) {
console.error('Error regenerating video:', error);
// You might want to show an error message here
}
};

return (
<ModalOverlay>
<ModalContent>
<Message>
{isComplete
? t('regenerateRequestSent')
: t('regenerateDescription')}
</Message>
<ButtonContainer>
{!isComplete ? (
<>
<Button onClick={onClose}>{t('cancel')}</Button>
<Button
onClick={handleRegenerate}
disabled={isRegenerating}
>
{isRegenerating ? t('regenerating') : t('regenerate')}
</Button>
</>
) : (
<Button onClick={onClose}>{t('close')}</Button>
)}
</ButtonContainer>
</ModalContent>
</ModalOverlay>
);
};

export default RegenerateModal;
7 changes: 6 additions & 1 deletion src/locales/ca.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,10 @@
"edit": "Edita",
"advanced": "Avançat",
"enableTimeline": "Mostrar Línia de Temps",
"delete": "Eliminar"
"delete": "Eliminar",
"regenerate": "Regenera",
"regenerating": "Regenerant...",
"regenerateDescription": "Després d'haver fet totes les modificacions necessàries, pots enviar-nos les modificacions per regenerar el vídeo. Rebràs un correu electrònic quan el vídeo estigui llest.",
"regenerateRequestSent": "La teva petició ha estat enviada amb èxit. Rebràs un correu electrònic quan el vídeo estigui llest.",
"close": "Tanca"
}
7 changes: 6 additions & 1 deletion src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,10 @@
"edit": "Edit",
"advanced": "Advanced",
"enableTimeline": "Enable Timeline",
"delete": "Delete"
"delete": "Delete",
"regenerate": "Regenerate",
"regenerating": "Regenerating...",
"regenerateDescription": "Once you have made all the necessary edits you can send us back the modifications so we can regenrate the video. You will receive an email once the video is ready.",
"regenerateRequestSent": "Your request has been sent successfully. You will receive an email once the video is ready.",
"close": "Close"
}
7 changes: 6 additions & 1 deletion src/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,10 @@
"edit": "Edita",
"advanced": "Avançat",
"enableTimeline": "Mostrar Línea de Tiempo",
"delete": "Eliminar"
"delete": "Eliminar",
"regenerate": "Regenera",
"regenerating": "Regenerant...",
"regenerateDescription": "Después de haber hecho todas las modificaciones necesarias, puedes enviarnos las modificaciones para regenerar el vídeo. Recibirás un correo electrónico cuando el vídeo esté listo.",
"regenerateRequestSent": "La petición ha sido enviada con éxito. Recibirás un correo electrónico cuando el vídeo esté listo.",
"close": "Cerrar"
}
1 change: 1 addition & 0 deletions src/services/APIServiceInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface DubbingAPIServiceInterface extends APIServiceInterface {
getBackgroundAudioUrl: (uuid: string) => string;
getOriginalVocalsUrl: (uuid: string) => string;
getDubbedVocalsUrl: (uuid: string) => string;
regenerateVideo: (uuid: string, tracks: Track[]) => Promise<void>;
}

export interface TranscriptionAPIServiceInterface extends APIServiceInterface {
Expand Down
42 changes: 42 additions & 0 deletions src/services/DubbingAPIService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,47 @@ export const getDubbedVocalsUrl = (uuid: string): string => {
return `${API_BASE_URL}/get_chunk/?uuid=${uuid}&chunk_name=dubbed_vocals.mp3`;
};

export const regenerateVideo = async (
uuid: string,
tracks: Track[]
): Promise<void> => {
// Filter out deleted tracks and convert to DubbingJSON format
const utteranceUpdate = tracks
.filter((track) => !track.deleted)
.map((track) => ({
id: track.id,
start: track.start,
end: track.end,
speaker_id: track.speaker_id,
path: track.path,
text: track.text,
for_dubbing: track.for_dubbing,
gender: track.ssml_gender,
translated_text: track.translated_text,
assigned_voice:
speakerService.getSpeakerById(track.speaker_id)?.voice?.id || "",
pitch: track.pitch,
speed: track.speed,
volume_gain_db: track.volume_gain_db,
dubbed_path: track.dubbed_path,
}));

const response = await fetch(`${API_BASE_URL}/regenerate_video`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
uuid,
utterance_update: utteranceUpdate,
}),
});

if (!response.ok) {
throw new Error("Failed to regenerate video");
}
};

export const DubbingAPIService: DubbingAPIServiceInterface = {
loadOriginalVocalsFromUUID,
loadBackgroundAudioFromUUID,
Expand All @@ -156,4 +197,5 @@ export const DubbingAPIService: DubbingAPIServiceInterface = {
getBackgroundAudioUrl,
getOriginalVocalsUrl,
getDubbedVocalsUrl,
regenerateVideo,
};

0 comments on commit a08c73a

Please sign in to comment.