Spaces:
Configuration error
Configuration error
| import { NextRequest, NextResponse } from "next/server" | |
| import prisma from "@/lib/prisma" | |
| // Badge types and their criteria | |
| export type BadgeType = | |
| | "verified-quality" // 95%+ success rate | |
| | "framework-compliant" // Uses RACE, CARE, APE, etc. | |
| | "high-performance" // Fast + low token usage | |
| | "community-favorite" // High stars + runs | |
| | "trending" // High recent activity | |
| | "prolific-creator" // Many prompts created | |
| interface Badge { | |
| type: BadgeType | |
| label: string | |
| description: string | |
| icon: string | |
| } | |
| const BADGE_DEFINITIONS: Record<BadgeType, Badge> = { | |
| "verified-quality": { | |
| type: "verified-quality", | |
| label: "Verified Quality", | |
| description: "95%+ success rate", | |
| icon: "✓" | |
| }, | |
| "framework-compliant": { | |
| type: "framework-compliant", | |
| label: "Framework Compliant", | |
| description: "Uses structured prompting framework", | |
| icon: "📐" | |
| }, | |
| "high-performance": { | |
| type: "high-performance", | |
| label: "High Performance", | |
| description: "Fast and efficient", | |
| icon: "⚡" | |
| }, | |
| "community-favorite": { | |
| type: "community-favorite", | |
| label: "Community Favorite", | |
| description: "Loved by the community", | |
| icon: "❤️" | |
| }, | |
| "trending": { | |
| type: "trending", | |
| label: "Trending", | |
| description: "High recent activity", | |
| icon: "🔥" | |
| }, | |
| "prolific-creator": { | |
| type: "prolific-creator", | |
| label: "Prolific Creator", | |
| description: "Created many quality prompts", | |
| icon: "⭐" | |
| } | |
| } | |
| // Calculate badges for a prompt | |
| export function calculatePromptBadges(prompt: { | |
| totalRuns: number | |
| starsCount: number | |
| remixesCount: number | |
| framework?: string | null | |
| badges?: string[] | |
| }): BadgeType[] { | |
| const badges: BadgeType[] = [] | |
| // Framework Compliant - has a framework assigned | |
| if (prompt.framework) { | |
| badges.push("framework-compliant") | |
| } | |
| // Community Favorite - 50+ stars or 1000+ runs | |
| if (prompt.starsCount >= 50 || prompt.totalRuns >= 1000) { | |
| badges.push("community-favorite") | |
| } | |
| // High Performance - high usage indicates it works well | |
| if (prompt.totalRuns >= 500 && prompt.starsCount >= 20) { | |
| badges.push("high-performance") | |
| } | |
| // Trending - high recent activity (approximated by total stats) | |
| if (prompt.totalRuns >= 100 && prompt.remixesCount >= 5) { | |
| badges.push("trending") | |
| } | |
| // Verified Quality - good star-to-run ratio | |
| const starRatio = prompt.totalRuns > 0 ? prompt.starsCount / prompt.totalRuns : 0 | |
| if (starRatio >= 0.1 && prompt.totalRuns >= 50) { | |
| badges.push("verified-quality") | |
| } | |
| return badges | |
| } | |
| // GET - Get badges for a prompt | |
| export async function GET(request: NextRequest) { | |
| try { | |
| const { searchParams } = new URL(request.url) | |
| const promptId = searchParams.get("promptId") | |
| const promptSlug = searchParams.get("slug") | |
| if (!promptId && !promptSlug) { | |
| return NextResponse.json( | |
| { error: "promptId or slug is required" }, | |
| { status: 400 } | |
| ) | |
| } | |
| const prompt = await prisma.prompt.findFirst({ | |
| where: promptId | |
| ? { id: promptId } | |
| : { slug: promptSlug! }, | |
| select: { | |
| id: true, | |
| totalRuns: true, | |
| starsCount: true, | |
| remixesCount: true, | |
| framework: true, | |
| badges: true, | |
| } | |
| }) | |
| if (!prompt) { | |
| return NextResponse.json( | |
| { error: "Prompt not found" }, | |
| { status: 404 } | |
| ) | |
| } | |
| const calculatedBadges = calculatePromptBadges(prompt) | |
| // Return badge details | |
| const badgeDetails = calculatedBadges.map(type => BADGE_DEFINITIONS[type]) | |
| return NextResponse.json({ | |
| promptId: prompt.id, | |
| badges: badgeDetails, | |
| badgeTypes: calculatedBadges | |
| }) | |
| } catch (error) { | |
| console.error("Error fetching badges:", error) | |
| return NextResponse.json( | |
| { error: "Failed to fetch badges" }, | |
| { status: 500 } | |
| ) | |
| } | |
| } | |
| // POST - Recalculate and update badges for a prompt | |
| export async function POST(request: NextRequest) { | |
| try { | |
| const { promptId } = await request.json() | |
| if (!promptId) { | |
| return NextResponse.json( | |
| { error: "promptId is required" }, | |
| { status: 400 } | |
| ) | |
| } | |
| const prompt = await prisma.prompt.findUnique({ | |
| where: { id: promptId }, | |
| select: { | |
| id: true, | |
| totalRuns: true, | |
| starsCount: true, | |
| remixesCount: true, | |
| framework: true, | |
| } | |
| }) | |
| if (!prompt) { | |
| return NextResponse.json( | |
| { error: "Prompt not found" }, | |
| { status: 404 } | |
| ) | |
| } | |
| const calculatedBadges = calculatePromptBadges(prompt) | |
| // Update badges in database | |
| await prisma.prompt.update({ | |
| where: { id: promptId }, | |
| data: { badges: calculatedBadges } | |
| }) | |
| const badgeDetails = calculatedBadges.map(type => BADGE_DEFINITIONS[type]) | |
| return NextResponse.json({ | |
| promptId: prompt.id, | |
| badges: badgeDetails, | |
| badgeTypes: calculatedBadges, | |
| updated: true | |
| }) | |
| } catch (error) { | |
| console.error("Error updating badges:", error) | |
| return NextResponse.json( | |
| { error: "Failed to update badges" }, | |
| { status: 500 } | |
| ) | |
| } | |
| } | |