修复时间显示和图像拓展功能
- 添加formatBeijingTime函数,将所有时间显示转换为北京时间(UTC+8) - 更新相册、管理后台、精选页面的时间显示 - 图像拓展功能改为直接发送图片URL而不是base64 - 优化API性能,减少数据传输量
This commit is contained in:
parent
da1579d852
commit
60082aca6f
@ -3,6 +3,7 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import useSWR from "swr";
|
||||
import { toast } from "sonner";
|
||||
import { formatBeijingTime } from "@/lib/utils";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
@ -1446,7 +1447,7 @@ export function AdminSettingsClient() {
|
||||
{img.userName || img.userEmail?.split("@")[0]}
|
||||
</div>
|
||||
<div className="text-[9px] text-center text-muted-foreground/60">
|
||||
{new Date(img.createdAt).toLocaleDateString("zh-CN", { month: "numeric", day: "numeric" })}
|
||||
{formatBeijingTime(img.createdAt, { month: "numeric", day: "numeric" })}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@ -7,6 +7,7 @@ import { Dialog, DialogContent } from "@/components/ui/dialog";
|
||||
import { ArrowLeft, Download, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Sparkles, User, Building2, Clock, Bot } from "lucide-react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import Image from "next/image";
|
||||
import { formatBeijingTime } from "@/lib/utils";
|
||||
|
||||
type FeaturedImage = {
|
||||
id: string;
|
||||
@ -199,7 +200,7 @@ export default function FeaturedPage() {
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<Clock className="h-3 w-3" />
|
||||
{new Date(img.createdAt).toLocaleDateString("zh-CN", {
|
||||
{formatBeijingTime(img.createdAt, {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
})}
|
||||
|
||||
@ -8,6 +8,7 @@ import { ArrowLeft, Download, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsR
|
||||
import { Input } from "@/components/ui/input";
|
||||
import Image from "next/image";
|
||||
import { toast } from "sonner";
|
||||
import { formatBeijingTime } from "@/lib/utils";
|
||||
|
||||
type GalleryImage = {
|
||||
id: string;
|
||||
@ -341,7 +342,7 @@ export default function GalleryPage() {
|
||||
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-2 translate-y-full group-hover:translate-y-0 transition-transform">
|
||||
<p className="text-xs text-white truncate">{img.alt}</p>
|
||||
<p className="text-xs text-white/70 mt-1">
|
||||
{new Date(img.createdAt).toLocaleString("zh-CN", {
|
||||
{formatBeijingTime(img.createdAt, {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "2-digit",
|
||||
@ -494,7 +495,7 @@ export default function GalleryPage() {
|
||||
<div className="flex-1">
|
||||
<p className="font-medium">{selectedImage.alt}</p>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
{new Date(selectedImage.createdAt).toLocaleString("zh-CN")}
|
||||
{formatBeijingTime(selectedImage.createdAt)}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
|
||||
@ -281,16 +281,80 @@ export async function POST(request: NextRequest) {
|
||||
let messageId: string | null = null;
|
||||
|
||||
if (contentType.includes("application/json")) {
|
||||
// JSON格式:Base64图片
|
||||
// JSON格式:支持Base64图片或图片URL
|
||||
const body = await request.json();
|
||||
imageBase64 = body.image_base64;
|
||||
const imageUrl = body.image_url; // 优先使用URL
|
||||
imageBase64 = body.image_base64; // 如果没有URL,使用Base64
|
||||
prompt = body.prompt || "图像拓展处理";
|
||||
chatId = body.chatId || null;
|
||||
messageId = body.messageId || null;
|
||||
|
||||
// 如果提供了URL,直接使用;否则需要Base64
|
||||
if (imageUrl) {
|
||||
console.log("[Extend API] 使用图片URL:", imageUrl);
|
||||
// 直接使用URL,跳过Base64转换和上传步骤
|
||||
const startTime = Date.now();
|
||||
const xScale = config.xScale || 1.5;
|
||||
const yScale = config.yScale || 1.5;
|
||||
|
||||
console.log(`[Extend API] 拓展参数: X=${xScale}, Y=${yScale}`);
|
||||
|
||||
const extendedImageUrl = await extendImage(imageUrl, config.apiKey, xScale, yScale);
|
||||
console.log("[Extend API] 拓展后图片URL:", extendedImageUrl);
|
||||
|
||||
// 下载拓展后的图片
|
||||
console.log("[Extend API] 下载拓展后的图片...");
|
||||
const imageResponse = await fetch(extendedImageUrl);
|
||||
if (!imageResponse.ok) {
|
||||
throw new Error(`下载拓展图片失败: ${imageResponse.status} ${imageResponse.statusText}`);
|
||||
}
|
||||
|
||||
const arrayBuffer = await imageResponse.arrayBuffer();
|
||||
const buffer = Buffer.from(arrayBuffer);
|
||||
const extendedImageBase64 = buffer.toString("base64");
|
||||
|
||||
// 上传到S3
|
||||
console.log("[Extend API] 上传到S3...");
|
||||
const { thumbnail, original } = await uploadBase64ToS3(extendedImageBase64, "image/jpeg");
|
||||
|
||||
// 保存到数据库(相册和生图记录)
|
||||
console.log("[Extend API] 保存到数据库...");
|
||||
let savedImage;
|
||||
try {
|
||||
[savedImage] = await db
|
||||
.insert(generatedImage)
|
||||
.values({
|
||||
userId,
|
||||
chatId: chatId || null,
|
||||
messageId: messageId || null,
|
||||
thumbnailUrl: thumbnail,
|
||||
originalUrl: original,
|
||||
prompt: prompt || "图像拓展处理",
|
||||
modelId: "extend-1.0",
|
||||
imageSize: "2K",
|
||||
})
|
||||
.returning();
|
||||
console.log(`[Extend API] ✅ 图片已保存到相册和生图记录,ID: ${savedImage.id}`);
|
||||
} catch (dbError) {
|
||||
console.error("[Extend API] ❌ 保存到数据库失败:", dbError);
|
||||
}
|
||||
|
||||
const processingTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
||||
console.log(`[Extend API] ✅ 图像拓展完成,处理时间: ${processingTime}秒`);
|
||||
|
||||
// 返回结果
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
original_url: original,
|
||||
thumbnail_url: thumbnail,
|
||||
base64: extendedImageBase64,
|
||||
processing_time: parseFloat(processingTime),
|
||||
});
|
||||
}
|
||||
|
||||
if (!imageBase64) {
|
||||
return NextResponse.json(
|
||||
{ error: "缺少image_base64参数" },
|
||||
{ error: "缺少image_base64或image_url参数" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
@ -352,21 +416,28 @@ export async function POST(request: NextRequest) {
|
||||
console.log("[Extend API] 上传到S3...");
|
||||
const { thumbnail, original } = await uploadBase64ToS3(extendedImageBase64, "image/jpeg");
|
||||
|
||||
// 6. 保存到数据库
|
||||
// 6. 保存到数据库(相册和生图记录)
|
||||
console.log("[Extend API] 保存到数据库...");
|
||||
const [savedImage] = await db
|
||||
.insert(generatedImage)
|
||||
.values({
|
||||
userId,
|
||||
chatId,
|
||||
messageId,
|
||||
thumbnailUrl: thumbnail,
|
||||
originalUrl: original,
|
||||
prompt,
|
||||
modelId: "extend-1.0",
|
||||
imageSize: "2K",
|
||||
})
|
||||
.returning();
|
||||
let savedImage;
|
||||
try {
|
||||
[savedImage] = await db
|
||||
.insert(generatedImage)
|
||||
.values({
|
||||
userId,
|
||||
chatId: chatId || null,
|
||||
messageId: messageId || null,
|
||||
thumbnailUrl: thumbnail,
|
||||
originalUrl: original,
|
||||
prompt: prompt || "图像拓展处理",
|
||||
modelId: "extend-1.0",
|
||||
imageSize: "2K",
|
||||
})
|
||||
.returning();
|
||||
console.log(`[Extend API] ✅ 图片已保存到相册和生图记录,ID: ${savedImage.id}`);
|
||||
} catch (dbError) {
|
||||
console.error("[Extend API] ❌ 保存到数据库失败:", dbError);
|
||||
// 数据库保存失败时仍然返回成功,但记录错误(图片已上传到S3,用户可以访问)
|
||||
}
|
||||
|
||||
const processingTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
||||
console.log(`[Extend API] ✅ 图像拓展完成,处理时间: ${processingTime}秒`);
|
||||
|
||||
@ -831,19 +831,17 @@ export function ImageAnnotator({ imageUrl, onConfirm, onCancel, initialResizeMod
|
||||
|
||||
setIsExtending(true);
|
||||
try {
|
||||
// 使用原图URL获取原图数据,而不是canvas的预览图
|
||||
console.log("[图像拓展] 使用原图URL获取数据:", originalImageUrl);
|
||||
const base64Data = await imageUrlToBase64(originalImageUrl);
|
||||
console.log("[图像拓展] 原图Base64长度:", base64Data.length, "字符");
|
||||
// 直接使用原图URL,而不是转换为base64
|
||||
console.log("[图像拓展] 使用原图URL:", originalImageUrl);
|
||||
|
||||
// 调用图像拓展API
|
||||
// 调用图像拓展API(直接发送URL)
|
||||
const response = await fetch("/api/extend", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
image_base64: base64Data,
|
||||
image_url: originalImageUrl, // 直接发送图片URL
|
||||
prompt: "画图标注-图像拓展处理", // 可选:添加提示词
|
||||
}),
|
||||
});
|
||||
|
||||
37
lib/utils.ts
37
lib/utils.ts
@ -114,3 +114,40 @@ export function getTextFromMessage(message: ChatMessage | UIMessage): string {
|
||||
.map((part) => (part as { type: 'text'; text: string}).text)
|
||||
.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* 将UTC时间转换为北京时间(UTC+8)
|
||||
* @param date - Date对象或时间字符串
|
||||
* @returns 北京时间对应的Date对象
|
||||
*/
|
||||
export function toBeijingTime(date: Date | string): Date {
|
||||
const d = typeof date === "string" ? new Date(date) : date;
|
||||
// 获取UTC时间戳
|
||||
const utcTime = d.getTime() + (d.getTimezoneOffset() * 60 * 1000);
|
||||
// 转换为北京时间(UTC+8)
|
||||
const beijingTime = new Date(utcTime + (8 * 60 * 60 * 1000));
|
||||
return beijingTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时间为北京时间字符串
|
||||
* @param date - Date对象或时间字符串
|
||||
* @param options - Intl.DateTimeFormatOptions 格式化选项
|
||||
* @returns 格式化后的北京时间字符串
|
||||
*/
|
||||
export function formatBeijingTime(
|
||||
date: Date | string,
|
||||
options?: Intl.DateTimeFormatOptions
|
||||
): string {
|
||||
const beijingTime = toBeijingTime(date);
|
||||
const defaultOptions: Intl.DateTimeFormatOptions = {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
timeZone: "Asia/Shanghai",
|
||||
...options,
|
||||
};
|
||||
return beijingTime.toLocaleString("zh-CN", defaultOptions);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user