From c605964fa861fdf6a8f5d283fa61b1b4230c6fba Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Wed, 12 Apr 2023 00:44:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=9F=A5=E8=AF=86=E5=BA=93=E5=8C=B9?= =?UTF-8?q?=E9=85=8D=E6=A8=A1=E5=BC=8F=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 1 + src/constants/model.ts | 45 +++++++++++++------ src/pages/api/chat/vectorGpt.ts | 26 ++++++++--- src/pages/api/model/update.ts | 3 +- src/pages/api/openapi/chat/lafGpt.ts | 12 ++--- src/pages/chat/index.tsx | 3 +- .../model/detail/components/ModelEditForm.tsx | 28 +++++++----- src/pages/model/detail/index.tsx | 1 + src/service/models/model.ts | 9 ++++ src/types/model.d.ts | 5 ++- src/types/mongoSchema.d.ts | 10 ++++- 11 files changed, 102 insertions(+), 41 deletions(-) diff --git a/.dockerignore b/.dockerignore index 599da9cd7..c7fff2624 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,3 +8,4 @@ README.md .yalc/ yalc.lock +testApi/ \ No newline at end of file diff --git a/src/constants/model.ts b/src/constants/model.ts index cd47a65a4..837b287d5 100644 --- a/src/constants/model.ts +++ b/src/constants/model.ts @@ -4,14 +4,12 @@ import type { RedisModelDataItemType } from '@/types/redis'; export enum ChatModelNameEnum { GPT35 = 'gpt-3.5-turbo', VECTOR_GPT = 'VECTOR_GPT', - GPT3 = 'text-davinci-003', VECTOR = 'text-embedding-ada-002' } export const ChatModelNameMap = { [ChatModelNameEnum.GPT35]: 'gpt-3.5-turbo', [ChatModelNameEnum.VECTOR_GPT]: 'gpt-3.5-turbo', - [ChatModelNameEnum.GPT3]: 'text-davinci-003', [ChatModelNameEnum.VECTOR]: 'text-embedding-ada-002' }; @@ -34,7 +32,7 @@ export const modelList: ModelConstantsData[] = [ trainName: '', maxToken: 4000, contextMaxToken: 7500, - maxTemperature: 2, + maxTemperature: 1.5, price: 3 }, { @@ -47,16 +45,6 @@ export const modelList: ModelConstantsData[] = [ maxTemperature: 1, price: 3 } - // { - // serviceCompany: 'openai', - // name: 'GPT3', - // model: ChatModelNameEnum.GPT3, - // trainName: 'davinci', - // maxToken: 4000, - // contextMaxToken: 7500, - // maxTemperature: 2, - // price: 30 - // } ]; export enum TrainingStatusEnum { @@ -97,6 +85,34 @@ export const ModelDataStatusMap: Record = { + [ModelVectorSearchModeEnum.hightSimilarity]: { + text: '高相似度, 无匹配时拒绝回复', + similarity: 0.2 + }, + [ModelVectorSearchModeEnum.noContext]: { + text: '高相似度,无匹配时直接回复', + similarity: 0.2 + }, + [ModelVectorSearchModeEnum.lowSimilarity]: { + text: '低相似度匹配', + similarity: 0.8 + } +}; + export const defaultModel: ModelSchema = { _id: '', userId: '', @@ -108,6 +124,9 @@ export const defaultModel: ModelSchema = { systemPrompt: '', intro: '', temperature: 5, + search: { + mode: ModelVectorSearchModeEnum.hightSimilarity + }, service: { company: 'openai', trainId: '', diff --git a/src/pages/api/chat/vectorGpt.ts b/src/pages/api/chat/vectorGpt.ts index aa5313d3c..78ad031ea 100644 --- a/src/pages/api/chat/vectorGpt.ts +++ b/src/pages/api/chat/vectorGpt.ts @@ -7,7 +7,7 @@ import { ChatItemType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import type { ModelSchema } from '@/types/mongoSchema'; import { PassThrough } from 'stream'; -import { modelList } from '@/constants/model'; +import { modelList, ModelVectorSearchModeMap, ModelVectorSearchModeEnum } from '@/constants/model'; import { pushChatBill } from '@/service/events/pushBill'; import { connectRedis } from '@/service/redis'; import { VecModelDataPrefix } from '@/constants/redis'; @@ -65,13 +65,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) text: prompt.value }); + const similarity = ModelVectorSearchModeMap[model.search.mode]?.similarity || 0.22; // 搜索系统提示词, 按相似度从 redis 中搜出相关的 q 和 text const redisData: any[] = await redis.sendCommand([ 'FT.SEARCH', `idx:${VecModelDataPrefix}:hash`, `@modelId:{${String( chat.modelId._id - )}} @vector:[VECTOR_RANGE 0.22 $blob]=>{$YIELD_DISTANCE_AS: score}`, + )}} @vector:[VECTOR_RANGE ${similarity} $blob]=>{$YIELD_DISTANCE_AS: score}`, 'RETURN', '1', 'text', @@ -97,7 +98,24 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } } - if (formatRedisPrompt.length > 0) { + /* 高相似度+退出,无法匹配时直接退出 */ + if ( + formatRedisPrompt.length === 0 && + model.search.mode === ModelVectorSearchModeEnum.hightSimilarity + ) { + return res.send('对不起,你的问题不在知识库中。'); + } + /* 高相似度+无上下文,不添加额外知识 */ + if ( + formatRedisPrompt.length === 0 && + model.search.mode === ModelVectorSearchModeEnum.noContext + ) { + prompts.unshift({ + obj: 'SYSTEM', + value: model.systemPrompt + }); + } else { + // 有匹配情况下,添加知识库内容。 // 系统提示词过滤,最多 2800 tokens const systemPrompt = systemPromptFilter(formatRedisPrompt, 2800); @@ -107,8 +125,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) 'YYYY/MM/DD HH:mm:ss' )} ${systemPrompt}"` }); - } else { - return res.send('对不起,你的问题不在知识库中。'); } // 控制在 tokens 数量,防止超出 diff --git a/src/pages/api/model/update.ts b/src/pages/api/model/update.ts index af9d013c2..329aa2cb7 100644 --- a/src/pages/api/model/update.ts +++ b/src/pages/api/model/update.ts @@ -8,7 +8,7 @@ import type { ModelUpdateParams } from '@/types/model'; /* 获取我的模型 */ export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - const { name, service, security, systemPrompt, intro, temperature } = + const { name, search, service, security, systemPrompt, intro, temperature } = req.body as ModelUpdateParams; const { modelId } = req.query as { modelId: string }; const { authorization } = req.headers; @@ -37,6 +37,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< systemPrompt, intro, temperature, + search, // service, security } diff --git a/src/pages/api/openapi/chat/lafGpt.ts b/src/pages/api/openapi/chat/lafGpt.ts index 1b8255649..31f7e20df 100644 --- a/src/pages/api/openapi/chat/lafGpt.ts +++ b/src/pages/api/openapi/chat/lafGpt.ts @@ -83,22 +83,22 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) 下面是一些例子: 实现一个手机号发生注册验证码方法. 1. 从 query 中获取 phone. -2. 校验手机号格式是否正确,不正确返回{error: "手机号格式错误"}. +2. 校验手机号格式是否正确,不正确则返回错误响应,消息为:手机号格式错误. 3. 给 phone 发送一个短信验证码,验证码长度为6位字符串,内容为:你正在注册laf,验证码为:code. 4. 数据库添加数据,表为"codes",内容为 {phone, code}. 实现根据手机号注册账号,需要验证手机验证码. 1. 从 body 中获取 phone 和 code. -2. 校验手机号格式是否正确,不正确返回{error: "手机号格式错误"}. -2. 获取数据库数据,表为"codes",查找是否有符合 phone, code 等于body参数的记录,没有的话返回 {error:"验证码不正确"}. +2. 校验手机号格式是否正确,不正确返回错误响应,消息为:手机号格式错误. +2. 获取数据库数据,表为"codes",查找是否有符合 phone, code 等于body参数的记录,没有的话错误响应,消息为:验证码不正确. 4. 添加数据库数据,表为"users" ,内容为{phone, code, createTime}. 5. 删除数据库数据,删除 code 记录. 更新博客记录。传入blogId,blogText,tags,还需要记录更新的时间. 1. 从 body 中获取 blogId,blogText 和 tags. -2. 校验 blogId 是否为空,为空则返回 {error: "博客ID不能为空"}. -3. 校验 blogText 是否为空,为空则返回 {error: "博客内容不能为空"}. -4. 校验 tags 是否为数组,不是则返回 {error: "标签必须为数组"}. +2. 校验 blogId 是否为空,为空则错误响应,消息为:博客ID不能为空. +3. 校验 blogText 是否为空,为空则错误响应,消息为:博客内容不能为空. +4. 校验 tags 是否为数组,不是则错误响应,消息为:标签必须为数组. 5. 获取当前时间,记录为 updateTime. 6. 更新数据库数据,表为"blogs",更新符合 blogId 的记录的内容为{blogText, tags, updateTime}. 7. 返回结果 {message: "更新博客记录成功"}.` diff --git a/src/pages/chat/index.tsx b/src/pages/chat/index.tsx index 4205c156e..48d943ad5 100644 --- a/src/pages/chat/index.tsx +++ b/src/pages/chat/index.tsx @@ -114,8 +114,7 @@ const Chat = ({ chatId }: { chatId: string }) => { async (prompts: ChatSiteItemType) => { const urlMap: Record = { [ChatModelNameEnum.GPT35]: '/api/chat/chatGpt', - [ChatModelNameEnum.VECTOR_GPT]: '/api/chat/vectorGpt', - [ChatModelNameEnum.GPT3]: '/api/chat/gpt3' + [ChatModelNameEnum.VECTOR_GPT]: '/api/chat/vectorGpt' }; if (!urlMap[chatData.modelName]) return Promise.reject('找不到模型'); diff --git a/src/pages/model/detail/components/ModelEditForm.tsx b/src/pages/model/detail/components/ModelEditForm.tsx index ec7cb4b87..cb0f0fdb5 100644 --- a/src/pages/model/detail/components/ModelEditForm.tsx +++ b/src/pages/model/detail/components/ModelEditForm.tsx @@ -12,12 +12,13 @@ import { SliderThumb, SliderMark, Tooltip, - Button + Button, + Select } from '@chakra-ui/react'; import { QuestionOutlineIcon } from '@chakra-ui/icons'; import type { ModelSchema } from '@/types/mongoSchema'; import { UseFormReturn } from 'react-hook-form'; -import { modelList } from '@/constants/model'; +import { modelList, ModelVectorSearchModeMap } from '@/constants/model'; import { formatPrice } from '@/utils/user'; import { useConfirm } from '@/hooks/useConfirm'; @@ -89,15 +90,6 @@ const ModelEditForm = ({ 删除模型 - {/* - 介绍: -