Your Name 9385b6f6d6 feat: implement auto-save, auto-title, and canvas file list sidebar
- Remove manual rename and save buttons from canvas header
- Add auto-save logic with debounce
- Add AI auto-titling and thumbnail generation based on canvas content
- Add CanvasFileList sidebar for managing canvases
- Direct entry to new canvas from top navigation
- Add new API endpoint for auto-titling
2026-01-24 22:50:34 +08:00

80 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/app/(auth)/auth";
import { createOpenAI } from "@ai-sdk/openai";
import { generateText } from "ai";
import { getSystemSetting } from "@/lib/db/queries";
export async function POST(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const { imageUrl } = await request.json();
if (!imageUrl) {
return NextResponse.json({ error: "Image URL is required" }, { status: 400 });
}
// 获取 AI 配置
const aiProviderConfig = await getSystemSetting({ key: "ai_provider_config" });
const modelsConfig = await getSystemSetting({ key: "ai_models_config" });
// 默认使用通义千问 (Alibaba) 配置,如果未配置则尝试其他
// 这里为了简化,我们假设系统中配置了支持视觉的模型。
// 在实际生产中,最好在前端指定一个确定的视觉模型ID传过来。
// 构造 Prompt
const prompt = "请用2-4个字概括这张图片的主体内容,作为文件标题。直接返回标题,不要包含任何标点符号或其他文字。";
// 这里我们尝试使用环境变量中的配置,或者从数据库读取的配置初始化模型
// 为了确保稳定性,这里建议使用一个支持视觉的兜底模型配置
// 假设系统中有配置好的 'qwen-vl-max' 或类似模型
// 临时方案:直接使用 fetch 调用通义千问 API (如果使用了兼容 OpenAI 的接口)
// 或者使用项目现有的 provider 逻辑。
// 由于我看不到完整的 provider 实现细节,我将使用项目中已有的 /api/chat 逻辑的简化版
// 但为了更直接,我们这里模拟一个简单的视觉模型调用,或者利用 ai-sdk 的标准特性
// ⚠️ 注意:这里需要确保您的环境变量中有 ALIBABA_API_KEY 或者对应的配置
// 如果项目中统一使用了 provider 管理,最好复用。
// 为了不破坏现有架构,我们这里简化处理:
// 如果您有特定的 vision model ID,请替换这里。
// 这里的 fallback 逻辑需要根据您的实际 .env 配置来调整。
const apiKey = process.env.ALIBABA_API_KEY || process.env.OPENAI_API_KEY;
const baseURL = process.env.ALIBABA_BASE_URL || "https://dashscope.aliyuncs.com/compatible-mode/v1";
if (!apiKey) {
return NextResponse.json({ title: "未命名画布" }, { status: 200 });
}
const openai = createOpenAI({
apiKey: apiKey,
baseURL: baseURL,
});
const { text } = await generateText({
model: openai("qwen-vl-max"), // 尝试使用 qwen-vl-max
messages: [
{
role: 'user',
content: [
{ type: 'text', text: prompt },
{ type: 'image', image: imageUrl },
],
},
],
});
return NextResponse.json({ title: text.trim() });
} catch (error) {
console.error("Auto-title error:", error);
// 失败时返回默认标题,不报错中断流程
return NextResponse.json({ title: "新画布" });
}
}