-
-
setEnhanceConfig({ ...enhanceConfig, apiUrl: e.target.value })}
- placeholder="https://techsz.aoscdn.com"
+ {/* API切换开关 */}
+
+
+
+
+ 启用后将使用Real-ESRGAN本地模型进行图片增强,效果更好
+
+
+
setEnhanceConfig({ ...enhanceConfig, useBackupApi: checked })}
/>
-
- 请输入完整的API地址,例如: https://techsz.aoscdn.com
-
-
-
-
-
setEnhanceConfig({ ...enhanceConfig, apiKey: e.target.value })}
- placeholder="请输入API密钥"
- />
-
- API密钥是必需的,请从服务提供商获取
-
-
-
-
-
-
- 选择图片类型:通用或人像(人像模式最多同时处理10个人)
-
-
-
-
-
-
- 选择放大倍数:自动(根据图片尺寸智能选择)、不放大、2倍或4倍
-
-
-
-
API文档说明
-
-
• API地址应指向服务根地址,例如: https://techsz.aoscdn.com
-
• 系统会自动调用 /api/tasks/visual/scale 接口进行变清晰处理
-
• 支持的图片格式:JPG, JPEG, PNG, BMP, WEBP, TIFF等
-
• 图片大小:不超过20MB,分辨率最大4096x4096
-
• 返回的链接有效期为1小时,系统会自动下载并存储到S3
-
+
+ {/* 主API配置 */}
+ {!enhanceConfig.useBackupApi && (
+ <>
+
+
主API配置 (第三方云服务)
+
+
+
setEnhanceConfig({ ...enhanceConfig, apiUrl: e.target.value })}
+ placeholder="https://techsz.aoscdn.com"
+ />
+
+ 请输入完整的API地址,例如: https://techsz.aoscdn.com
+
+
+
+
+
setEnhanceConfig({ ...enhanceConfig, apiKey: e.target.value })}
+ placeholder="请输入API密钥"
+ />
+
+ API密钥是必需的,请从服务提供商获取
+
+
+
+
+
+
+ 选择图片类型:通用或人像(人像模式最多同时处理10个人)
+
+
+
+
+
+
+ 选择放大倍数:自动(根据图片尺寸智能选择)、不放大、2倍或4倍
+
+
+
+
主API文档说明
+
+
• API地址应指向服务根地址,例如: https://techsz.aoscdn.com
+
• 系统会自动调用 /api/tasks/visual/scale 接口进行变清晰处理
+
• 支持的图片格式:JPG, JPEG, PNG, BMP, WEBP, TIFF等
+
• 图片大小:不超过20MB,分辨率最大4096x4096
+
• 返回的链接有效期为1小时,系统会自动下载并存储到S3
+
+
+ >
+ )}
+
+ {/* 备用API配置 (Real-ESRGAN) */}
+ {enhanceConfig.useBackupApi && (
+ <>
+
+
备用API配置 (Real-ESRGAN 本地模型)
+
+
+
setEnhanceConfig({ ...enhanceConfig, backupApiUrl: e.target.value })}
+ placeholder="http://156.225.27.52:5233"
+ />
+
+ Real-ESRGAN API服务地址,默认: http://156.225.27.52:5233
+
+
+
+
+
setEnhanceConfig({ ...enhanceConfig, backupApiKey: e.target.value })}
+ placeholder="请输入Real-ESRGAN API密钥"
+ />
+
+ API密钥用于认证,请从管理员处获取
+
+
+
+
+
+
+
+ 推荐使用4倍放大,效果最佳
+
+
+
+
+
+
+ 不同模型适用于不同场景
+
+
+
+
+
Real-ESRGAN API说明
+
+
• 基于Real-ESRGAN深度学习模型,图像超分辨率效果更好
+
• 使用URL方式上传图片,处理后自动保存到S3存储
+
• 支持2x、4x、8x放大倍数
+
• 处理时间:通常1-10秒,取决于图片大小
+
• 支持格式:JPG, PNG, JPEG等常见图片格式
+
• 文件限制:最大50MB
+
+
+ >
+ )}
+
diff --git a/app/api/enhance/route.ts b/app/api/enhance/route.ts
index cda828a..1492b5d 100644
--- a/app/api/enhance/route.ts
+++ b/app/api/enhance/route.ts
@@ -5,6 +5,20 @@ import { uploadFile } from "@/lib/storage/service";
import { db } from "@/lib/db";
import { generatedImage } from "@/lib/db/schema";
+// 变清晰API配置类型
+type EnhanceApiConfig = {
+ apiUrl?: string;
+ apiKey?: string;
+ type?: string; // "clean" | "face"
+ scaleFactor?: number | string; // 1 | 2 | 4 | "auto"
+ // 备用API配置 (Real-ESRGAN)
+ useBackupApi?: boolean;
+ backupApiUrl?: string;
+ backupApiKey?: string;
+ backupScale?: string; // "2" | "4" | "8"
+ backupModel?: string;
+};
+
/**
* 压缩图片生成缩略图(使用 sharp)
*/
@@ -84,6 +98,150 @@ async function uploadBase64ToS3(base64Data: string, mimeType: string = "image/jp
// 设置API路由最大执行时间为3分钟(180秒)
export const maxDuration = 180;
+/**
+ * 使用Real-ESRGAN备用API处理图片(通过URL方式)
+ * @param imageUrl 图片URL(需要公开可访问)
+ * @param config 备用API配置
+ * @returns 处理后的图片Base64和S3 URL
+ */
+async function processWithRealESRGAN(
+ imageUrl: string,
+ config: {
+ backupApiUrl: string;
+ backupApiKey: string;
+ backupScale: string;
+ backupModel: string;
+ }
+): Promise<{ imageBase64: string; imageUrl: string; processingTime: number }> {
+ const startTime = Date.now();
+ const apiUrl = config.backupApiUrl.endsWith("/")
+ ? config.backupApiUrl.slice(0, -1)
+ : config.backupApiUrl;
+
+ const upscaleUrl = `${apiUrl}/upscale/url`;
+ console.log(`[Enhance-RealESRGAN] 调用URL方式API: ${upscaleUrl}`);
+ console.log(`[Enhance-RealESRGAN] 图片URL: ${imageUrl}`);
+ console.log(`[Enhance-RealESRGAN] 放大倍数: ${config.backupScale}x, 模型: ${config.backupModel}`);
+
+ const response = await fetch(upscaleUrl, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "X-API-Key": config.backupApiKey,
+ },
+ body: JSON.stringify({
+ image_url: imageUrl,
+ scale: Number.parseInt(config.backupScale) || 4,
+ model_name: config.backupModel || "RealESRGAN_x4plus",
+ }),
+ });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+ console.error(`[Enhance-RealESRGAN] API请求失败: ${response.status} ${response.statusText}`);
+ console.error(`[Enhance-RealESRGAN] 错误详情: ${errorText}`);
+ throw new Error(`Real-ESRGAN API请求失败: ${response.status} - ${errorText || response.statusText}`);
+ }
+
+ const result = await response.json();
+ console.log(`[Enhance-RealESRGAN] API响应:`, {
+ success: result.success,
+ hasImageUrl: !!result.image_url,
+ processingTime: result.processing_time,
+ totalTime: result.total_time,
+ });
+
+ if (!result.success || !result.image_url) {
+ throw new Error(`Real-ESRGAN处理失败: ${JSON.stringify(result)}`);
+ }
+
+ // Real-ESRGAN API直接返回S3 URL,我们需要下载图片并转换为Base64
+ console.log(`[Enhance-RealESRGAN] 下载处理后的图片: ${result.image_url}`);
+ const imageResponse = await fetch(result.image_url);
+ if (!imageResponse.ok) {
+ throw new Error(`无法下载Real-ESRGAN处理后的图片: ${imageResponse.status}`);
+ }
+
+ const imageBuffer = await imageResponse.arrayBuffer();
+ const imageBase64 = Buffer.from(imageBuffer).toString("base64");
+
+ const processingTime = (Date.now() - startTime) / 1000;
+ console.log(`[Enhance-RealESRGAN] ✅ 处理完成,总耗时: ${processingTime.toFixed(2)}秒`);
+ console.log(`[Enhance-RealESRGAN] ✅ 处理后图片大小: ${imageBuffer.byteLength} bytes`);
+
+ return {
+ imageBase64,
+ imageUrl: result.image_url,
+ processingTime,
+ };
+}
+
+/**
+ * 使用Real-ESRGAN备用API处理图片(通过Base64方式,用于没有公开URL的图片)
+ * @param imageBase64 图片Base64数据
+ * @param config 备用API配置
+ * @returns 处理后的图片Base64
+ */
+async function processWithRealESRGANBase64(
+ imageBase64: string,
+ config: {
+ backupApiUrl: string;
+ backupApiKey: string;
+ backupScale: string;
+ backupModel: string;
+ }
+): Promise<{ imageBase64: string; processingTime: number }> {
+ const startTime = Date.now();
+ const apiUrl = config.backupApiUrl.endsWith("/")
+ ? config.backupApiUrl.slice(0, -1)
+ : config.backupApiUrl;
+
+ const upscaleUrl = `${apiUrl}/upscale/base64`;
+ console.log(`[Enhance-RealESRGAN] 调用Base64方式API: ${upscaleUrl}`);
+ console.log(`[Enhance-RealESRGAN] 放大倍数: ${config.backupScale}x, 模型: ${config.backupModel}`);
+ console.log(`[Enhance-RealESRGAN] 输入图片Base64长度: ${imageBase64.length}`);
+
+ const response = await fetch(upscaleUrl, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "X-API-Key": config.backupApiKey,
+ },
+ body: JSON.stringify({
+ image_base64: imageBase64,
+ scale: Number.parseInt(config.backupScale) || 4,
+ model_name: config.backupModel || "RealESRGAN_x4plus",
+ }),
+ });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+ console.error(`[Enhance-RealESRGAN] API请求失败: ${response.status} ${response.statusText}`);
+ console.error(`[Enhance-RealESRGAN] 错误详情: ${errorText}`);
+ throw new Error(`Real-ESRGAN API请求失败: ${response.status} - ${errorText || response.statusText}`);
+ }
+
+ const result = await response.json();
+ console.log(`[Enhance-RealESRGAN] API响应:`, {
+ success: result.success,
+ hasImageBase64: !!result.image_base64,
+ processingTime: result.processing_time,
+ });
+
+ if (!result.success || !result.image_base64) {
+ throw new Error(`Real-ESRGAN处理失败: ${JSON.stringify(result)}`);
+ }
+
+ const processingTime = (Date.now() - startTime) / 1000;
+ console.log(`[Enhance-RealESRGAN] ✅ 处理完成,总耗时: ${processingTime.toFixed(2)}秒`);
+ console.log(`[Enhance-RealESRGAN] ✅ 处理后图片Base64长度: ${result.image_base64.length}`);
+
+ return {
+ imageBase64: result.image_base64,
+ processingTime,
+ };
+}
+
/**
* 轮询获取任务结果(根据官方示例)
*/
@@ -184,18 +342,28 @@ export async function POST(request: NextRequest) {
);
}
- const config = enhanceConfig.value as {
- apiUrl?: string;
- apiKey?: string;
- type?: string; // "clean" | "face"
- scaleFactor?: number | string; // 1 | 2 | 4 | "auto"
- };
+ const config = enhanceConfig.value as EnhanceApiConfig;
- if (!config.apiUrl || !config.apiKey) {
- return NextResponse.json(
- { error: "变清晰API地址或密钥未配置" },
- { status: 400 }
- );
+ // 检查是否使用备用API
+ const useBackupApi = config.useBackupApi === true;
+ console.log(`[Enhance API] 使用${useBackupApi ? "备用API (Real-ESRGAN)" : "主API"}`);
+
+ if (useBackupApi) {
+ // 验证备用API配置
+ if (!config.backupApiUrl || !config.backupApiKey) {
+ return NextResponse.json(
+ { error: "备用变清晰API地址或密钥未配置" },
+ { status: 400 }
+ );
+ }
+ } else {
+ // 验证主API配置
+ if (!config.apiUrl || !config.apiKey) {
+ return NextResponse.json(
+ { error: "变清晰API地址或密钥未配置" },
+ { status: 400 }
+ );
+ }
}
// 2. 获取请求体(Base64图片或FormData)
@@ -250,11 +418,86 @@ export async function POST(request: NextRequest) {
);
}
+ // ========== 备用API处理路径 (Real-ESRGAN) ==========
+ if (useBackupApi) {
+ console.log("[Enhance API] 使用Real-ESRGAN备用API处理...");
+
+ try {
+ // 使用Base64方式调用Real-ESRGAN API
+ const result = await processWithRealESRGANBase64(imageBase64, {
+ backupApiUrl: config.backupApiUrl!,
+ backupApiKey: config.backupApiKey!,
+ backupScale: config.backupScale || "4",
+ backupModel: config.backupModel || "RealESRGAN_x4plus",
+ });
+
+ // 上传处理后的图片到S3
+ let thumbnailUrl: string;
+ let originalUrl: string;
+
+ try {
+ console.log(`[Enhance-RealESRGAN] 📤 上传处理后的图片到S3...`);
+ const uploadResult = await uploadBase64ToS3(result.imageBase64, "image/png");
+ thumbnailUrl = uploadResult.thumbnail;
+ originalUrl = uploadResult.original;
+ console.log(`[Enhance-RealESRGAN] ✅ 上传成功: ${originalUrl}`);
+ } catch (uploadError) {
+ console.error("[Enhance-RealESRGAN] ❌ 上传到S3失败:", uploadError);
+ return NextResponse.json(
+ {
+ error: "图片上传到存储桶失败",
+ detail: uploadError instanceof Error ? uploadError.message : "未知错误"
+ },
+ { status: 500 }
+ );
+ }
+
+ // 保存到数据库
+ try {
+ const [savedImage] = await db.insert(generatedImage).values({
+ userId,
+ chatId: chatId || null,
+ messageId: messageId || null,
+ thumbnailUrl,
+ originalUrl,
+ imageSize: `${config.backupScale}x放大`,
+ prompt: prompt || "Real-ESRGAN图片变清晰处理",
+ modelId: `realesrgan-${config.backupModel}`,
+ }).returning();
+ console.log(`[Enhance-RealESRGAN] ✅ 保存到数据库成功,ID: ${savedImage.id}`);
+ } catch (dbError) {
+ console.error("[Enhance-RealESRGAN] ⚠️ 保存到数据库失败:", dbError);
+ // 继续返回成功,图片已处理并上传
+ }
+
+ // 返回结果
+ return NextResponse.json({
+ success: true,
+ image_base64: result.imageBase64,
+ thumbnail_url: thumbnailUrl,
+ original_url: originalUrl,
+ processing_time: result.processingTime,
+ api_type: "realesrgan",
+ });
+
+ } catch (error) {
+ console.error("[Enhance-RealESRGAN] ❌ 处理失败:", error);
+ return NextResponse.json(
+ {
+ error: "Real-ESRGAN变清晰处理失败",
+ detail: error instanceof Error ? error.message : "未知错误",
+ },
+ { status: 500 }
+ );
+ }
+ }
+
+ // ========== 主API处理路径 ==========
// 3. 调用变清晰API(使用异步模式,根据官方示例)
- console.log("[Enhance API] 开始准备API调用...");
- const apiUrl = config.apiUrl.endsWith("/")
- ? config.apiUrl.slice(0, -1)
- : config.apiUrl;
+ console.log("[Enhance API] 开始准备主API调用...");
+ const apiUrl = config.apiUrl!.endsWith("/")
+ ? config.apiUrl!.slice(0, -1)
+ : config.apiUrl!;
const enhanceUrl = `${apiUrl}/api/tasks/visual/scale`;
console.log("[Enhance API] API URL:", enhanceUrl);
@@ -283,7 +526,7 @@ export async function POST(request: NextRequest) {
formData.append("return_type", "2"); // 返回base64
const headers: Record
= {
- "X-API-KEY": config.apiKey,
+ "X-API-KEY": config.apiKey!,
...formData.getHeaders(), // 包含Content-Type和boundary
};
@@ -418,7 +661,7 @@ export async function POST(request: NextRequest) {
// 4. 轮询获取任务结果(根据官方示例)
console.log(`[Enhance] 开始轮询任务结果,task_id: ${taskId}`);
- const taskResult = await pollTaskResult(apiUrl, config.apiKey, taskId);
+ const taskResult = await pollTaskResult(apiUrl, config.apiKey!, taskId);
const finalProcessingTime = (Date.now() - startTime) / 1000;
diff --git a/scripts/fix-high-cpu.sh b/scripts/fix-high-cpu.sh
index 42cd9fe..e6fdd78 100755
--- a/scripts/fix-high-cpu.sh
+++ b/scripts/fix-high-cpu.sh
@@ -84,3 +84,5 @@ echo ""
+
+
diff --git a/系统性能诊断与解决方案.md b/系统性能诊断与解决方案.md
index a383c0b..7c3fd7a 100644
--- a/系统性能诊断与解决方案.md
+++ b/系统性能诊断与解决方案.md
@@ -137,3 +137,5 @@ pmset -g
+
+