Prmbr/src/app/api/prompts/route.ts
2025-08-05 22:43:18 +08:00

192 lines
4.7 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 { prisma } from '@/lib/prisma'
import { SubscriptionService } from '@/lib/subscription-service'
// GET /api/prompts - 获取用户的 prompts 列表
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const page = parseInt(searchParams.get('page') || '1')
const limit = parseInt(searchParams.get('limit') || '12')
const search = searchParams.get('search') || ''
const tag = searchParams.get('tag') || ''
const sortBy = searchParams.get('sortBy') || 'updatedAt'
const sortOrder = searchParams.get('sortOrder') || 'desc'
const userId = searchParams.get('userId')
if (!userId) {
return NextResponse.json({ error: 'User ID is required' }, { status: 401 })
}
const skip = (page - 1) * limit
// 构建查询条件
const where: {
userId: string
OR?: Array<{
name?: { contains: string; mode: 'insensitive' }
description?: { contains: string; mode: 'insensitive' }
content?: { contains: string; mode: 'insensitive' }
}>
tags?: {
some: {
name: string
}
}
} = {
userId: userId,
}
if (search) {
where.OR = [
{ name: { contains: search, mode: 'insensitive' } },
{ description: { contains: search, mode: 'insensitive' } },
{ content: { contains: search, mode: 'insensitive' } },
]
}
if (tag) {
where.tags = {
some: {
name: tag
}
}
}
// 构建排序条件
const orderBy: Record<string, string> = {}
orderBy[sortBy] = sortOrder
// 获取总数
const total = await prisma.prompt.count({ where })
// 获取 prompts
const prompts = await prisma.prompt.findMany({
where,
include: {
tags: true,
versions: {
orderBy: { version: 'desc' },
take: 1
},
tests: {
orderBy: { createdAt: 'desc' },
take: 1
}
},
orderBy,
skip,
take: limit,
})
// 计算最后使用时间
const promptsWithLastUsed = prompts.map(prompt => ({
...prompt,
lastUsed: prompt.tests[0]?.createdAt || null,
currentVersion: prompt.versions[0]?.version || 1,
tags: prompt.tags.map(tag => tag.name)
}))
return NextResponse.json({
prompts: promptsWithLastUsed,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit)
}
})
} catch (error) {
console.error('Error fetching prompts:', error)
return NextResponse.json(
{ error: 'Failed to fetch prompts' },
{ status: 500 }
)
}
}
// POST /api/prompts - 创建新的 prompt
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const { name, description, content, tags, userId, permissions } = body
if (!userId) {
return NextResponse.json({ error: 'User ID is required' }, { status: 401 })
}
if (!name || !content) {
return NextResponse.json(
{ error: 'Name and content are required' },
{ status: 400 }
)
}
// 检查用户是否可以创建新的提示词
const canCreate = await SubscriptionService.canCreatePrompt(userId)
if (!canCreate) {
return NextResponse.json(
{ error: 'Prompt limit reached. Please upgrade your plan to create more prompts.' },
{ status: 403 }
)
}
// 创建或获取标签
const tagObjects = []
if (tags && tags.length > 0) {
for (const tagName of tags) {
const tag = await prisma.promptTag.upsert({
where: { name: tagName },
update: {},
create: { name: tagName }
})
tagObjects.push(tag)
}
}
// 创建 prompt
const prompt = await prisma.prompt.create({
data: {
name,
description,
content,
userId,
permissions: permissions || 'private',
tags: {
connect: tagObjects.map(tag => ({ id: tag.id }))
}
},
include: {
tags: true,
versions: true
}
})
// 创建初始版本
await prisma.promptVersion.create({
data: {
promptId: prompt.id,
version: 1,
content,
changelog: 'Initial version'
}
})
// 处理返回数据格式确保tags是字符串数组
const promptWithMetadata = {
...prompt,
tags: prompt.tags.map(tag => tag.name)
}
return NextResponse.json(promptWithMetadata, { status: 201 })
} catch (error) {
console.error('Error creating prompt:', error)
return NextResponse.json(
{ error: 'Failed to create prompt' },
{ status: 500 }
)
}
}