0.1.13 AI功能大改

This commit is contained in:
liaibo
2026-01-10 23:08:56 +08:00
parent 63050f3927
commit be71849aa5
37 changed files with 6400 additions and 160 deletions
@@ -7,10 +7,11 @@ export const dynamic = "force-dynamic";
export async function GET(request: Request) {
const supabase = await createSupabaseRouteClient();
const {
data: { session },
} = await supabase.auth.getSession();
data: { user },
error: authError,
} = await supabase.auth.getUser();
if (!session) {
if (authError || !user) {
return NextResponse.json({ error: "未登录" }, { status: 401 });
}
@@ -47,10 +48,11 @@ export async function GET(request: Request) {
export async function POST(request: Request) {
const supabase = await createSupabaseRouteClient();
const {
data: { session },
} = await supabase.auth.getSession();
data: { user },
error: authError,
} = await supabase.auth.getUser();
if (!session) {
if (authError || !user) {
return NextResponse.json({ error: "未登录" }, { status: 401 });
}
@@ -80,7 +82,7 @@ export async function POST(request: Request) {
file_name: payload.fileName,
file_size: payload.fileSize ?? null,
mime_type: payload.mimeType ?? null,
created_by: session.user.id,
created_by: user.id,
})
.select("*")
.single();
@@ -27,7 +27,7 @@ export async function POST(request: Request) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL;
const backendUrl = process.env.BACKEND_URL ?? process.env.NEXT_PUBLIC_BACKEND_URL;
if (backendUrl) {
void fetch(`${backendUrl}/api/v1/tasks/media-ocr`, {
method: "POST",
@@ -0,0 +1,78 @@
import { NextResponse } from "next/server";
import { createSupabaseRouteClient } from "@/lib/supabase/server";
export const dynamic = "force-dynamic";
export async function GET(request: Request) {
const supabase = await createSupabaseRouteClient();
const {
data: { user },
error: authError,
} = await supabase.auth.getUser();
if (authError || !user) {
return NextResponse.json({ error: "未登录" }, { status: 401 });
}
const { searchParams } = new URL(request.url);
const assetId = searchParams.get("assetId");
if (!assetId) {
return NextResponse.json({ error: "缺少 assetId" }, { status: 400 });
}
// 获取资源信息
const { data: asset, error: assetError } = await supabase
.from("media_assets")
.select("*")
.eq("id", assetId)
.single();
if (assetError || !asset) {
return NextResponse.json({ error: "资源不存在" }, { status: 404 });
}
// 对于图片,添加高质量参数以获得更好的显示效果
// Supabase Storage 支持通过 URL 参数控制图片质量和尺寸
const isImage = asset.mime_type?.startsWith("image/");
let signedUrl: string;
if (isImage) {
// 使用 createSignedUrl 并添加高质量参数
// 注意:transform 参数需要在签名时指定
const { data: signedUrlData, error: signError } = await supabase.storage
.from(asset.bucket)
.createSignedUrl(asset.storage_path, 60 * 60, {
// 添加转换参数以获得高质量图片
transform: {
quality: 95, // 高质量
format: "origin", // 保持原始格式
},
});
if (signError || !signedUrlData) {
return NextResponse.json({ error: "生成签名 URL 失败" }, { status: 500 });
}
signedUrl = signedUrlData.signedUrl;
} else {
// 非图片文件,直接生成签名 URL
const { data: signedUrlData, error: signError } = await supabase.storage
.from(asset.bucket)
.createSignedUrl(asset.storage_path, 60 * 60);
if (signError || !signedUrlData) {
return NextResponse.json({ error: "生成签名 URL 失败" }, { status: 500 });
}
signedUrl = signedUrlData.signedUrl;
}
return NextResponse.json({
signedUrl,
asset: {
id: asset.id,
file_name: asset.file_name,
mime_type: asset.mime_type,
file_size: asset.file_size,
},
});
}
@@ -51,8 +51,20 @@ export async function POST(request: Request) {
}
// 为私有桶生成临时访问链接(7 天);前端可在需要时通过 /api/media/signed-url 刷新
const { data: signed } = await supabase.storage.from(DOC_BUCKET).createSignedUrl(path, 60 * 60 * 24 * 7);
const signedUrl = signed?.signedUrl ?? "";
// 对于图片,使用高质量参数以获得更好的显示效果
let signedUrl = "";
if (assetType === "image") {
const { data: signed } = await supabase.storage.from(DOC_BUCKET).createSignedUrl(path, 60 * 60 * 24 * 7, {
transform: {
quality: 95, // 高质量
format: "origin", // 保持原始格式
},
});
signedUrl = signed?.signedUrl ?? "";
} else {
const { data: signed } = await supabase.storage.from(DOC_BUCKET).createSignedUrl(path, 60 * 60 * 24 * 7);
signedUrl = signed?.signedUrl ?? "";
}
const { data: asset, error } = await supabase
.from("media_assets")
@@ -76,7 +88,11 @@ export async function POST(request: Request) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ asset: asset as MediaAsset });
// 返回 asset 和一个特殊的 asset:id 格式用于存储在思维导图中
return NextResponse.json({
asset: asset as MediaAsset,
mindmapUrl: `asset:${asset.id}`,
});
} catch (error) {
console.error(error);
return NextResponse.json({ error: "上传失败" }, { status: 500 });