mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 21:13:50 +00:00
perf: 加快拆分QA和生成向量;余额不足提醒
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@/service/response';
|
import { jsonRes } from '@/service/response';
|
||||||
import { connectToDatabase, DataItem, Data } from '@/service/mongo';
|
import { connectToDatabase, SplitData } from '@/service/mongo';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
try {
|
try {
|
||||||
@@ -10,20 +10,18 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
}
|
}
|
||||||
await connectToDatabase();
|
await connectToDatabase();
|
||||||
|
|
||||||
// await DataItem.updateMany(
|
const data = await SplitData.aggregate([
|
||||||
// {},
|
{ $match: { textList: { $exists: true, $ne: [] } } },
|
||||||
// {
|
{ $sample: { size: 1 } }
|
||||||
// type: 'QA'
|
]);
|
||||||
// // times: 2
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
await Data.updateMany(
|
const dataItem: any = data[0];
|
||||||
{},
|
const textList: string[] = dataItem.textList.slice(-5);
|
||||||
{
|
console.log(textList);
|
||||||
type: 'QA'
|
console.log(dataItem.textList.slice(0, -5));
|
||||||
}
|
await SplitData.findByIdAndUpdate(dataItem._id, {
|
||||||
);
|
textList: dataItem.textList.slice(0, -5)
|
||||||
|
});
|
||||||
|
|
||||||
jsonRes(res, {
|
jsonRes(res, {
|
||||||
data: {}
|
data: {}
|
@@ -6,6 +6,9 @@ export const openaiError: Record<string, string> = {
|
|||||||
'Too Many Requests': '请求次数太多了,请慢点~',
|
'Too Many Requests': '请求次数太多了,请慢点~',
|
||||||
'Bad Gateway': '网关异常,请重试'
|
'Bad Gateway': '网关异常,请重试'
|
||||||
};
|
};
|
||||||
|
export const openaiError2: Record<string, string> = {
|
||||||
|
insufficient_quota: 'API 余额不足'
|
||||||
|
};
|
||||||
export const proxyError: Record<string, boolean> = {
|
export const proxyError: Record<string, boolean> = {
|
||||||
ECONNABORTED: true,
|
ECONNABORTED: true,
|
||||||
ECONNRESET: true
|
ECONNRESET: true
|
||||||
|
@@ -9,39 +9,35 @@ import { generateVector } from './generateVector';
|
|||||||
import { connectRedis } from '../redis';
|
import { connectRedis } from '../redis';
|
||||||
import { VecModelDataPrefix } from '@/constants/redis';
|
import { VecModelDataPrefix } from '@/constants/redis';
|
||||||
import { customAlphabet } from 'nanoid';
|
import { customAlphabet } from 'nanoid';
|
||||||
|
import { ModelSplitDataSchema } from '@/types/mongoSchema';
|
||||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
||||||
|
|
||||||
export async function generateQA(): Promise<any> {
|
export async function generateQA(next = false): Promise<any> {
|
||||||
// 最多 5 个进程
|
if (global.generatingQA === true && !next) return;
|
||||||
if (global.generatingQA >= 5) {
|
global.generatingQA = true;
|
||||||
console.log('QA 最多5个进程');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
global.generatingQA++;
|
|
||||||
|
|
||||||
let dataId = null;
|
let dataId = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const redis = await connectRedis();
|
const redis = await connectRedis();
|
||||||
// 找出一个需要生成的 dataItem
|
// 找出一个需要生成的 dataItem
|
||||||
const dataItem = await SplitData.findOne({
|
const data = await SplitData.aggregate([
|
||||||
textList: { $exists: true, $ne: [] }
|
{ $match: { textList: { $exists: true, $ne: [] } } },
|
||||||
});
|
{ $sample: { size: 1 } }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const dataItem: ModelSplitDataSchema = data[0];
|
||||||
|
|
||||||
if (!dataItem) {
|
if (!dataItem) {
|
||||||
console.log('没有需要生成 QA 的数据');
|
console.log('没有需要生成 QA 的数据');
|
||||||
global.generatingQA = 0;
|
global.generatingQA = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dataId = dataItem._id;
|
dataId = dataItem._id;
|
||||||
|
|
||||||
// 源文本
|
// 获取 5 个源文本
|
||||||
const text = dataItem.textList[dataItem.textList.length - 1];
|
const textList: string[] = dataItem.textList.slice(-5);
|
||||||
if (!text) {
|
|
||||||
await SplitData.findByIdAndUpdate(dataItem._id, { $pop: { textList: 1 } }); // 弹出无效文本
|
|
||||||
throw new Error('无文本');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取 openapi Key
|
// 获取 openapi Key
|
||||||
let userApiKey, systemKey;
|
let userApiKey, systemKey;
|
||||||
@@ -62,7 +58,7 @@ export async function generateQA(): Promise<any> {
|
|||||||
throw new Error('获取 openai key 失败');
|
throw new Error('获取 openai key 失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('正在生成一组QA, ID:', dataItem._id);
|
console.log(`正在生成一组QA, 包含 ${textList.length} 组文本。ID: ${dataItem._id}`);
|
||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
@@ -76,33 +72,50 @@ export async function generateQA(): Promise<any> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 请求 chatgpt 获取回答
|
// 请求 chatgpt 获取回答
|
||||||
const response = await chatAPI
|
const response = await Promise.allSettled(
|
||||||
.createChatCompletion(
|
textList.map((text) =>
|
||||||
{
|
chatAPI
|
||||||
model: ChatModelNameEnum.GPT35,
|
.createChatCompletion(
|
||||||
temperature: 0.8,
|
|
||||||
n: 1,
|
|
||||||
messages: [
|
|
||||||
systemPrompt,
|
|
||||||
{
|
{
|
||||||
role: 'user',
|
model: ChatModelNameEnum.GPT35,
|
||||||
content: text
|
temperature: 0.8,
|
||||||
|
n: 1,
|
||||||
|
messages: [
|
||||||
|
systemPrompt,
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content: text
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timeout: 180000,
|
||||||
|
httpsAgent
|
||||||
}
|
}
|
||||||
]
|
)
|
||||||
},
|
.then((res) => ({
|
||||||
{
|
rawContent: res?.data.choices[0].message?.content || '', // chatgpt原本的回复
|
||||||
timeout: 180000,
|
result: splitText(res?.data.choices[0].message?.content || '') // 格式化后的QA对
|
||||||
httpsAgent
|
}))
|
||||||
}
|
|
||||||
)
|
)
|
||||||
.then((res) => ({
|
);
|
||||||
rawContent: res?.data.choices[0].message?.content || '', // chatgpt原本的回复
|
|
||||||
result: splitText(res?.data.choices[0].message?.content || '') // 格式化后的QA对
|
// 获取成功的回答
|
||||||
}));
|
const successResponse: {
|
||||||
|
rawContent: string;
|
||||||
|
result: {
|
||||||
|
q: string;
|
||||||
|
a: string;
|
||||||
|
}[];
|
||||||
|
}[] = response.filter((item) => item.status === 'fulfilled').map((item: any) => item.value);
|
||||||
|
|
||||||
|
const resultList = successResponse.map((item) => item.result).flat();
|
||||||
|
|
||||||
await Promise.allSettled([
|
await Promise.allSettled([
|
||||||
SplitData.findByIdAndUpdate(dataItem._id, { $pop: { textList: 1 } }), // 弹出已经拆分的文本
|
SplitData.findByIdAndUpdate(dataItem._id, {
|
||||||
...response.result.map((item) => {
|
textList: dataItem.textList.slice(0, -5)
|
||||||
|
}), // 删掉后5个数据
|
||||||
|
...resultList.map((item) => {
|
||||||
// 插入 redis
|
// 插入 redis
|
||||||
return redis.sendCommand([
|
return redis.sendCommand([
|
||||||
'HMSET',
|
'HMSET',
|
||||||
@@ -125,20 +138,21 @@ export async function generateQA(): Promise<any> {
|
|||||||
'生成QA成功,time:',
|
'生成QA成功,time:',
|
||||||
`${(Date.now() - startTime) / 1000}s`,
|
`${(Date.now() - startTime) / 1000}s`,
|
||||||
'QA数量:',
|
'QA数量:',
|
||||||
response.result.length
|
resultList.length
|
||||||
);
|
);
|
||||||
|
|
||||||
// 计费
|
// 计费
|
||||||
pushSplitDataBill({
|
pushSplitDataBill({
|
||||||
isPay: !userApiKey && response.result.length > 0,
|
isPay: !userApiKey && resultList.length > 0,
|
||||||
userId: dataItem.userId,
|
userId: dataItem.userId,
|
||||||
type: 'QA',
|
type: 'QA',
|
||||||
text: systemPrompt.content + text + response.rawContent
|
text:
|
||||||
|
systemPrompt.content +
|
||||||
|
textList.join('') +
|
||||||
|
successResponse.map((item) => item.rawContent).join('')
|
||||||
});
|
});
|
||||||
|
|
||||||
global.generatingQA--;
|
generateQA(true);
|
||||||
|
|
||||||
generateQA();
|
|
||||||
generateVector();
|
generateVector();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
// log
|
// log
|
||||||
@@ -157,14 +171,13 @@ export async function generateQA(): Promise<any> {
|
|||||||
errorText: 'api 余额不足'
|
errorText: 'api 余额不足'
|
||||||
});
|
});
|
||||||
|
|
||||||
generateQA();
|
generateQA(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
global.generatingQA--;
|
generateQA(true);
|
||||||
generateQA();
|
}, 4000);
|
||||||
}, 5000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -75,9 +75,7 @@ export async function generateVector(next = false): Promise<any> {
|
|||||||
|
|
||||||
console.log(`生成向量成功: ${dataItem.id}`);
|
console.log(`生成向量成功: ${dataItem.id}`);
|
||||||
|
|
||||||
setTimeout(() => {
|
generateVector(true);
|
||||||
generateVector(true);
|
|
||||||
}, 4000);
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
// log
|
// log
|
||||||
if (error?.response) {
|
if (error?.response) {
|
||||||
@@ -88,7 +86,7 @@ export async function generateVector(next = false): Promise<any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dataId && error?.response?.data?.error?.type === 'insufficient_quota') {
|
if (dataId && error?.response?.data?.error?.type === 'insufficient_quota') {
|
||||||
console.log('api 余额不足');
|
console.log('api 余额不足,删除 redis 模型数据');
|
||||||
const redis = await connectRedis();
|
const redis = await connectRedis();
|
||||||
redis.del(dataId);
|
redis.del(dataId);
|
||||||
generateVector(true);
|
generateVector(true);
|
||||||
|
@@ -27,7 +27,6 @@ export async function connectToDatabase(): Promise<void> {
|
|||||||
global.mongodb = null;
|
global.mongodb = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
global.generatingQA = 0;
|
|
||||||
generateQA();
|
generateQA();
|
||||||
// generateAbstract();
|
// generateAbstract();
|
||||||
generateVector(true);
|
generateVector(true);
|
||||||
|
@@ -1,21 +0,0 @@
|
|||||||
import { ChatItemType } from '../types/chat';
|
|
||||||
|
|
||||||
export const chatWindows = new Map<string, ChatItemType[]>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取聊天窗口信息
|
|
||||||
*/
|
|
||||||
export const getWindowMessages = (id: string) => {
|
|
||||||
return chatWindows.get(id) || [];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const pushWindowMessage = (id: string, prompt: ChatItemType) => {
|
|
||||||
const messages = chatWindows.get(id) || [];
|
|
||||||
messages.push(prompt);
|
|
||||||
chatWindows.set(id, messages);
|
|
||||||
return messages;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteWindow = (id: string) => {
|
|
||||||
chatWindows.delete(id);
|
|
||||||
};
|
|
@@ -1,5 +1,5 @@
|
|||||||
import { NextApiResponse } from 'next';
|
import { NextApiResponse } from 'next';
|
||||||
import { openaiError, proxyError } from './errorCode';
|
import { openaiError, openaiError2, proxyError } from './errorCode';
|
||||||
|
|
||||||
export interface ResponseType<T = any> {
|
export interface ResponseType<T = any> {
|
||||||
code: number;
|
code: number;
|
||||||
@@ -25,13 +25,19 @@ export const jsonRes = <T = any>(
|
|||||||
msg = error;
|
msg = error;
|
||||||
} else if (proxyError[error?.code]) {
|
} else if (proxyError[error?.code]) {
|
||||||
msg = '服务器代理出错';
|
msg = '服务器代理出错';
|
||||||
|
} else if (openaiError2[error?.response?.data?.error?.type]) {
|
||||||
|
msg = openaiError2[error?.response?.data?.error?.type];
|
||||||
} else if (openaiError[error?.response?.statusText]) {
|
} else if (openaiError[error?.response?.statusText]) {
|
||||||
msg = openaiError[error.response.statusText];
|
msg = openaiError[error.response.statusText];
|
||||||
}
|
}
|
||||||
console.log('error->');
|
console.log('error->');
|
||||||
console.log('code:', error.code);
|
console.log('code:', error.code);
|
||||||
console.log('statusText:', error?.response?.statusText);
|
|
||||||
console.log('msg:', msg);
|
console.log('msg:', msg);
|
||||||
|
// request 时候报错
|
||||||
|
if (error?.response) {
|
||||||
|
console.log('statusText:', error?.response?.statusText);
|
||||||
|
console.log('type:', error?.response?.data?.error?.type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
|
2
src/types/index.d.ts
vendored
2
src/types/index.d.ts
vendored
@@ -4,7 +4,7 @@ import type { RedisClientType } from 'redis';
|
|||||||
declare global {
|
declare global {
|
||||||
var mongodb: Mongoose | string | null;
|
var mongodb: Mongoose | string | null;
|
||||||
var redisClient: RedisClientType | null;
|
var redisClient: RedisClientType | null;
|
||||||
var generatingQA: number;
|
var generatingQA: boolean;
|
||||||
var generatingAbstract: boolean;
|
var generatingAbstract: boolean;
|
||||||
var generatingVector: boolean;
|
var generatingVector: boolean;
|
||||||
var QRCode: any;
|
var QRCode: any;
|
||||||
|
Reference in New Issue
Block a user