Spaces:
Configuration error
Configuration error
| /** | |
| * Search utilities for OpenPrompt | |
| * Supports full-text search across prompts | |
| */ | |
| export interface SearchFilters { | |
| query?: string | |
| category?: string | |
| tags?: string[] | |
| model?: string | |
| minStars?: number | |
| minRuns?: number | |
| dateRange?: 'day' | 'week' | 'month' | 'all' | |
| sortBy?: 'trending' | 'recent' | 'stars' | 'runs' | |
| } | |
| export interface SearchResult { | |
| id: string | |
| slug: string | |
| title: string | |
| description: string | null | |
| category: string | null | |
| tags: string[] | |
| totalRuns: number | |
| starsCount: number | |
| remixesCount: number | |
| createdAt: Date | |
| creator: { | |
| name: string | null | |
| username: string | null | |
| image: string | null | |
| } | null | |
| score?: number // relevance score | |
| } | |
| /** | |
| * Build Prisma where clause from search filters | |
| */ | |
| export function buildSearchWhere(filters: SearchFilters) { | |
| const where: Record<string, unknown> = { | |
| visibility: 'public', | |
| } | |
| // Text search (title + description) | |
| if (filters.query) { | |
| where.OR = [ | |
| { title: { contains: filters.query, mode: 'insensitive' } }, | |
| { description: { contains: filters.query, mode: 'insensitive' } }, | |
| { tags: { hasSome: [filters.query.toLowerCase()] } }, | |
| ] | |
| } | |
| // Category filter | |
| if (filters.category) { | |
| where.category = filters.category | |
| } | |
| // Tags filter | |
| if (filters.tags && filters.tags.length > 0) { | |
| where.tags = { hasSome: filters.tags } | |
| } | |
| // Model filter | |
| if (filters.model) { | |
| where.modelAllowed = { has: filters.model } | |
| } | |
| // Stars filter | |
| if (filters.minStars) { | |
| where.starsCount = { gte: filters.minStars } | |
| } | |
| // Runs filter | |
| if (filters.minRuns) { | |
| where.totalRuns = { gte: filters.minRuns } | |
| } | |
| // Date range filter | |
| if (filters.dateRange && filters.dateRange !== 'all') { | |
| const now = new Date() | |
| const cutoff = new Date() | |
| switch (filters.dateRange) { | |
| case 'day': | |
| cutoff.setDate(now.getDate() - 1) | |
| break | |
| case 'week': | |
| cutoff.setDate(now.getDate() - 7) | |
| break | |
| case 'month': | |
| cutoff.setMonth(now.getMonth() - 1) | |
| break | |
| } | |
| where.createdAt = { gte: cutoff } | |
| } | |
| return where | |
| } | |
| /** | |
| * Build Prisma orderBy from sort option | |
| */ | |
| export function buildSearchOrderBy(sortBy: SearchFilters['sortBy'] = 'trending') { | |
| switch (sortBy) { | |
| case 'recent': | |
| return [{ createdAt: 'desc' as const }] | |
| case 'stars': | |
| return [{ starsCount: 'desc' as const }, { createdAt: 'desc' as const }] | |
| case 'runs': | |
| return [{ totalRuns: 'desc' as const }, { createdAt: 'desc' as const }] | |
| case 'trending': | |
| default: | |
| // Trending uses a calculated score (handled separately) | |
| return [{ totalRuns: 'desc' as const }, { starsCount: 'desc' as const }] | |
| } | |
| } | |
| /** | |
| * Extract unique categories from prompts | |
| */ | |
| export function getCategories(): string[] { | |
| return [ | |
| 'Content', | |
| 'Development', | |
| 'Marketing', | |
| 'Business', | |
| 'Education', | |
| 'Creative', | |
| 'Research', | |
| ] | |
| } | |
| /** | |
| * Extract unique tags from prompts | |
| */ | |
| export async function getPopularTags(limit: number = 20): Promise<string[]> { | |
| try { | |
| // Query database for actual popular tags | |
| const { prisma } = await import('@/lib/prisma') | |
| const prompts = await prisma.prompt.findMany({ | |
| where: { visibility: 'public', tags: { isEmpty: false } }, | |
| select: { tags: true }, | |
| orderBy: { totalRuns: 'desc' }, | |
| take: 200, | |
| }) | |
| // Count tag frequency | |
| const tagCounts = new Map<string, number>() | |
| for (const prompt of prompts) { | |
| for (const tag of prompt.tags) { | |
| tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1) | |
| } | |
| } | |
| // Sort by frequency and return top N | |
| return [...tagCounts.entries()] | |
| .sort((a, b) => b[1] - a[1]) | |
| .slice(0, limit) | |
| .map(([tag]) => tag) | |
| } catch { | |
| // Fallback to hardcoded list if DB query fails | |
| return [ | |
| 'blog', 'writing', 'code', 'email', 'social-media', | |
| 'seo', 'ai', 'productivity', 'marketing', 'business', | |
| ].slice(0, limit) | |
| } | |
| } | |