import { PrismaClient, PromptModelProvider } from "@prisma/client"; const prisma = new PrismaClient(); async function main() { // 최소 사용자(시드): 운영 초기에는 OAuth/Email 붙이기 전까지 작성자 null 허용 // 카테고리 const catModels = await prisma.entityCategory.upsert({ where: { slug: "models" }, update: {}, create: { slug: "models", name: "모델", description: "LLM/이미지 모델" }, }); const catWork = await prisma.entityCategory.upsert({ where: { slug: "work" }, update: {}, create: { slug: "work", name: "업무", description: "업무/상황 기반 대상" }, }); // 엔티티 const entityChatGPT = await prisma.entity.upsert({ where: { slug: "chatgpt" }, update: {}, create: { slug: "chatgpt", name: "ChatGPT", summary: "대화형 LLM 기반 생산성/개발/글쓰기 도구", contentMd: "## 개요\nChatGPT는 자연어로 지시를 내리면 다양한 결과물을 생성하는 대화형 모델입니다.\n\n## 추천 사용\n- 요약/정리\n- 문서 초안\n- 코드 리뷰/디버깅\n", categoryId: catModels.id, }, }); const entityInterview = await prisma.entity.upsert({ where: { slug: "interview" }, update: {}, create: { slug: "interview", name: "면접", summary: "면접 준비/질문/답변 구조화", contentMd: "## 개요\n면접은 직무 역량과 커뮤니케이션을 검증하는 과정입니다.\n\n## 프롬프트 활용\n- 경험 정리(STAR)\n- 예상 질문 대비\n- 모의면접\n", categoryId: catWork.id, }, }); // 모델 const modelChatGPT = await prisma.promptModel.upsert({ where: { slug: "chatgpt" }, update: {}, create: { slug: "chatgpt", provider: PromptModelProvider.openai, name: "ChatGPT (OpenAI)", description: "OpenAI ChatGPT 계열", }, }); const modelClaude = await prisma.promptModel.upsert({ where: { slug: "claude" }, update: {}, create: { slug: "claude", provider: PromptModelProvider.anthropic, name: "Claude (Anthropic)", description: "Anthropic Claude 계열", }, }); // 태그 const tagSummary = await prisma.tag.upsert({ where: { slug: "summary" }, update: {}, create: { slug: "summary", name: "요약" }, }); const tagDev = await prisma.tag.upsert({ where: { slug: "dev" }, update: {}, create: { slug: "dev", name: "개발" }, }); const tagInterview = await prisma.tag.upsert({ where: { slug: "interview" }, update: {}, create: { slug: "interview", name: "면접" }, }); // Prompt 생성 헬퍼(버전 1 + current_version 세팅 + 예시 + 태그) async function createPromptWithV1(args: { entityId: string; title: string; descriptionMd?: string; modelId?: string; promptText: string; changelog?: string; tags: string[]; // tag ids examples?: Array<{ input?: string; output?: string; note?: string }>; }) { return prisma.$transaction(async (tx) => { const prompt = await tx.prompt.create({ data: { entityId: args.entityId, title: args.title, descriptionMd: args.descriptionMd, modelId: args.modelId, }, }); const v1 = await tx.promptVersion.create({ data: { promptId: prompt.id, versionNo: 1, promptText: args.promptText, changelog: args.changelog ?? "초기 등록", isApproved: true, approvedAt: new Date(), }, }); await tx.prompt.update({ where: { id: prompt.id }, data: { currentVersionId: v1.id }, }); if (args.tags.length) { await tx.promptTag.createMany({ data: args.tags.map((tagId) => ({ promptId: prompt.id, tagId })), skipDuplicates: true, }); } if (args.examples?.length) { await tx.promptExample.createMany({ data: args.examples.map((ex) => ({ promptVersionId: v1.id, inputExample: ex.input, outputExample: ex.output, note: ex.note, })), }); } return { promptId: prompt.id, versionId: v1.id }; }); } // 샘플 프롬프트 await createPromptWithV1({ entityId: entityChatGPT.id, title: "긴 글 핵심 요약 + 액션아이템 추출", descriptionMd: "회의록/기사/긴 문서를 붙여넣고 **핵심 요약 + 액션아이템**을 구조화해서 뽑습니다.", modelId: modelChatGPT.id, promptText: "너는 뛰어난 문서 편집자다.\n\n아래 텍스트를 읽고 다음 형식으로 답해라:\n1) 5줄 요약\n2) 핵심 포인트(불릿 5개)\n3) 액션 아이템(담당/기한 포함, 모르면 '미정')\n4) 리스크/의문점\n\n[텍스트]\n{{TEXT}}\n", tags: [tagSummary.id], examples: [ { input: "TEXT=오늘 회의에서 A는 3/1까지…", output: "1) 5줄 요약…\n2) 핵심 포인트…\n3) 액션 아이템…", }, ], }); await createPromptWithV1({ entityId: entityChatGPT.id, title: "코드 리뷰어(버그/보안/성능 체크리스트)", descriptionMd: "PR diff를 주면 **버그/보안/성능/가독성** 관점에서 리뷰 코멘트를 작성합니다.", modelId: modelClaude.id, promptText: "너는 시니어 코드 리뷰어다.\n\n다음을 수행해라:\n- 잠재 버그\n- 보안 취약점\n- 성능 병목\n- 코드 스타일/가독성\n- 테스트 제안\n\n출력은 섹션별로 bullet로.\n\n[DIFF]\n{{DIFF}}\n", tags: [tagDev.id], }); await createPromptWithV1({ entityId: entityInterview.id, title: "STAR 기반 경험 정리 + 면접 답변 리라이트", descriptionMd: "경험을 STAR로 재구성하고, 면접 답변으로 자연스럽게 리라이트합니다.", modelId: modelChatGPT.id, promptText: "너는 면접 코치다.\n\n아래 경험을 STAR(상황/과제/행동/결과)로 정리하고, 60~90초 답변 스크립트로 리라이트해라.\n- 과장 금지, 수치/근거 우선\n- 리스크/실패가 있으면 학습 포인트 포함\n\n[경험]\n{{EXP}}\n", tags: [tagInterview.id], }); } main() .then(async () => { await prisma.$disconnect(); }) .catch(async (e) => { console.error(e); await prisma.$disconnect(); process.exit(1); });