实现了AI助手

This commit is contained in:
2025-06-24 14:09:12 +08:00
parent 7d139b22db
commit 8a4ccd5ef2
31 changed files with 2883 additions and 252 deletions
+159
View File
@@ -0,0 +1,159 @@
import { prisma } from '@/lib/prisma'
export interface ComponentQueryParams {
type?: string
typeId?: string // 直接使用typeId
brand?: string
minPrice?: number
maxPrice?: number
search?: string
page?: number
limit?: number
}
export interface ComponentQueryResult {
components: Array<{
id: string
name: string
brand: string
model: string
price: number
description: string | null
stock: number
type: string
specifications: string | null
imageUrl: string | null
}>
pagination: {
page: number
limit: number
total: number
totalPages: number
hasNext: boolean
hasPrev: boolean
}
}
export class ComponentService {
/**
* 查询组件列表
*/
static async queryComponents(params: ComponentQueryParams): Promise<ComponentQueryResult> {
const {
type,
typeId,
brand,
minPrice,
maxPrice,
search,
page = 1,
limit = 12
} = params
const where: any = {}
// 优先使用typeId,如果没有但有type,则查找typeId
if (typeId) {
where.componentTypeId = typeId
} else if (type) {
const componentType = await prisma.componentType.findFirst({
where: {
name: {
contains: type,
mode: 'insensitive'
}
}
})
if (componentType) {
where.componentTypeId = componentType.id
}
}
if (brand) {
where.brand = {
contains: brand,
mode: 'insensitive'
}
}
if (minPrice || maxPrice) {
where.price = {}
if (minPrice) where.price.gte = minPrice
if (maxPrice) where.price.lte = maxPrice
}
if (search) {
where.OR = [
{ name: { contains: search, mode: 'insensitive' } },
{ brand: { contains: search, mode: 'insensitive' } },
{ model: { contains: search, mode: 'insensitive' } },
{ description: { contains: search, mode: 'insensitive' } }
]
}
const [components, total] = await Promise.all([
prisma.component.findMany({
where,
include: {
componentType: true
},
orderBy: {
createdAt: 'desc'
},
skip: (page - 1) * limit,
take: limit
}),
prisma.component.count({ where })
])
const totalPages = Math.ceil(total / limit)
return {
components: components.map(comp => ({
id: comp.id,
name: comp.name,
brand: comp.brand,
model: comp.model,
price: comp.price,
description: comp.description,
stock: comp.stock,
type: comp.componentType.name,
specifications: comp.specifications,
imageUrl: comp.imageUrl
})),
pagination: {
page,
limit,
total,
totalPages,
hasNext: page < totalPages,
hasPrev: page > 1
}
}
}
/**
* 根据ID获取单个组件
*/
static async getComponentById(id: string) {
return await prisma.component.findUnique({
where: { id },
include: {
componentType: true
}
})
}
static async getComponentsByIds(componentIds: string[]) {
return await Promise.all(componentIds.map(id => ComponentService.getComponentById(id)))
}
/**
* 获取所有组件类型
*/
static async getComponentTypes() {
return await prisma.componentType.findMany({
orderBy: {
name: 'asc'
}
})
}
}
+163
View File
@@ -0,0 +1,163 @@
import { prisma } from '@/lib/prisma'
import type { MessageParam } from '@anthropic-ai/sdk/resources'
export interface ConversationData {
id: string
title: string | null
messages: MessageParam[]
createdAt: Date
updatedAt: Date
}
export class ConversationService {
/**
* 创建新对话
*/
static async createConversation(userId: string, initialMessage: string): Promise<string> {
// 生成对话标题(取用户消息的前30个字符)
const title = initialMessage.length > 30
? initialMessage.substring(0, 30) + '...'
: initialMessage
const systemMessage: MessageParam = {
role: "user",
content: `你是PC DIY商店的专业AI助手。你的主要职责是:
1. 帮助用户查找和推荐PC配件
2. 提供配件的价格、性能和兼容性信息
3. 根据用户预算和需求推荐最适合的配件
4. 解答关于PC装机的技术问题`
}
const assistantGreeting: MessageParam = {
role: "assistant",
content: "您好!我是PC DIY商店的AI助手,很高兴为您服务。请告诉我您需要什么帮助?"
}
const userMessage: MessageParam = {
role: "user",
content: initialMessage
}
const initialMessages = [systemMessage, assistantGreeting, userMessage]
const conversation = await prisma.conversation.create({
data: {
userId,
title,
messages: JSON.stringify(initialMessages)
}
})
return conversation.id
}
/**
* 获取对话
*/
static async getConversation(conversationId: string, userId: string): Promise<ConversationData | null> {
const conversation = await prisma.conversation.findFirst({
where: {
id: conversationId,
userId
}
})
if (!conversation) {
return null
}
return {
id: conversation.id,
title: conversation.title,
messages: JSON.parse(conversation.messages) as MessageParam[],
createdAt: conversation.createdAt,
updatedAt: conversation.updatedAt
}
}
/**
* 更新对话消息
*/
static async updateConversationMessages(
conversationId: string,
userId: string,
messages: MessageParam[]
): Promise<void> {
await prisma.conversation.updateMany({
where: {
id: conversationId,
userId
},
data: {
messages: JSON.stringify(messages),
updatedAt: new Date()
}
})
}
/**
* 获取用户的对话列表
*/
static async getUserConversations(userId: string, page = 1, limit = 20) {
const skip = (page - 1) * limit
const [conversations, total] = await Promise.all([
prisma.conversation.findMany({
where: { userId },
select: {
id: true,
title: true,
createdAt: true,
updatedAt: true
},
orderBy: { updatedAt: 'desc' },
skip,
take: limit
}),
prisma.conversation.count({
where: { userId }
})
])
return {
conversations,
total,
page,
totalPages: Math.ceil(total / limit)
}
}
/**
* 删除对话
*/
static async deleteConversation(conversationId: string, userId: string): Promise<boolean> {
const result = await prisma.conversation.deleteMany({
where: {
id: conversationId,
userId
}
})
return result.count > 0
}
/**
* 更新对话标题
*/
static async updateConversationTitle(
conversationId: string,
userId: string,
title: string
): Promise<boolean> {
const result = await prisma.conversation.updateMany({
where: {
id: conversationId,
userId
},
data: { title }
})
return result.count > 0
}
}