feat: 实现 Mini Game AI 工具平台
基于 Next.js 15、React 19 和 TypeScript 构建面向小游戏开发者的 AI 赋能工具平台。 主要功能: - 首页:包含 Hero、功能展示、优势介绍、定价和 CTA 区域 - 三大核心工具:视频转序列帧、图片压缩、音频压缩 - 响应式布局:包含顶部导航、页脚和侧边栏 - 文件上传:支持拖拽上传,使用 react-dropzone - 进度追踪:实时显示上传和处理进度 - 可配置工具:每个工具都支持自定义参数配置 - 结果预览:支持下载处理后的文件 - 4K 优化:针对大屏幕优化的响应式设计 - API 路由:文件上传和处理的模拟实现 技术栈: - Next.js 15 (App Router) - React 19 - TypeScript (严格模式) - Tailwind CSS(自定义 4K 断点) - shadcn/ui 组件库 - Framer Motion 动画 - Zustand 状态管理 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
122
src/lib/api.ts
Normal file
122
src/lib/api.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import { type ApiResponse, type UploadResponse } from "@/types";
|
||||
|
||||
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "";
|
||||
|
||||
/**
|
||||
* Base API client with error handling
|
||||
*/
|
||||
async function apiClient<T>(
|
||||
endpoint: string,
|
||||
options?: RequestInit
|
||||
): Promise<ApiResponse<T>> {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/api${endpoint}`, {
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options?.headers,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
return {
|
||||
success: false,
|
||||
error: data.message || "An error occurred",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Network error",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a file
|
||||
*/
|
||||
export async function uploadFile(file: File, _onProgress?: (progress: number) => Promise<void>): Promise<ApiResponse<UploadResponse>> {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/api/upload`, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Upload failed");
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
success: true,
|
||||
data,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Upload failed",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process video to frames
|
||||
*/
|
||||
export async function processVideoFrames(fileId: string, config: any) {
|
||||
return apiClient("/process/video-frames", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ fileId, config }),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Process image compression
|
||||
*/
|
||||
export async function processImageCompression(fileId: string, config: any) {
|
||||
return apiClient("/process/image-compress", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ fileId, config }),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Process audio compression
|
||||
*/
|
||||
export async function processAudioCompression(fileId: string, config: any) {
|
||||
return apiClient("/process/audio-compress", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ fileId, config }),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Download processed file
|
||||
*/
|
||||
export async function downloadFile(fileId: string): Promise<Blob> {
|
||||
const response = await fetch(`${API_BASE_URL}/api/download/${fileId}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Download failed");
|
||||
}
|
||||
|
||||
return response.blob();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check user quota
|
||||
*/
|
||||
export async function checkQuota() {
|
||||
return apiClient("/quota", {
|
||||
method: "GET",
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user