import api from "./http"; import { Asset, ChatMessage, ChatResponse, PipelineStatus, Project, ProjectListItem, RenderStatus, Scene, StudioResponse, ProjectTemplateChangeJob, ProjectRegenerateScriptJob, RegenerateScriptPreviewOut, } from "./types"; // ─── Project API ────────────────────────────────────────── export const createProject = ( blog_url: string, name?: string, voice_gender?: string, voice_accent?: string, accent_color?: string, bg_color?: string, text_color?: string, animation_instructions?: string, logo_position?: string, logo_opacity?: number, custom_voice_id?: string, aspect_ratio?: string ) => api.post("/projects", { blog_url, name, voice_gender, voice_accent, accent_color, bg_color, text_color, animation_instructions, logo_position, logo_opacity, custom_voice_id, aspect_ratio, }); export const uploadLogo = (projectId: number, file: File) => { const formData = new FormData(); formData.append("file", file); return api.post<{ logo_url: string; logo_position: string }>( `/projects/${projectId}/logo`, formData, { headers: { "Content-Type": "multipart/form-data" } } ); }; export const listProjects = () => api.get("/projects"); export const getProject = (id: number) => api.get(`/projects/${id}`); export const deleteProject = (id: number) => api.delete(`/projects/${id}`); export const toggleAssetExclusion = (projectId: number, assetId: number) => api.patch<{ id: number; excluded: boolean }>( `/projects/${projectId}/assets/${assetId}/exclude` ); export const scrapeProject = (id: number) => api.post(`/projects/${id}/scrape`); export const generateScript = (id: number) => api.post(`/projects/${id}/generate-script`); export const generateScenes = (id: number) => api.post(`/projects/${id}/generate-scenes`); // ─── Async pipeline ────────────────────────────────────── export const startGeneration = (id: number) => api.post(`/projects/${id}/generate`); export const getPipelineStatus = (id: number) => api.get(`/projects/${id}/status`); export const changeProjectTemplateRegenerateLayouts = ( projectId: number, template: string ) => api.post( `/projects/${projectId}/change-template-regenerate-layouts`, { template } ); export const getProjectTemplateChangeStatus = (projectId: number) => api.get( `/projects/${projectId}/template-change-status` ); export const regenerateScript = ( projectId: number, body?: { user_instruction?: string }, ) => api.post( `/projects/${projectId}/regenerate-script`, body ?? {}, ); export const getRegenerateScriptStatus = (projectId: number) => api.get( `/projects/${projectId}/regenerate-script-status` ); // Fetch the previous (pre-regeneration) scenes for the verify-step before/after comparison. export const getRegenerateScriptPreview = (projectId: number) => api.get( `/projects/${projectId}/regenerate-script/preview` ); // Approve the regenerated script (paused at the verify step) and resume scene generation. export const verifyRegenerateScript = (projectId: number) => api.post( `/projects/${projectId}/regenerate-script/verify`, {}, ); // Discard the regenerated script and re-run it, optionally with a modified instruction. export const rejectRegenerateScript = ( projectId: number, body?: { user_instruction?: string }, ) => api.post( `/projects/${projectId}/regenerate-script/regenerate`, body ?? {}, ); export const updateScene = ( projectId: number, sceneId: number, data: Partial ) => api.put(`/projects/${projectId}/scenes/${sceneId}`, data); export const deleteScene = (projectId: number, sceneId: number) => api.delete(`/projects/${projectId}/scenes/${sceneId}`); export const launchStudio = (id: number) => api.post(`/projects/${id}/launch-studio`); export const renderVideo = (id: number, resolution: string = "720p") => api.post(`/projects/${id}/render?resolution=${resolution}`); export const getRenderStatus = (id: number) => api.get(`/projects/${id}/render-status`); export const downloadVideo = async (id: number, filename?: string) => { const urlRes = await api.get<{ url: string }>(`/projects/${id}/download-url`); const videoUrl = urlRes.data.url; // Fetch the video as a blob so the download works even with popup blockers. // Using fetch() directly (not axios) because the URL may be a cross-origin R2 URL. const resp = await fetch(videoUrl); if (!resp.ok) throw new Error(`Download failed (${resp.status})`); const blob = await resp.blob(); const blobUrl = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.href = blobUrl; a.download = filename || "video.mp4"; document.body.appendChild(a); a.click(); a.remove(); window.URL.revokeObjectURL(blobUrl); }; export const downloadStudioZip = async (id: number, filename?: string) => { const res = await api.get(`/projects/${id}/download-studio`, { responseType: "blob", }); const url = window.URL.createObjectURL(new Blob([res.data])); const a = document.createElement("a"); a.href = url; a.download = filename || "studio_project.zip"; document.body.appendChild(a); a.click(); a.remove(); window.URL.revokeObjectURL(url); }; export const sendChatMessage = (id: number, message: string) => api.post(`/projects/${id}/chat`, { message }); export const getChatHistory = (id: number) => api.get(`/projects/${id}/chat/history`);