import "server-only"; import { Prisma, PrismaClient } from "@prisma/client"; import { buildStyle8DPromptBlock } from "@/lib/types/style-profile"; const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient & { __schemaFingerprint?: string }; }; /** 與 schema 同步;dmmf 不可用時用固定字串讓 dev 快取仍能失效。 */ const SCHEMA_FINGERPRINT_FALLBACK = "ProductProfile:accountId,brand,brandId,context,createdAt,id,label,matchTags,topics,updatedAt|Topic:accountId,active,brief,brandProfileId,createdAt,id,label,productContext,productProfileId,query,researchMap,selectedTags,topicGoal"; let schemaFingerprint: string | null = null; function getSchemaFingerprint(): string { if (schemaFingerprint) return schemaFingerprint; try { const models = Prisma.dmmf?.datamodel?.models; if (models) { const account = models.find((m) => m.name === "Account"); const product = models.find((m) => m.name === "ProductProfile"); const topic = models.find((m) => m.name === "Topic"); const productFields = product?.fields.map((f) => f.name).sort().join(",") ?? ""; const topicFields = topic?.fields.map((f) => f.name).sort().join(",") ?? ""; const accountFields = account?.fields.map((f) => f.name).sort().join(",") ?? ""; schemaFingerprint = `Account:${accountFields}|ProductProfile:${productFields}|Topic:${topicFields}`; return schemaFingerprint; } } catch { // Prisma.dmmf 僅在 server runtime 可用 } schemaFingerprint = SCHEMA_FINGERPRINT_FALLBACK; return schemaFingerprint; } function createPrismaClient() { const fingerprint = getSchemaFingerprint(); const client = new PrismaClient({ log: process.env.NODE_ENV === "development" ? ["error", "warn"] : ["error"], }) as PrismaClient & { __schemaFingerprint?: string }; client.__schemaFingerprint = fingerprint; return client; } function isPrismaClientCurrent( client: PrismaClient & { __schemaFingerprint?: string } ): boolean { return ( "backgroundJob" in client && "user" in client && "productProfile" in client && "brandProfile" in client && client.__schemaFingerprint === getSchemaFingerprint() ); } function getPrismaClient() { const cached = globalForPrisma.prisma; if (cached && isPrismaClientCurrent(cached)) return cached; const client = createPrismaClient(); if (process.env.NODE_ENV !== "production") { globalForPrisma.prisma = client; } return client; } export const prisma = getPrismaClient(); export function resolvePersona( settings: { persona: string | null }, account?: { persona: string | null; styleProfile?: string | null; targetAudience?: string | null; goals?: string | null; } | null ) { const blocks = [ account?.persona?.trim() || settings.persona?.trim(), buildStyle8DPromptBlock(account?.styleProfile), account?.targetAudience?.trim() ? `目標受眾:${account.targetAudience.trim()}` : null, account?.goals?.trim() ? `經營目標:${account.goals.trim()}` : null, ].filter(Boolean); return blocks.length > 0 ? blocks.join("\n\n") : null; }