/* B03 다중 파일 업로드 API 클라이언트 */ import { API_BASE_URL, API_TIMEOUT_MS } from "@config/config_frontend"; export interface UploadedFileResult { input_file_id: number; original_filename: string; file_type: string; relative_path: string; size_bytes: number; metadata: Record; } export interface FileUploadResponse { status: string; project_id: string; files: UploadedFileResult[]; } export interface ChunkSessionCreateResponse { status: string; project_id: string; upload_session_id: string; original_filename: string; file_size_bytes: number; chunk_size_bytes: number; total_chunks: number; completed_chunks: number; } export interface ChunkUploadResponse { status: string; upload_session_id: string; chunk_index: number; completed_chunks: number; total_chunks: number; chunk_hash: string; } export interface UploadStatusResponse { status: string; upload_session_id: string; upload_status: string; original_filename: string; file_size_bytes: number; chunk_size_bytes: number; total_chunks: number; completed_chunks: number; completed_chunk_indexes: number[]; } async function readJsonOrThrow(response: Response): Promise { const payload = (await response.json()) as T & { message?: string }; if (!response.ok) { throw new Error(payload.message ?? `HTTP ${response.status}`); } return payload; } export async function uploadProjectFiles( projectId: string, files: readonly File[], ): Promise { const formData = new FormData(); for (const file of files) formData.append("files", file, file.name); const controller = new AbortController(); const timeoutId = window.setTimeout(() => controller.abort(), API_TIMEOUT_MS); try { const response = await fetch(`${API_BASE_URL}/projects/${projectId}/files`, { method: "POST", credentials: "include", body: formData, signal: controller.signal, }); return await readJsonOrThrow(response); } finally { window.clearTimeout(timeoutId); } } export async function createUploadSession( projectId: string, file: File, chunkSizeBytes: number, ): Promise { const response = await fetch(`${API_BASE_URL}/projects/${projectId}/upload-sessions`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ original_filename: file.name, size_bytes: file.size, chunk_size_bytes: chunkSizeBytes, }), }); return await readJsonOrThrow(response); } export async function uploadFileChunk( projectId: string, sessionId: string, chunkIndex: number, chunk: Blob, ): Promise { const formData = new FormData(); formData.append("session_id", sessionId); formData.append("chunk_index", String(chunkIndex)); formData.append("chunk_data", chunk, `${sessionId}-${chunkIndex}.chunk`); const response = await fetch(`${API_BASE_URL}/projects/${projectId}/chunks`, { method: "POST", credentials: "include", body: formData, }); return await readJsonOrThrow(response); } export async function finalizeUploadSession( projectId: string, sessionId: string, totalChunks: number, ): Promise { const response = await fetch(`${API_BASE_URL}/projects/${projectId}/finalize`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ session_id: sessionId, total_chunks: totalChunks }), }); return await readJsonOrThrow(response); } export async function fetchUploadStatus( projectId: string, sessionId: string, ): Promise { const response = await fetch(`${API_BASE_URL}/projects/${projectId}/upload-status/${sessionId}`, { method: "GET", credentials: "include", }); return await readJsonOrThrow(response); } export interface WF1AnalysisStatus { project_id: string; status: "pending" | "in_progress" | "completed" | "failed"; model_count: number; progress_percent: number; current_stage: string; message: string; error?: string; } export async function checkWF1AnalysisStatus(projectId: string): Promise { const response = await fetch(`${API_BASE_URL}/projects/${projectId}/surface/status`, { method: "GET", credentials: "include", }); return await readJsonOrThrow(response); }