| | import axios, { AxiosInstance, AxiosRequestConfig } from 'axios' |
| | import { getSession } from 'next-auth/react' |
| |
|
| | class APIClient { |
| | private client: AxiosInstance |
| | private baseURL: string |
| |
|
| | constructor() { |
| | this.baseURL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000' |
| | |
| | this.client = axios.create({ |
| | baseURL: this.baseURL, |
| | timeout: 30000, |
| | headers: { |
| | 'Content-Type': 'application/json', |
| | }, |
| | }) |
| |
|
| | |
| | this.client.interceptors.request.use( |
| | async (config) => { |
| | const session = await getSession() |
| | if (session?.accessToken) { |
| | config.headers.Authorization = `Bearer ${session.accessToken}` |
| | } |
| | return config |
| | }, |
| | (error) => Promise.reject(error) |
| | ) |
| |
|
| | |
| | this.client.interceptors.response.use( |
| | (response) => response, |
| | async (error) => { |
| | if (error.response?.status === 401) { |
| | |
| | window.location.href = '/login' |
| | } |
| | return Promise.reject(error) |
| | } |
| | ) |
| | } |
| |
|
| | |
| | async request<T>(config: AxiosRequestConfig): Promise<T> { |
| | const response = await this.client.request<T>(config) |
| | return response.data |
| | } |
| |
|
| | |
| | async get<T>(url: string, config?: AxiosRequestConfig): Promise<T> { |
| | return this.request<T>({ ...config, method: 'GET', url }) |
| | } |
| |
|
| | async post<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> { |
| | return this.request<T>({ ...config, method: 'POST', url, data }) |
| | } |
| |
|
| | async put<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> { |
| | return this.request<T>({ ...config, method: 'PUT', url, data }) |
| | } |
| |
|
| | async delete<T>(url: string, config?: AxiosRequestConfig): Promise<T> { |
| | return this.request<T>({ ...config, method: 'DELETE', url }) |
| | } |
| |
|
| | |
| | async upload<T>( |
| | url: string, |
| | file: File, |
| | onProgress?: (progress: number) => void |
| | ): Promise<T> { |
| | const formData = new FormData() |
| | formData.append('file', file) |
| |
|
| | return this.request<T>({ |
| | method: 'POST', |
| | url, |
| | data: formData, |
| | headers: { |
| | 'Content-Type': 'multipart/form-data', |
| | }, |
| | onUploadProgress: (progressEvent) => { |
| | if (onProgress && progressEvent.total) { |
| | const progress = Math.round( |
| | (progressEvent.loaded * 100) / progressEvent.total |
| | ) |
| | onProgress(progress) |
| | } |
| | }, |
| | }) |
| | } |
| |
|
| | |
| | createWebSocket(path: string): WebSocket { |
| | const wsURL = this.baseURL.replace(/^http/, 'ws') |
| | return new WebSocket(`${wsURL}${path}`) |
| | } |
| | } |
| |
|
| | |
| | export const apiClient = new APIClient() |
| |
|
| | |
| | export const api = { |
| | |
| | auth: { |
| | login: (credentials: { email: string; password: string }) => |
| | apiClient.post<{ token: string; user: any }>('/auth/login', credentials), |
| | |
| | register: (data: { email: string; password: string; name: string }) => |
| | apiClient.post<{ token: string; user: any }>('/auth/register', data), |
| | |
| | logout: () => apiClient.post('/auth/logout'), |
| | |
| | refreshToken: () => |
| | apiClient.post<{ token: string }>('/auth/refresh'), |
| | }, |
| |
|
| | |
| | processing: { |
| | removeBackground: (file: File, options?: any, onProgress?: (p: number) => void) => |
| | apiClient.upload<{ id: string; result: string }>('/process/remove-background', file, onProgress), |
| | |
| | replaceBackground: (imageId: string, backgroundId: string) => |
| | apiClient.post<{ result: string }>('/process/replace-background', { |
| | imageId, |
| | backgroundId, |
| | }), |
| | |
| | batchProcess: (files: File[], options?: any) => { |
| | const formData = new FormData() |
| | files.forEach((file) => formData.append('files', file)) |
| | if (options) { |
| | formData.append('options', JSON.stringify(options)) |
| | } |
| | return apiClient.post<{ jobId: string }>('/process/batch', formData, { |
| | headers: { 'Content-Type': 'multipart/form-data' }, |
| | }) |
| | }, |
| | |
| | getJobStatus: (jobId: string) => |
| | apiClient.get<{ status: string; progress: number; results?: any[] }>( |
| | `/process/jobs/${jobId}` |
| | ), |
| | }, |
| |
|
| | |
| | projects: { |
| | list: (params?: { page?: number; limit?: number; search?: string }) => |
| | apiClient.get<{ items: any[]; total: number }>('/projects', { params }), |
| | |
| | get: (id: string) => |
| | apiClient.get<any>(`/projects/${id}`), |
| | |
| | create: (data: any) => |
| | apiClient.post<any>('/projects', data), |
| | |
| | update: (id: string, data: any) => |
| | apiClient.put<any>(`/projects/${id}`, data), |
| | |
| | delete: (id: string) => |
| | apiClient.delete(`/projects/${id}`), |
| | }, |
| |
|
| | |
| | backgrounds: { |
| | list: (category?: string) => |
| | apiClient.get<any[]>('/backgrounds', { params: { category } }), |
| | |
| | upload: (file: File) => |
| | apiClient.upload<{ id: string; url: string }>('/backgrounds/upload', file), |
| | |
| | generate: (prompt: string) => |
| | apiClient.post<{ id: string; url: string }>('/backgrounds/generate', { prompt }), |
| | }, |
| |
|
| | |
| | user: { |
| | profile: () => |
| | apiClient.get<any>('/user/profile'), |
| | |
| | updateProfile: (data: any) => |
| | apiClient.put<any>('/user/profile', data), |
| | |
| | usage: () => |
| | apiClient.get<{ images: number; videos: number; storage: number }>( |
| | '/user/usage' |
| | ), |
| | |
| | billing: () => |
| | apiClient.get<any>('/user/billing'), |
| | }, |
| | } |
| |
|
| | export default api |