From 1f112f7715120aa3867f674c1ff9efed2a831f2a Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Mon, 24 Apr 2023 16:46:39 +0800 Subject: [PATCH] feat: chat content use tiktoken count --- package.json | 1 - pnpm-lock.yaml | 8 - src/constants/model.ts | 38 +-- src/pages/api/chat/chatGpt.ts | 39 +-- src/pages/api/chat/vectorGpt.ts | 40 ++- src/pages/api/data/splitData.ts | 4 +- src/pages/api/model/create.ts | 6 +- src/pages/api/openapi/chat/chatGpt.ts | 29 +-- src/pages/api/openapi/chat/lafGpt.ts | 53 ++-- src/pages/api/openapi/chat/vectorGpt.ts | 37 ++- src/pages/chat/index.tsx | 6 +- src/pages/data/components/CreateDataModal.tsx | 97 -------- src/pages/data/components/ImportDataModal.tsx | 229 ----------------- src/pages/data/detail.tsx | 67 ----- src/pages/data/list.tsx | 235 ------------------ .../detail/components/SelectUrlModal.tsx | 7 - src/service/events/generateAbstract.ts | 4 +- src/service/events/generateQA.ts | 4 +- src/service/events/pushBill.ts | 27 +- src/service/utils/openai.ts | 12 +- src/service/utils/tools.ts | 63 +++-- src/types/mongoSchema.d.ts | 9 +- src/utils/tools.ts | 3 +- 23 files changed, 182 insertions(+), 836 deletions(-) delete mode 100644 src/pages/data/components/CreateDataModal.tsx delete mode 100644 src/pages/data/components/ImportDataModal.tsx delete mode 100644 src/pages/data/detail.tsx delete mode 100644 src/pages/data/list.tsx diff --git a/package.json b/package.json index b7641a674..e010c98bc 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "eventsource-parser": "^0.1.0", "formidable": "^2.1.1", "framer-motion": "^9.0.6", - "gpt-token-utils": "^1.2.0", "graphemer": "^1.4.0", "hyperdown": "^2.4.29", "immer": "^9.0.19", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7a97f5c6f..6e464905a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,7 +33,6 @@ specifiers: eventsource-parser: ^0.1.0 formidable: ^2.1.1 framer-motion: ^9.0.6 - gpt-token-utils: ^1.2.0 graphemer: ^1.4.0 husky: ^8.0.3 hyperdown: ^2.4.29 @@ -86,7 +85,6 @@ dependencies: eventsource-parser: registry.npmmirror.com/eventsource-parser/0.1.0 formidable: registry.npmmirror.com/formidable/2.1.1 framer-motion: registry.npmmirror.com/framer-motion/9.0.6_biqbaboplfbrettd7655fr4n2y - gpt-token-utils: registry.npmmirror.com/gpt-token-utils/1.2.0 graphemer: registry.npmmirror.com/graphemer/1.4.0 hyperdown: registry.npmmirror.com/hyperdown/2.4.29 immer: registry.npmmirror.com/immer/9.0.19 @@ -7668,12 +7666,6 @@ packages: get-intrinsic: registry.npmmirror.com/get-intrinsic/1.2.0 dev: true - registry.npmmirror.com/gpt-token-utils/1.2.0: - resolution: {integrity: sha512-s8twaU38UE2Vp65JhQEjz8qvWhWY8KZYvmvYHapxlPT03Ok35Clq+gm9eE27wQILdFisseMVRSiC5lJR9GBklA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/gpt-token-utils/-/gpt-token-utils-1.2.0.tgz} - name: gpt-token-utils - version: 1.2.0 - dev: false - registry.npmmirror.com/graceful-fs/4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.10.tgz} name: graceful-fs diff --git a/src/constants/model.ts b/src/constants/model.ts index 1d6a67383..bb56bd622 100644 --- a/src/constants/model.ts +++ b/src/constants/model.ts @@ -5,24 +5,28 @@ export enum ModelDataStatusEnum { waiting = 'waiting' } -export enum ChatModelNameEnum { - GPT35 = 'gpt-3.5-turbo', - VECTOR_GPT = 'VECTOR_GPT', - VECTOR = 'text-embedding-ada-002' +export const embeddingModel = 'text-embedding-ada-002'; +export enum ChatModelEnum { + 'GPT35' = 'gpt-3.5-turbo', + 'GPT4' = 'gpt-4', + 'GPT432k' = 'gpt-4-32k' } -export const ChatModelNameMap = { - [ChatModelNameEnum.GPT35]: 'gpt-3.5-turbo', - [ChatModelNameEnum.VECTOR_GPT]: 'gpt-3.5-turbo', - [ChatModelNameEnum.VECTOR]: 'text-embedding-ada-002' +export enum ModelNameEnum { + GPT35 = 'gpt-3.5-turbo', + VECTOR_GPT = 'VECTOR_GPT' +} + +export const Model2ChatModelMap: Record<`${ModelNameEnum}`, `${ChatModelEnum}`> = { + [ModelNameEnum.GPT35]: 'gpt-3.5-turbo', + [ModelNameEnum.VECTOR_GPT]: 'gpt-3.5-turbo' }; export type ModelConstantsData = { icon: 'model' | 'dbModel'; name: string; - model: `${ChatModelNameEnum}`; + model: `${ModelNameEnum}`; trainName: string; // 空字符串代表不能训练 - maxToken: number; contextMaxToken: number; maxTemperature: number; price: number; // 多少钱 / 1token,单位: 0.00001元 @@ -32,20 +36,18 @@ export const modelList: ModelConstantsData[] = [ { icon: 'model', name: 'chatGPT', - model: ChatModelNameEnum.GPT35, + model: ModelNameEnum.GPT35, trainName: '', - maxToken: 4000, - contextMaxToken: 7000, + contextMaxToken: 4096, maxTemperature: 1.5, price: 3 }, { icon: 'dbModel', name: '知识库', - model: ChatModelNameEnum.VECTOR_GPT, + model: ModelNameEnum.VECTOR_GPT, trainName: 'vector', - maxToken: 4000, - contextMaxToken: 7000, + contextMaxToken: 4096, maxTemperature: 1, price: 3 } @@ -133,8 +135,8 @@ export const defaultModel: ModelSchema = { }, service: { trainId: '', - chatModel: ChatModelNameEnum.GPT35, - modelName: ChatModelNameEnum.GPT35 + chatModel: ModelNameEnum.GPT35, + modelName: ModelNameEnum.GPT35 }, security: { domain: ['*'], diff --git a/src/pages/api/chat/chatGpt.ts b/src/pages/api/chat/chatGpt.ts index 5c97f0019..e102ede09 100644 --- a/src/pages/api/chat/chatGpt.ts +++ b/src/pages/api/chat/chatGpt.ts @@ -2,7 +2,6 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase } from '@/service/mongo'; import { getOpenAIApi, authChat } from '@/service/utils/auth'; import { httpsAgent, openaiChatFilter } from '@/service/utils/tools'; -import { ChatCompletionRequestMessage, ChatCompletionRequestMessageRoleEnum } from 'openai'; import { ChatItemType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; @@ -64,42 +63,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } // 控制在 tokens 数量,防止超出 - const filterPrompts = openaiChatFilter(prompts, modelConstantsData.contextMaxToken); - - // 格式化文本内容成 chatgpt 格式 - const map = { - Human: ChatCompletionRequestMessageRoleEnum.User, - AI: ChatCompletionRequestMessageRoleEnum.Assistant, - SYSTEM: ChatCompletionRequestMessageRoleEnum.System - }; - const formatPrompts: ChatCompletionRequestMessage[] = filterPrompts.map( - (item: ChatItemType) => ({ - role: map[item.obj], - content: item.value - }) - ); + const filterPrompts = openaiChatFilter({ + model: model.service.chatModel, + prompts, + maxTokens: modelConstantsData.contextMaxToken - 500 + }); // 计算温度 const temperature = modelConstantsData.maxTemperature * (model.temperature / 10); - // console.log({ - // model: model.service.chatModel, - // temperature: temperature, - // // max_tokens: modelConstantsData.maxToken, - // messages: formatPrompts, - // frequency_penalty: 0.5, // 越大,重复内容越少 - // presence_penalty: -0.5, // 越大,越容易出现新内容 - // stream: true, - // stop: ['.!?。'] - // }); + // console.log(filterPrompts); // 获取 chatAPI const chatAPI = getOpenAIApi(userApiKey || systemKey); // 发出请求 const chatResponse = await chatAPI.createChatCompletion( { model: model.service.chatModel, - temperature: temperature, - // max_tokens: modelConstantsData.maxToken, - messages: formatPrompts, + temperature, + messages: filterPrompts, frequency_penalty: 0.5, // 越大,重复内容越少 presence_penalty: -0.5, // 越大,越容易出现新内容 stream: true, @@ -121,7 +101,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) stream, chatResponse }); - const promptsContent = formatPrompts.map((item) => item.content).join(''); // 只有使用平台的 key 才计费 pushChatBill({ @@ -129,7 +108,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) modelName: model.service.modelName, userId, chatId, - text: promptsContent + responseContent + messages: filterPrompts.concat({ role: 'assistant', content: responseContent }) }); } catch (err: any) { if (step === 1) { diff --git a/src/pages/api/chat/vectorGpt.ts b/src/pages/api/chat/vectorGpt.ts index 59fcb0d93..b607bed4c 100644 --- a/src/pages/api/chat/vectorGpt.ts +++ b/src/pages/api/chat/vectorGpt.ts @@ -2,10 +2,8 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase } from '@/service/mongo'; import { authChat } from '@/service/utils/auth'; import { httpsAgent, systemPromptFilter, openaiChatFilter } from '@/service/utils/tools'; -import { ChatCompletionRequestMessage, ChatCompletionRequestMessageRoleEnum } from 'openai'; import { ChatItemType } from '@/types/chat'; import { jsonRes } from '@/service/response'; -import type { ModelSchema } from '@/types/mongoSchema'; import { PassThrough } from 'stream'; import { modelList, @@ -105,9 +103,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) value: model.systemPrompt }); } else { - // 有匹配情况下,添加知识库内容。 - // 系统提示词过滤,最多 3000 tokens - const systemPrompt = systemPromptFilter(formatRedisPrompt, 3000); + // 有匹配情况下,system 添加知识库内容。 + // 系统提示词过滤,最多 2500 tokens + const systemPrompt = systemPromptFilter({ + model: model.service.chatModel, + prompts: formatRedisPrompt, + maxTokens: 2500 + }); prompts.unshift({ obj: 'SYSTEM', @@ -124,21 +126,13 @@ ${ } // 控制在 tokens 数量,防止超出 - const filterPrompts = openaiChatFilter(prompts, modelConstantsData.contextMaxToken); + const filterPrompts = openaiChatFilter({ + model: model.service.chatModel, + prompts, + maxTokens: modelConstantsData.contextMaxToken - 500 + }); - // 格式化文本内容成 chatgpt 格式 - const map = { - Human: ChatCompletionRequestMessageRoleEnum.User, - AI: ChatCompletionRequestMessageRoleEnum.Assistant, - SYSTEM: ChatCompletionRequestMessageRoleEnum.System - }; - const formatPrompts: ChatCompletionRequestMessage[] = filterPrompts.map( - (item: ChatItemType) => ({ - role: map[item.obj], - content: item.value - }) - ); - // console.log(formatPrompts); + // console.log(filterPrompts); // 计算温度 const temperature = modelConstantsData.maxTemperature * (model.temperature / 10); @@ -146,9 +140,8 @@ ${ const chatResponse = await chatAPI.createChatCompletion( { model: model.service.chatModel, - temperature: temperature, - // max_tokens: modelConstantsData.maxToken, - messages: formatPrompts, + temperature, + messages: filterPrompts, frequency_penalty: 0.5, // 越大,重复内容越少 presence_penalty: -0.5, // 越大,越容易出现新内容 stream: true @@ -170,14 +163,13 @@ ${ chatResponse }); - const promptsContent = formatPrompts.map((item) => item.content).join(''); // 只有使用平台的 key 才计费 pushChatBill({ isPay: !userApiKey, modelName: model.service.modelName, userId, chatId, - text: promptsContent + responseContent + messages: filterPrompts.concat({ role: 'assistant', content: responseContent }) }); // jsonRes(res); } catch (err: any) { diff --git a/src/pages/api/data/splitData.ts b/src/pages/api/data/splitData.ts index 13143ae6e..206578368 100644 --- a/src/pages/api/data/splitData.ts +++ b/src/pages/api/data/splitData.ts @@ -4,7 +4,7 @@ import { connectToDatabase, DataItem, Data } from '@/service/mongo'; import { authToken } from '@/service/utils/tools'; import { generateQA } from '@/service/events/generateQA'; import { generateAbstract } from '@/service/events/generateAbstract'; -import { encode } from 'gpt-token-utils'; +import { countChatTokens } from '@/utils/tools'; /* 拆分数据成QA */ export default async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -34,7 +34,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) chunks.forEach((chunk) => { splitText += chunk; - const tokens = encode(splitText).length; + const tokens = countChatTokens({ messages: [{ role: 'system', content: splitText }] }); if (tokens >= 780) { dataItems.push({ userId, diff --git a/src/pages/api/model/create.ts b/src/pages/api/model/create.ts index 928d2163d..f1a7e25e4 100644 --- a/src/pages/api/model/create.ts +++ b/src/pages/api/model/create.ts @@ -3,14 +3,14 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { connectToDatabase } from '@/service/mongo'; import { authToken } from '@/service/utils/tools'; -import { ModelStatusEnum, modelList, ChatModelNameEnum, ChatModelNameMap } from '@/constants/model'; +import { ModelStatusEnum, modelList, ModelNameEnum, Model2ChatModelMap } from '@/constants/model'; import { Model } from '@/service/models/model'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { const { name, serviceModelName } = req.body as { name: string; - serviceModelName: `${ChatModelNameEnum}`; + serviceModelName: `${ModelNameEnum}`; }; const { authorization } = req.headers; @@ -48,7 +48,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< status: ModelStatusEnum.running, service: { trainId: '', - chatModel: ChatModelNameMap[modelItem.model], // 聊天时用的模型 + chatModel: Model2ChatModelMap[modelItem.model], // 聊天时用的模型 modelName: modelItem.model // 最底层的模型,不会变,用于计费等核心操作 } }); diff --git a/src/pages/api/openapi/chat/chatGpt.ts b/src/pages/api/openapi/chat/chatGpt.ts index d162c6c2a..b06b1764b 100644 --- a/src/pages/api/openapi/chat/chatGpt.ts +++ b/src/pages/api/openapi/chat/chatGpt.ts @@ -75,21 +75,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } // 控制在 tokens 数量,防止超出 - const filterPrompts = openaiChatFilter(prompts, modelConstantsData.contextMaxToken); + const filterPrompts = openaiChatFilter({ + model: model.service.chatModel, + prompts, + maxTokens: modelConstantsData.contextMaxToken - 500 + }); - // 格式化文本内容成 chatgpt 格式 - const map = { - Human: ChatCompletionRequestMessageRoleEnum.User, - AI: ChatCompletionRequestMessageRoleEnum.Assistant, - SYSTEM: ChatCompletionRequestMessageRoleEnum.System - }; - const formatPrompts: ChatCompletionRequestMessage[] = filterPrompts.map( - (item: ChatItemType) => ({ - role: map[item.obj], - content: item.value - }) - ); - // console.log(formatPrompts); + // console.log(filterPrompts); // 计算温度 const temperature = modelConstantsData.maxTemperature * (model.temperature / 10); @@ -99,9 +91,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const chatResponse = await chatAPI.createChatCompletion( { model: model.service.chatModel, - temperature: temperature, - // max_tokens: modelConstantsData.maxToken, - messages: formatPrompts, + temperature, + messages: filterPrompts, frequency_penalty: 0.5, // 越大,重复内容越少 presence_penalty: -0.5, // 越大,越容易出现新内容 stream: isStream, @@ -133,14 +124,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }); } - const promptsContent = formatPrompts.map((item) => item.content).join(''); - // 只有使用平台的 key 才计费 pushChatBill({ isPay: true, modelName: model.service.modelName, userId, - text: promptsContent + responseContent + messages: filterPrompts.concat({ role: 'assistant', content: responseContent }) }); } catch (err: any) { if (step === 1) { diff --git a/src/pages/api/openapi/chat/lafGpt.ts b/src/pages/api/openapi/chat/lafGpt.ts index 8863e1f03..4619e6b38 100644 --- a/src/pages/api/openapi/chat/lafGpt.ts +++ b/src/pages/api/openapi/chat/lafGpt.ts @@ -3,15 +3,14 @@ import { connectToDatabase, Model } from '@/service/mongo'; import { getOpenAIApi } from '@/service/utils/auth'; import { authOpenApiKey } from '@/service/utils/tools'; import { httpsAgent, openaiChatFilter, systemPromptFilter } from '@/service/utils/tools'; -import { ChatCompletionRequestMessage, ChatCompletionRequestMessageRoleEnum } from 'openai'; import { ChatItemType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; import { - ChatModelNameEnum, + ModelNameEnum, modelList, - ChatModelNameMap, - ModelVectorSearchModeMap + ModelVectorSearchModeMap, + ChatModelEnum } from '@/constants/model'; import { pushChatBill } from '@/service/events/pushBill'; import { openaiCreateEmbedding, gpt35StreamResponse } from '@/service/utils/openai'; @@ -60,9 +59,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) throw new Error('找不到模型'); } - const modelConstantsData = modelList.find( - (item) => item.model === ChatModelNameEnum.VECTOR_GPT - ); + const modelConstantsData = modelList.find((item) => item.model === ModelNameEnum.VECTOR_GPT); if (!modelConstantsData) { throw new Error('模型已下架'); } @@ -74,7 +71,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) // 请求一次 chatgpt 拆解需求 const promptResponse = await chatAPI.createChatCompletion( { - model: ChatModelNameMap[ChatModelNameEnum.GPT35], + model: ChatModelEnum.GPT35, temperature: 0, frequency_penalty: 0.5, // 越大,重复内容越少 presence_penalty: -0.5, // 越大,越容易出现新内容 @@ -122,7 +119,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) ] }, { - timeout: 120000, + timeout: 180000, httpsAgent: httpsAgent(true) } ); @@ -163,30 +160,26 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const formatRedisPrompt: string[] = vectorSearch.rows.map((item) => `${item.q}\n${item.a}`); - // textArr 筛选,最多 2500 tokens - const systemPrompt = systemPromptFilter(formatRedisPrompt, 2500); + // system 筛选,最多 2500 tokens + const systemPrompt = systemPromptFilter({ + model: model.service.chatModel, + prompts: formatRedisPrompt, + maxTokens: 2500 + }); prompts.unshift({ obj: 'SYSTEM', value: `${model.systemPrompt} 知识库是最新的,下面是知识库内容:${systemPrompt}` }); - // 控制在 tokens 数量,防止超出 - const filterPrompts = openaiChatFilter(prompts, modelConstantsData.contextMaxToken); + // 控制上下文 tokens 数量,防止超出 + const filterPrompts = openaiChatFilter({ + model: model.service.chatModel, + prompts, + maxTokens: modelConstantsData.contextMaxToken - 500 + }); - // 格式化文本内容成 chatgpt 格式 - const map = { - Human: ChatCompletionRequestMessageRoleEnum.User, - AI: ChatCompletionRequestMessageRoleEnum.Assistant, - SYSTEM: ChatCompletionRequestMessageRoleEnum.System - }; - const formatPrompts: ChatCompletionRequestMessage[] = filterPrompts.map( - (item: ChatItemType) => ({ - role: map[item.obj], - content: item.value - }) - ); - // console.log(formatPrompts); + // console.log(filterPrompts); // 计算温度 const temperature = modelConstantsData.maxTemperature * (model.temperature / 10); @@ -195,13 +188,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) { model: model.service.chatModel, temperature, - messages: formatPrompts, + messages: filterPrompts, frequency_penalty: 0.5, // 越大,重复内容越少 presence_penalty: -0.5, // 越大,越容易出现新内容 stream: isStream }, { - timeout: 120000, + timeout: 180000, responseType: isStream ? 'stream' : 'json', httpsAgent: httpsAgent(true) } @@ -228,13 +221,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) console.log('laf gpt done. time:', `${(Date.now() - startTime) / 1000}s`); - const promptsContent = formatPrompts.map((item) => item.content).join(''); - pushChatBill({ isPay: true, modelName: model.service.modelName, userId, - text: promptsContent + responseContent + messages: filterPrompts.concat({ role: 'assistant', content: responseContent }) }); } catch (err: any) { if (step === 1) { diff --git a/src/pages/api/openapi/chat/vectorGpt.ts b/src/pages/api/openapi/chat/vectorGpt.ts index 759c9d345..ee80571be 100644 --- a/src/pages/api/openapi/chat/vectorGpt.ts +++ b/src/pages/api/openapi/chat/vectorGpt.ts @@ -126,8 +126,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }); } else { // 有匹配或者低匹配度模式情况下,添加知识库内容。 - // 系统提示词过滤,最多 3000 tokens - const systemPrompt = systemPromptFilter(formatRedisPrompt, 3000); + // 系统提示词过滤,最多 2500 tokens + const systemPrompt = systemPromptFilter({ + model: model.service.chatModel, + prompts: formatRedisPrompt, + maxTokens: 2500 + }); prompts.unshift({ obj: 'SYSTEM', @@ -144,21 +148,13 @@ ${ } // 控制在 tokens 数量,防止超出 - const filterPrompts = openaiChatFilter(prompts, modelConstantsData.contextMaxToken); + const filterPrompts = openaiChatFilter({ + model: model.service.chatModel, + prompts, + maxTokens: modelConstantsData.contextMaxToken - 500 + }); - // 格式化文本内容成 chatgpt 格式 - const map = { - Human: ChatCompletionRequestMessageRoleEnum.User, - AI: ChatCompletionRequestMessageRoleEnum.Assistant, - SYSTEM: ChatCompletionRequestMessageRoleEnum.System - }; - const formatPrompts: ChatCompletionRequestMessage[] = filterPrompts.map( - (item: ChatItemType) => ({ - role: map[item.obj], - content: item.value - }) - ); - // console.log(formatPrompts); + // console.log(filterPrompts); // 计算温度 const temperature = modelConstantsData.maxTemperature * (model.temperature / 10); @@ -166,14 +162,14 @@ ${ const chatResponse = await chatAPI.createChatCompletion( { model: model.service.chatModel, - temperature: temperature, - messages: formatPrompts, + temperature, + messages: filterPrompts, frequency_penalty: 0.5, // 越大,重复内容越少 presence_penalty: -0.5, // 越大,越容易出现新内容 stream: isStream }, { - timeout: 120000, + timeout: 180000, responseType: isStream ? 'stream' : 'json', httpsAgent: httpsAgent(true) } @@ -198,12 +194,11 @@ ${ }); } - const promptsContent = formatPrompts.map((item) => item.content).join(''); pushChatBill({ isPay: true, modelName: model.service.modelName, userId, - text: promptsContent + responseContent + messages: filterPrompts.concat({ role: 'assistant', content: responseContent }) }); // jsonRes(res); } catch (err: any) { diff --git a/src/pages/chat/index.tsx b/src/pages/chat/index.tsx index 394e9b2aa..f8759640e 100644 --- a/src/pages/chat/index.tsx +++ b/src/pages/chat/index.tsx @@ -21,7 +21,7 @@ import { import { useToast } from '@/hooks/useToast'; import { useScreen } from '@/hooks/useScreen'; import { useQuery } from '@tanstack/react-query'; -import { ChatModelNameEnum } from '@/constants/model'; +import { ModelNameEnum } from '@/constants/model'; import dynamic from 'next/dynamic'; import { useGlobalStore } from '@/store/global'; import { useCopyData } from '@/utils/tools'; @@ -178,8 +178,8 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => { const gptChatPrompt = useCallback( async (prompts: ChatSiteItemType) => { const urlMap: Record = { - [ChatModelNameEnum.GPT35]: '/api/chat/chatGpt', - [ChatModelNameEnum.VECTOR_GPT]: '/api/chat/vectorGpt' + [ModelNameEnum.GPT35]: '/api/chat/chatGpt', + [ModelNameEnum.VECTOR_GPT]: '/api/chat/vectorGpt' }; if (!urlMap[chatData.modelName]) return Promise.reject('找不到模型'); diff --git a/src/pages/data/components/CreateDataModal.tsx b/src/pages/data/components/CreateDataModal.tsx deleted file mode 100644 index 85e56eeda..000000000 --- a/src/pages/data/components/CreateDataModal.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React, { useState } from 'react'; -import { - Modal, - ModalOverlay, - ModalContent, - ModalHeader, - ModalFooter, - ModalBody, - ModalCloseButton, - Button, - Input, - Select, - FormControl, - FormErrorMessage -} from '@chakra-ui/react'; -import { postData } from '@/api/data'; -import { useMutation } from '@tanstack/react-query'; -import { useForm, SubmitHandler } from 'react-hook-form'; -import { DataType } from '@/types/data'; -import { DataTypeTextMap } from '@/constants/data'; - -export interface CreateDataProps { - name: string; - type: DataType; -} - -const CreateDataModal = ({ - onClose, - onSuccess -}: { - onClose: () => void; - onSuccess: () => void; -}) => { - const [inputVal, setInputVal] = useState(''); - const { - getValues, - register, - handleSubmit, - formState: { errors } - } = useForm({ - defaultValues: { - name: '', - type: 'abstract' - } - }); - - const { isLoading, mutate } = useMutation({ - mutationFn: (e: CreateDataProps) => postData(e), - onSuccess() { - onSuccess(); - onClose(); - } - }); - - return ( - - - - 创建数据集 - - - - - - - {!!errors.name && errors.name.message} - - - - - - - - - - - - - ); -}; - -export default CreateDataModal; diff --git a/src/pages/data/components/ImportDataModal.tsx b/src/pages/data/components/ImportDataModal.tsx deleted file mode 100644 index 558493c3b..000000000 --- a/src/pages/data/components/ImportDataModal.tsx +++ /dev/null @@ -1,229 +0,0 @@ -import React, { useState, useCallback } from 'react'; -import { - Modal, - ModalOverlay, - ModalContent, - ModalHeader, - ModalFooter, - ModalBody, - ModalCloseButton, - Button, - Box, - Flex, - Textarea -} from '@chakra-ui/react'; -import { useTabs } from '@/hooks/useTabs'; -import { useConfirm } from '@/hooks/useConfirm'; -import { useSelectFile } from '@/hooks/useSelectFile'; -import { readTxtContent, readPdfContent, readDocContent } from '@/utils/file'; -import { postSplitData } from '@/api/data'; -import { useMutation } from '@tanstack/react-query'; -import { useToast } from '@/hooks/useToast'; -import { useLoading } from '@/hooks/useLoading'; -import { formatPrice } from '@/utils/user'; -import { modelList, ChatModelNameEnum } from '@/constants/model'; -import { encode } from 'gpt-token-utils'; - -const fileExtension = '.txt,.doc,.docx,.pdf,.md'; - -const ImportDataModal = ({ - dataId, - onClose, - onSuccess -}: { - dataId: string; - onClose: () => void; - onSuccess: () => void; -}) => { - const { openConfirm, ConfirmChild } = useConfirm({ - content: '确认提交生成任务?该任务无法终止!' - }); - const { toast } = useToast(); - const { setIsLoading, Loading } = useLoading(); - const { File, onOpen } = useSelectFile({ fileType: fileExtension, multiple: true }); - const { tabs, activeTab, setActiveTab } = useTabs({ - tabs: [ - { id: 'text', label: '文本' }, - { id: 'doc', label: '文件' } - // { id: 'url', label: '链接' } - ] - }); - - const [textInput, setTextInput] = useState(''); - const [fileText, setFileText] = useState(''); - - const { mutate: handleClickSubmit, isLoading } = useMutation({ - mutationFn: async () => { - let text = ''; - if (activeTab === 'text') { - text = textInput; - } else if (activeTab === 'doc') { - text = fileText; - } else if (activeTab === 'url') { - } - if (!text) return; - return postSplitData(dataId, text); - }, - onSuccess() { - toast({ - title: '任务提交成功', - status: 'success' - }); - onClose(); - onSuccess(); - }, - onError(err: any) { - toast({ - title: err?.message || '提交任务异常', - status: 'error' - }); - } - }); - - const onSelectFile = useCallback( - async (e: File[]) => { - setIsLoading(true); - try { - const fileTexts = ( - await Promise.all( - e.map((file) => { - // @ts-ignore - const extension = file?.name?.split('.').pop().toLowerCase(); - switch (extension) { - case 'txt': - case 'md': - return readTxtContent(file); - case 'pdf': - return readPdfContent(file); - case 'doc': - case 'docx': - return readDocContent(file); - default: - return ''; - } - }) - ) - ) - .join('\n') - .replace(/\n+/g, '\n'); - setFileText(fileTexts); - console.log(encode(fileTexts)); - } catch (error: any) { - console.log(error); - toast({ - title: typeof error === 'string' ? error : '解析文件失败', - status: 'error' - }); - } - setIsLoading(false); - }, - [setIsLoading, toast] - ); - - return ( - - - - - 导入数据,生成QA - - {formatPrice( - modelList.find((item) => item.model === ChatModelNameEnum.GPT35)?.price || 0, - 1000 - )} - 元/1K tokens - - - - - - - {tabs.map((item) => ( - - ))} - - - - {activeTab === 'text' && ( - <> -