// 画布服务层 import type { CanvasProject, CanvasState, CanvasNode } from '@/types/canvas'; // API 响应类型 interface ApiResponse { success: boolean; data?: T; error?: string; } export interface CanvasTextDetectItem { id: string; text: string; confidence?: number; } export interface CanvasTextEditPayloadItem { id: string; originalText: string; editedText?: string; action?: 'replace' | 'delete'; } // 画布服务 export const canvasService = { // 获取画布列表 async getProjects(): Promise> { try { const response = await fetch('/api/canvas'); const data = await response.json(); return data; } catch (error) { return { success: false, error: '获取画布列表失败' }; } }, // 获取单个画布 async getProject(id: string): Promise> { try { const response = await fetch(`/api/canvas/${id}`); const data = await response.json(); return data; } catch (error) { return { success: false, error: '获取画布失败' }; } }, // 创建画布 async createProject(project: Partial): Promise> { try { const response = await fetch('/api/canvas', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(project), }); const data = await response.json(); return data; } catch (error) { return { success: false, error: '创建画布失败' }; } }, // 更新画布 async updateProject(id: string, updates: Partial): Promise> { try { const response = await fetch(`/api/canvas/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(updates), }); const data = await response.json(); return data; } catch (error) { return { success: false, error: '更新画布失败' }; } }, // 删除画布 async deleteProject(id: string): Promise { try { const response = await fetch(`/api/canvas/${id}`, { method: 'DELETE', }); const data = await response.json(); return data; } catch (error) { return { success: false, error: '删除画布失败' }; } }, // 保存画布状态 async saveCanvasState(id: string, canvasData: CanvasState): Promise { try { const requestBody = JSON.stringify({ canvasData }); const doSave = async () => fetch(`/api/canvas/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: requestBody, }); let response = await doSave(); if (response.status === 429) { const retryPayload = await response.json().catch(() => ({})); const retryAfter = Number(retryPayload?.retryAfter || 0); const waitMs = retryAfter > 0 ? retryAfter * 1000 : 800; await new Promise((resolve) => setTimeout(resolve, waitMs)); response = await doSave(); } const data = await response.json().catch(() => ({})); if (!response.ok) { return { success: false, error: String(data?.error || data?.message || '保存画布状态失败') }; } return data as ApiResponse; } catch (error) { return { success: false, error: '保存画布状态失败' }; } }, // 自动保存(防抖) createAutoSave(projectId: string, delay = 2000) { let timeoutId: NodeJS.Timeout | null = null; return (canvasData: CanvasState) => { if (timeoutId) { clearTimeout(timeoutId); } timeoutId = setTimeout(async () => { await this.saveCanvasState(projectId, canvasData); }, delay); }; }, }; // 图片生成服务 export const imageGenerationService = { // 上传图片到存储桶 async uploadImage(file: File): Promise> { try { const formData = new FormData(); formData.append('file', file); const response = await fetch('/api/files/upload', { method: 'POST', body: formData, }); if (!response.ok) { const errorData = await response.json(); return { success: false, error: errorData.error || '上传失败' }; } const data = await response.json(); return { success: true, data: { url: data.url, pathname: data.pathname } }; } catch (error) { console.error('[Canvas] 图片上传失败:', error); return { success: false, error: '图片上传失败' }; } }, // AI 生成图片 async generateImage(params: { prompt: string; negativePrompt?: string; model?: string; aspectRatio?: string; imageCount?: number; referenceImage?: string; }): Promise; model?: string; prompt?: string }>> { try { const response = await fetch('/api/canvas/generate/image', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params), }); const data = await response.json(); return data; } catch (error) { return { success: false, error: '生成图片失败' }; } }, // 图片抠图 - 使用图片URL async removeBackground(imageUrl: string): Promise> { try { const response = await fetch('/api/rmbg', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ imageUrl }), // 使用 imageUrl 参数 }); const data = await response.json(); if (data.success && data.original_url) { return { success: true, data: { url: data.original_url } }; } return { success: false, error: data.error || '抠图失败' }; } catch (error) { console.error('[Canvas] 抠图失败:', error); return { success: false, error: '抠图失败' }; } }, // 去水印 - 使用图片URL async removeWatermark(imageUrl: string): Promise> { try { const response = await fetch('/api/watermark-remove', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ image_url: imageUrl }), }); const data = await response.json(); if (data.success && data.original_url) { return { success: true, data: { url: data.original_url } }; } return { success: false, error: data.error || '去水印失败' }; } catch (error) { console.error('[Canvas] 去水印失败:', error); return { success: false, error: '去水印失败' }; } }, // 图片增强 - 使用图片URL async enhanceImage(imageUrl: string): Promise> { try { const response = await fetch('/api/enhance', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ imageUrl }), // 使用 imageUrl 参数 }); const data = await response.json(); if (data.success && data.original_url) { return { success: true, data: { url: data.original_url } }; } return { success: false, error: data.error || '图片增强失败' }; } catch (error) { console.error('[Canvas] 图片增强失败:', error); return { success: false, error: '图片增强失败' }; } }, // 图片扩展 - 使用图片URL async extendImage(imageUrl: string, direction?: string): Promise> { try { const response = await fetch('/api/extend', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ image_url: imageUrl, direction }), // extend API 使用 image_url 参数名 }); const data = await response.json(); if (data.success && data.original_url) { return { success: true, data: { url: data.original_url } }; } return { success: false, error: data.error || '图片扩展失败' }; } catch (error) { console.error('[Canvas] 图片扩展失败:', error); return { success: false, error: '图片扩展失败' }; } }, // 尺寸调整 - 通过 URL 下载图片,调整大小后上传到 S3 async resizeImage(imageUrl: string, width: number, height: number): Promise> { try { // 1. 下载原图 const response = await fetch(imageUrl); if (!response.ok) { throw new Error('下载图片失败'); } const blob = await response.blob(); // 2. 使用 canvas 调整尺寸 const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); if (!ctx) { throw new Error('无法创建 canvas context'); } const img = new Image(); img.crossOrigin = 'anonymous'; await new Promise((resolve, reject) => { img.onload = () => resolve(); img.onerror = () => reject(new Error('图片加载失败')); img.src = URL.createObjectURL(blob); }); canvas.width = width; canvas.height = height; ctx.drawImage(img, 0, 0, width, height); // 3. 转换为 base64 const base64 = canvas.toDataURL('image/png').split(',')[1]; // 4. 上传到 S3 const uploadResponse = await fetch('/api/resize', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ image_base64: base64, canvasWidth: width, canvasHeight: height, prompt: '尺寸调整', }), }); const data = await uploadResponse.json(); if (data.success && data.original_url) { return { success: true, data: { url: data.original_url } }; } return { success: false, error: data.error || '尺寸调整失败' }; } catch (error) { console.error('[Canvas] 尺寸调整失败:', error); return { success: false, error: '尺寸调整失败' }; } }, // 角度编辑 async editAngle(params: { imageUrl: string; horizontalAngle: number; verticalAngle: number; zoom: number; }): Promise> { try { const response = await fetch('/api/angle-edit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params), }); const data = await response.json(); return data; } catch (error) { return { success: false, error: '角度编辑失败' }; } }, // 场景裂变 async sceneFusion(params: { productImage: string; backgroundImages: string[]; productName?: string; }): Promise> { try { const response = await fetch('/api/scene-fusion', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params), }); const data = await response.json(); return data; } catch (error) { return { success: false, error: '场景裂变失败' }; } }, // 识别图片中的文字(OCR) async detectCanvasText(imageUrl: string): Promise> { try { const response = await fetch('/api/canvas/text-detect', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ imageUrl }), }); const data = await response.json(); return data; } catch (error) { console.error('[Canvas] 文字识别失败:', error); return { success: false, error: '文字识别失败' }; } }, // 应用文字替换并生成新图 async editCanvasText(params: { imageUrl: string; items: CanvasTextEditPayloadItem[]; }): Promise> { try { const response = await fetch('/api/canvas/text-edit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params), }); const data = await response.json(); return data; } catch (error) { console.error('[Canvas] 文字替换失败:', error); return { success: false, error: '文字替换失败' }; } }, }; // 视频生成服务 export const videoGenerationService = { // 生成视频 async generateVideo(params: { prompt: string; model: string; referenceImage?: string; duration?: number; }): Promise> { try { const response = await fetch('/api/canvas/generate/video', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params), }); const data = await response.json(); return data; } catch (error) { return { success: false, error: '生成视频失败' }; } }, }; export type Model3DTaskStatus = | 'queued' | 'running' | 'success' | 'failed' | 'banned' | 'expired' | 'cancelled' | 'unknown'; export const model3DGenerationService = { async uploadImage(file: File): Promise }>> { try { const formData = new FormData(); formData.append('file', file); const response = await fetch('/api/canvas/3d/upload-image', { method: 'POST', body: formData, }); const data = await response.json(); return data; } catch (error) { return { success: false, error: '上传参考图失败' }; } }, async createTask(params: Record): Promise> { try { const response = await fetch('/api/canvas/3d/tasks', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params), }); const data = await response.json(); return data; } catch (error) { return { success: false, error: '创建 3D 任务失败' }; } }, async getTask(taskId: string): Promise; modelUrl?: string | null; previewImageUrl?: string | null; errorCode?: number | null; errorMessage?: string | null; }>> { try { const response = await fetch(`/api/canvas/3d/tasks/${taskId}`); const data = await response.json(); return data; } catch (error) { return { success: false, error: '查询 3D 任务失败' }; } }, async getBalance(): Promise>> { try { const response = await fetch('/api/canvas/3d/balance'); const data = await response.json(); return data; } catch (error) { return { success: false, error: '查询余额失败' }; } }, }; export default { canvas: canvasService, image: imageGenerationService, video: videoGenerationService, model3d: model3DGenerationService, };