feat: Phase 1-3 全部完成 — 沙盒增强、学情分析、学习路径

This commit is contained in:
yuzhiran-dev
2026-05-18 09:48:51 +08:00
commit 11bb86854c
277 changed files with 37755 additions and 0 deletions
+511
View File
@@ -0,0 +1,511 @@
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
enum UserStatus {
ACTIVE
INACTIVE
BANNED
}
enum ContentStatus {
DRAFT
PUBLISHED
ARCHIVED
}
enum OrderStatus {
PENDING
PAID
CANCELLED
REFUNDED
}
enum MemberPlan {
FREE
MONTHLY
YEARLY
}
model User {
id Int @id @default(autoincrement())
phone String? @unique
email String? @unique
passwordHash String?
nickname String?
avatar String?
bio String?
status UserStatus @default(ACTIVE)
memberPlan MemberPlan @default(FREE)
memberExpire DateTime?
sandboxDaily Int @default(10)
followerCount Int @default(0)
followingCount Int @default(0)
postCount Int @default(0)
lastLoginAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
learnRecords LearnRecord[]
promptFavorites PromptFavorite[]
prompts Prompt[]
sandboxSessions SandboxSession[]
orders Order[]
subscriptions Subscription[]
posts Post[]
comments Comment[]
postLikes PostLike[]
followers Follow[] @relation("Following")
following Follow[] @relation("Follower")
createdCircles Circle[] @relation("CircleCreator")
circleMemberships CircleMember[]
organizationMemberships OrganizationMember[]
notifications Notification[]
@@map("users")
}
model Category {
id Int @id @default(autoincrement())
name String
slug String @unique
description String?
sortOrder Int @default(0)
parentId Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
parent Category? @relation("CategoryTree", fields: [parentId], references: [id])
children Category[] @relation("CategoryTree")
courses Course[]
prompts Prompt[]
contents Content[]
tools Tool[]
@@map("categories")
}
model Course {
id Int @id @default(autoincrement())
title String
description String?
cover String?
categoryId Int?
price Float @default(0)
isFree Boolean @default(true)
status ContentStatus @default(DRAFT)
sortOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
category Category? @relation(fields: [categoryId], references: [id])
chapters Chapter[]
progress LearnRecord[]
assignments CourseAssignment[]
@@map("courses")
}
model Chapter {
id Int @id @default(autoincrement())
courseId Int
title String
sortOrder Int @default(0)
createdAt DateTime @default(now())
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
lessons Lesson[]
@@map("chapters")
}
model Lesson {
id Int @id @default(autoincrement())
chapterId Int
title String
content String?
videoUrl String?
duration Int?
sortOrder Int @default(0)
status ContentStatus @default(DRAFT)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
chapter Chapter @relation(fields: [chapterId], references: [id], onDelete: Cascade)
progress LearnRecord[]
@@map("lessons")
}
model LearnRecord {
id Int @id @default(autoincrement())
userId Int
courseId Int
lessonId Int
completed Boolean @default(false)
progress Float @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade)
@@unique([userId, lessonId])
@@map("learn_records")
}
model Prompt {
id Int @id @default(autoincrement())
title String
content String
description String?
categoryId Int?
tags String?
authorId Int?
model String?
isPublic Boolean @default(true)
status ContentStatus @default(PUBLISHED)
viewCount Int @default(0)
likeCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
category Category? @relation(fields: [categoryId], references: [id])
author User? @relation(fields: [authorId], references: [id])
favorites PromptFavorite[]
@@map("prompts")
}
model PromptFavorite {
id Int @id @default(autoincrement())
userId Int
promptId Int
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade)
@@unique([userId, promptId])
@@map("prompt_favorites")
}
model Tool {
id Int @id @default(autoincrement())
name String
description String?
url String
icon String?
categoryId Int?
tags String?
isFeatured Boolean @default(false)
status ContentStatus @default(PUBLISHED)
viewCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
category Category? @relation(fields: [categoryId], references: [id])
@@map("tools")
}
model Content {
id Int @id @default(autoincrement())
title String
summary String?
content String?
cover String?
categoryId Int?
tags String?
authorName String?
contentType String @default("article")
status ContentStatus @default(DRAFT)
viewCount Int @default(0)
isAiGenerated Boolean @default(false)
publishedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
category Category? @relation(fields: [categoryId], references: [id])
@@map("contents")
}
model AiModel {
id Int @id @default(autoincrement())
name String
provider String
description String?
capabilities String?
contextWindow Int?
maxTokens Int?
pricing String?
isFree Boolean @default(false)
isFeatured Boolean @default(false)
icon String?
sortOrder Int @default(0)
status String @default("ACTIVE")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("ai_models")
}
model SandboxSession {
id Int @id @default(autoincrement())
userId Int
conversationId String @default("")
model String
title String @default("AI 对话")
messages String @db.Text
feedback String?
tokens Int @default(0)
duration Int @default(0)
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, conversationId])
@@index([userId, createdAt])
@@map("sandbox_sessions")
}
model Order {
id Int @id @default(autoincrement())
orderNo String @unique
userId Int
amount Float
planType String
status OrderStatus @default(PENDING)
payChannel String?
paidAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id])
@@index([userId, status])
@@index([status, createdAt])
@@map("orders")
}
model Subscription {
id Int @id @default(autoincrement())
userId Int
plan MemberPlan
startDate DateTime
endDate DateTime
status String @default("ACTIVE")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id])
@@index([userId, status])
@@map("subscriptions")
}
model AdminUser {
id Int @id @default(autoincrement())
username String @unique
passwordHash String
nickname String?
role String @default("editor")
status String @default("ACTIVE")
lastLoginAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("admin_users")
}
model AdminLog {
id Int @id @default(autoincrement())
adminId Int
action String
target String?
detail String?
ip String?
createdAt DateTime @default(now())
@@map("admin_logs")
}
model Post {
id Int @id @default(autoincrement())
userId Int
title String
content String
tags String?
circleId Int?
status String @default("PUBLISHED")
viewCount Int @default(0)
likeCount Int @default(0)
commentCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
comments Comment[]
likes PostLike[]
circle Circle? @relation(fields: [circleId], references: [id])
@@index([userId])
@@index([status, createdAt])
@@index([circleId])
@@map("posts")
}
model Comment {
id Int @id @default(autoincrement())
postId Int
userId Int
content String
parentId Int?
status String @default("PUBLISHED")
reviewNote String?
reviewedAt DateTime?
createdAt DateTime @default(now())
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
parent Comment? @relation("CommentReply", fields: [parentId], references: [id])
replies Comment[] @relation("CommentReply")
@@index([postId])
@@index([status])
@@map("comments")
}
model PostLike {
id Int @id @default(autoincrement())
postId Int
userId Int
createdAt DateTime @default(now())
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([postId, userId])
@@map("post_likes")
}
model Circle {
id Int @id @default(autoincrement())
name String
description String?
tags String?
creatorId Int
isPublic Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
creator User @relation("CircleCreator", fields: [creatorId], references: [id])
members CircleMember[]
posts Post[]
@@map("circles")
}
model CircleMember {
id Int @id @default(autoincrement())
circleId Int
userId Int
role String @default("member")
joinedAt DateTime @default(now())
circle Circle @relation(fields: [circleId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([circleId, userId])
@@map("circle_members")
}
model Follow {
id Int @id @default(autoincrement())
followerId Int
followingId Int
createdAt DateTime @default(now())
follower User @relation("Follower", fields: [followerId], references: [id], onDelete: Cascade)
following User @relation("Following", fields: [followingId], references: [id], onDelete: Cascade)
@@unique([followerId, followingId])
@@map("follows")
}
model Organization {
id Int @id @default(autoincrement())
name String
description String?
contactName String?
contactPhone String?
logo String?
memberCount Int @default(0)
status String @default("ACTIVE")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
members OrganizationMember[]
assignments CourseAssignment[]
@@map("organizations")
}
model OrganizationMember {
id Int @id @default(autoincrement())
organizationId Int
userId Int
role String @default("MEMBER")
status String @default("ACTIVE")
joinedAt DateTime @default(now())
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([organizationId, userId])
@@map("organization_members")
}
model CourseAssignment {
id Int @id @default(autoincrement())
organizationId Int
courseId Int
assignedBy Int
deadline DateTime?
createdAt DateTime @default(now())
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
@@map("course_assignments")
}
model Notification {
id Int @id @default(autoincrement())
userId Int
type String // 'like', 'comment', 'follow', 'system'
title String
content String?
link String?
relatedId Int?
isRead Boolean @default(false)
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, isRead])
@@map("notifications")
}
+1
View File
@@ -0,0 +1 @@
export {};
+156
View File
@@ -0,0 +1,156 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const client_1 = require("@prisma/client");
const bcrypt = __importStar(require("bcryptjs"));
const prisma = new client_1.PrismaClient();
async function main() {
const adminPassword = await bcrypt.hash('admin123456', 10);
await prisma.adminUser.upsert({
where: { username: 'admin' },
update: {},
create: {
username: 'admin',
passwordHash: adminPassword,
nickname: '超级管理员',
role: 'superadmin',
},
});
const categories = [
{ name: 'AI 入门', slug: 'ai-basics', description: 'AI 基础知识与入门指南' },
{ name: '办公效率', slug: 'office-productivity', description: '用 AI 提升办公效率' },
{ name: '创意设计', slug: 'creative-design', description: 'AI 辅助创意与设计' },
{ name: '编程开发', slug: 'programming', description: 'AI 辅助编程开发' },
{ name: '教育学习', slug: 'education', description: 'AI 在教育中的应用' },
{ name: '提示词技巧', slug: 'prompt-engineering', description: '提示词工程与技巧' },
{ name: 'AI 工具', slug: 'ai-tools', description: 'AI 工具收录与评测' },
{ name: '模型百科', slug: 'model-encyclopedia', description: '大模型介绍与对比' },
];
for (const cat of categories) {
await prisma.category.upsert({
where: { slug: cat.slug },
update: {},
create: cat,
});
}
const basicsCategory = await prisma.category.findUnique({ where: { slug: 'ai-basics' } });
const promptCategory = await prisma.category.findUnique({ where: { slug: 'prompt-engineering' } });
if (basicsCategory) {
const course = await prisma.course.upsert({
where: { id: 1 },
update: {},
create: {
title: 'AI 通识课:零基础入门人工智能',
description: '面向零基础用户的 AI 入门课程,带你了解 AI 的基本概念、发展历程和实际应用。',
categoryId: basicsCategory.id,
isFree: true,
status: 'PUBLISHED',
sortOrder: 1,
chapters: {
create: [
{
title: '第一章:什么是人工智能',
sortOrder: 1,
lessons: {
create: [
{ title: 'AI 的定义与发展简史', content: '# AI 的定义\n\n人工智能...', sortOrder: 1, status: 'PUBLISHED' },
{ title: '机器学习 vs 深度学习', content: '# 机器学习\n\n...', sortOrder: 2, status: 'PUBLISHED' },
{ title: '大语言模型(LLM)是什么', content: '# 大语言模型\n\n...', sortOrder: 3, status: 'PUBLISHED' },
],
},
},
{
title: '第二章:主流 AI 工具介绍',
sortOrder: 2,
lessons: {
create: [
{ title: 'ChatGPT 与 GPT 系列', content: '# ChatGPT\n\n...', sortOrder: 1, status: 'PUBLISHED' },
{ title: 'Claude 系列模型', content: '# Claude\n\n...', sortOrder: 2, status: 'PUBLISHED' },
{ title: '国内大模型:通义千问、文心一言、GLM', content: '# 国内大模型\n\n...', sortOrder: 3, status: 'PUBLISHED' },
],
},
},
],
},
},
});
}
if (promptCategory) {
const prompts = [
{ title: '写周报助手', content: '请帮我写一份本周工作总结,我的工作是:[描述你的工作内容]。\n\n要求:\n1. 按重点项目分类\n2. 包含数据成果\n3. 列出下周计划\n4. 语言简洁专业', description: '帮你快速生成高质量周报', categoryId: promptCategory.id, tags: '办公,周报', model: '通用', status: 'PUBLISHED' },
{ title: '会议纪要生成', content: '请根据以下会议内容生成会议纪要:\n[粘贴会议内容]\n\n格式要求:\n- 时间\n- 参会人\n- 会议议题\n- 讨论要点\n- 待办事项及负责人', description: '快速整理会议内容为结构化纪要', categoryId: promptCategory.id, tags: '办公,会议', model: '通用', status: 'PUBLISHED' },
];
for (const prompt of prompts) {
await prisma.prompt.create({ data: prompt });
}
}
const toolsCategory = await prisma.category.findUnique({ where: { slug: 'ai-tools' } });
if (toolsCategory) {
const tools = [
{ name: 'ChatGPT', description: 'OpenAI 开发的对话式 AI 助手,支持文本生成、代码编写、分析等', url: 'https://chat.openai.com', categoryId: toolsCategory.id, tags: '对话,文本生成,代码', isFeatured: true, status: 'PUBLISHED' },
{ name: 'Claude', description: 'Anthropic 开发的 AI 助手,擅长深度分析、长文本处理', url: 'https://claude.ai', categoryId: toolsCategory.id, tags: '对话,分析,长文本', isFeatured: true, status: 'PUBLISHED' },
{ name: '通义千问', description: '阿里云开发的 AI 大模型,支持文本、图像、代码等多种任务', url: 'https://tongyi.aliyun.com', categoryId: toolsCategory.id, tags: '对话,文本,国内', isFeatured: true, status: 'PUBLISHED' },
{ name: '文心一言', description: '百度开发的 AI 对话产品,基于文心大模型', url: 'https://yiyan.baidu.com', categoryId: toolsCategory.id, tags: '对话,文本,国内', isFeatured: true, status: 'PUBLISHED' },
];
for (const tool of tools) {
await prisma.tool.create({ data: tool });
}
}
const models = [
{ name: 'GPT-4o', provider: 'OpenAI', description: 'OpenAI 的多模态旗舰模型,支持文本、图像、音频输入,性能全面领先', capabilities: '文本生成,图像理解,代码,分析,多语言', contextWindow: 128000, maxTokens: 4096, pricing: '付费 API', isFeatured: true, sortOrder: 1 },
{ name: 'GPT-4o-mini', provider: 'OpenAI', description: 'GPT-4o 的轻量版,速度快、成本低,适合日常对话和简单任务', capabilities: '文本生成,代码,分析', contextWindow: 128000, maxTokens: 16384, pricing: '付费 API', isFeatured: false, sortOrder: 2 },
{ name: 'Claude 3.5 Sonnet', provider: 'Anthropic', description: 'Anthropic 的旗舰模型,在编程、深度分析、长文本处理方面表现优异', capabilities: '文本生成,代码,分析,长文本,多语言', contextWindow: 200000, maxTokens: 8192, pricing: '付费 API', isFeatured: true, sortOrder: 3 },
{ name: 'DeepSeek-V3', provider: '深度求索', description: '国产开源大模型,推理能力强,数学和编程能力突出,性价比极高', capabilities: '文本生成,代码,数学推理,分析', contextWindow: 128000, maxTokens: 8192, pricing: '免费/付费 API', isFeatured: true, sortOrder: 4 },
{ name: 'DeepSeek-R1', provider: '深度求索', description: '专注推理的模型,擅长复杂逻辑推理、数学问题,思维链能力强大', capabilities: '推理,数学,逻辑,代码', contextWindow: 128000, maxTokens: 8192, pricing: '免费/付费 API', isFeatured: true, sortOrder: 5 },
{ name: '通义千问 2.5', provider: '阿里云', description: '阿里云推出的最新版 Qwen 模型,中英文能力优秀,支持图像理解', capabilities: '文本生成,图像理解,代码,多语言', contextWindow: 131072, maxTokens: 8192, pricing: '免费/付费 API', isFeatured: true, sortOrder: 6 },
{ name: 'GLM-4', provider: '智谱 AI', description: '智谱 AI 的第四代 GLM 模型,中文理解能力强,支持多模态和工具调用', capabilities: '文本生成,代码,工具调用,多模态', contextWindow: 128000, maxTokens: 4096, pricing: '免费/付费 API', isFeatured: false, sortOrder: 7 },
{ name: '文心一言 4.0', provider: '百度', description: '百度文心大模型 4.0,知识问答和中文理解能力强,支持多种格式', capabilities: '文本生成,知识问答,图像生成,代码', contextWindow: 8000, maxTokens: 4096, pricing: '付费 API', isFeatured: false, sortOrder: 8 },
{ name: 'Moonshot', provider: '月之暗面', description: 'Kimi 背后的模型,超长上下文窗口(200 万字),擅长长文档处理', capabilities: '长文本,文档分析,文本生成', contextWindow: 128000, maxTokens: 4096, pricing: '免费/付费 API', isFeatured: false, sortOrder: 9 },
{ name: 'Gemini 2.0 Flash', provider: 'Google', description: 'Google 的轻量高速模型,多模态能力强,支持图片/视频/音频理解', capabilities: '多模态,图像理解,音频,视频,代码', contextWindow: 1000000, maxTokens: 8192, pricing: '免费 API', isFree: true, isFeatured: false, sortOrder: 10 },
];
for (const model of models) {
await prisma.aiModel.create({ data: model });
}
console.log('Seed data created successfully!');
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
//# sourceMappingURL=seed.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"seed.js","sourceRoot":"","sources":["seed.ts"],"names":[],"mappings":"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"}
+122
View File
@@ -0,0 +1,122 @@
import { PrismaClient } from '@prisma/client';
import * as bcrypt from 'bcryptjs';
const prisma = new PrismaClient();
async function main() {
// 创建管理员
const adminPassword = await bcrypt.hash('admin123456', 10);
await prisma.adminUser.upsert({
where: { username: 'admin' },
update: {},
create: {
username: 'admin',
passwordHash: adminPassword,
nickname: '超级管理员',
role: 'superadmin',
},
});
// 创建分类
const categories = [
{ name: 'AI 入门', slug: 'ai-basics', description: 'AI 基础知识与入门指南' },
{ name: '办公效率', slug: 'office-productivity', description: '用 AI 提升办公效率' },
{ name: '创意设计', slug: 'creative-design', description: 'AI 辅助创意与设计' },
{ name: '编程开发', slug: 'programming', description: 'AI 辅助编程开发' },
{ name: '教育学习', slug: 'education', description: 'AI 在教育中的应用' },
{ name: '提示词技巧', slug: 'prompt-engineering', description: '提示词工程与技巧' },
{ name: 'AI 工具', slug: 'ai-tools', description: 'AI 工具收录与评测' },
{ name: '模型百科', slug: 'model-encyclopedia', description: '大模型介绍与对比' },
];
for (const cat of categories) {
await prisma.category.upsert({
where: { slug: cat.slug },
update: {},
create: cat,
});
}
// 创建示例课程
const basicsCategory = await prisma.category.findUnique({ where: { slug: 'ai-basics' } });
const promptCategory = await prisma.category.findUnique({ where: { slug: 'prompt-engineering' } });
if (basicsCategory) {
const course = await prisma.course.upsert({
where: { id: 1 },
update: {},
create: {
title: 'AI 通识课:零基础入门人工智能',
description: '面向零基础用户的 AI 入门课程,带你了解 AI 的基本概念、发展历程和实际应用。',
categoryId: basicsCategory.id,
isFree: true,
status: 'PUBLISHED',
sortOrder: 1,
chapters: {
create: [
{
title: '第一章:什么是人工智能',
sortOrder: 1,
lessons: {
create: [
{ title: 'AI 的定义与发展简史', content: '# AI 的定义\n\n人工智能...', sortOrder: 1, status: 'PUBLISHED' },
{ title: '机器学习 vs 深度学习', content: '# 机器学习\n\n...', sortOrder: 2, status: 'PUBLISHED' },
{ title: '大语言模型(LLM)是什么', content: '# 大语言模型\n\n...', sortOrder: 3, status: 'PUBLISHED' },
],
},
},
{
title: '第二章:主流 AI 工具介绍',
sortOrder: 2,
lessons: {
create: [
{ title: 'ChatGPT 与 GPT 系列', content: '# ChatGPT\n\n...', sortOrder: 1, status: 'PUBLISHED' },
{ title: 'Claude 系列模型', content: '# Claude\n\n...', sortOrder: 2, status: 'PUBLISHED' },
{ title: '国内大模型:通义千问、文心一言、GLM', content: '# 国内大模型\n\n...', sortOrder: 3, status: 'PUBLISHED' },
],
},
},
],
},
},
});
}
// 创建示例提示词
if (promptCategory) {
const prompts = [
{ title: '写周报助手', content: '请帮我写一份本周工作总结,我的工作是:[描述你的工作内容]。\n\n要求:\n1. 按重点项目分类\n2. 包含数据成果\n3. 列出下周计划\n4. 语言简洁专业', description: '帮你快速生成高质量周报', categoryId: promptCategory.id, tags: '办公,周报', model: '通用', status: 'PUBLISHED' as const },
{ title: '会议纪要生成', content: '请根据以下会议内容生成会议纪要:\n[粘贴会议内容]\n\n格式要求:\n- 时间\n- 参会人\n- 会议议题\n- 讨论要点\n- 待办事项及负责人', description: '快速整理会议内容为结构化纪要', categoryId: promptCategory.id, tags: '办公,会议', model: '通用', status: 'PUBLISHED' as const },
];
for (const prompt of prompts) {
await prisma.prompt.create({ data: prompt });
}
}
// 创建示例 AI 工具
const toolsCategory = await prisma.category.findUnique({ where: { slug: 'ai-tools' } });
if (toolsCategory) {
const tools = [
{ name: 'ChatGPT', description: 'OpenAI 开发的对话式 AI 助手,支持文本生成、代码编写、分析等', url: 'https://chat.openai.com', categoryId: toolsCategory.id, tags: '对话,文本生成,代码', isFeatured: true, status: 'PUBLISHED' as const },
{ name: 'Claude', description: 'Anthropic 开发的 AI 助手,擅长深度分析、长文本处理', url: 'https://claude.ai', categoryId: toolsCategory.id, tags: '对话,分析,长文本', isFeatured: true, status: 'PUBLISHED' as const },
{ name: '通义千问', description: '阿里云开发的 AI 大模型,支持文本、图像、代码等多种任务', url: 'https://tongyi.aliyun.com', categoryId: toolsCategory.id, tags: '对话,文本,国内', isFeatured: true, status: 'PUBLISHED' as const },
{ name: '文心一言', description: '百度开发的 AI 对话产品,基于文心大模型', url: 'https://yiyan.baidu.com', categoryId: toolsCategory.id, tags: '对话,文本,国内', isFeatured: true, status: 'PUBLISHED' as const },
];
for (const tool of tools) {
await prisma.tool.create({ data: tool });
}
}
console.log('Seed data created successfully!');
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": ".",
"outDir": "./dist-prisma",
"types": ["node"]
},
"include": ["prisma/**/*.ts"]
}