fix: conflict
This commit is contained in:
129
src/service/events/generateQA.ts
Normal file
129
src/service/events/generateQA.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { DataItem } from '@/service/mongo';
|
||||
import { getOpenAIApi } from '@/service/utils/chat';
|
||||
import { httpsAgent, getOpenApiKey } from '@/service/utils/tools';
|
||||
import type { ChatCompletionRequestMessage } from 'openai';
|
||||
import { DataItemSchema } from '@/types/mongoSchema';
|
||||
import { ChatModelNameEnum } from '@/constants/model';
|
||||
|
||||
export async function generateQA(next = false): Promise<any> {
|
||||
if (global.generatingQA && !next) return;
|
||||
global.generatingQA = true;
|
||||
|
||||
const systemPrompt: ChatCompletionRequestMessage = {
|
||||
role: 'system',
|
||||
content: `总结助手。我会向你发送一段长文本,请从中总结出10个问题和答案,答案请尽量详细,请按以下格式返回:
|
||||
"Q1:"
|
||||
"A1:"
|
||||
"Q2:"
|
||||
"A2:"
|
||||
`
|
||||
};
|
||||
let dataItem: DataItemSchema | null = null;
|
||||
|
||||
try {
|
||||
// 找出一个需要生成的 dataItem
|
||||
dataItem = await DataItem.findOne({
|
||||
status: 1,
|
||||
times: { $gt: 0 }
|
||||
});
|
||||
|
||||
if (!dataItem) {
|
||||
console.log('没有需要生成 QA 的数据');
|
||||
global.generatingQA = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 减少一次重试次数, 并更新状态为生成中
|
||||
await DataItem.findByIdAndUpdate(dataItem._id, {
|
||||
status: 2,
|
||||
$inc: {
|
||||
time: -1
|
||||
}
|
||||
});
|
||||
|
||||
// 获取 openapi Key
|
||||
let userApiKey, systemKey;
|
||||
try {
|
||||
const key = await getOpenApiKey(dataItem.userId);
|
||||
userApiKey = key.userApiKey;
|
||||
systemKey = key.systemKey;
|
||||
} catch (error) {
|
||||
// 余额不够了, 把用户所有记录改成闲置
|
||||
await DataItem.updateMany({
|
||||
userId: dataItem.userId,
|
||||
status: 0
|
||||
});
|
||||
throw new Error('获取 openai key 失败');
|
||||
}
|
||||
|
||||
console.log('正在生成一个QA', dataItem._id);
|
||||
const startTime = Date.now();
|
||||
|
||||
// 获取 openai 请求实例
|
||||
const chatAPI = getOpenAIApi(userApiKey || systemKey);
|
||||
// 请求 chatgpt 获取回答
|
||||
const response = await chatAPI.createChatCompletion(
|
||||
{
|
||||
model: ChatModelNameEnum.GPT35,
|
||||
temperature: dataItem.temperature,
|
||||
n: 1,
|
||||
messages: [
|
||||
systemPrompt,
|
||||
{
|
||||
role: 'user',
|
||||
content: dataItem.text
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
timeout: 60000,
|
||||
httpsAgent
|
||||
}
|
||||
);
|
||||
const content = response.data.choices[0].message?.content;
|
||||
// 从 content 中提取 QA
|
||||
const splitResponse = splitText(content || '');
|
||||
if (splitResponse.length > 0) {
|
||||
// 插入数据库,并修改状态
|
||||
await DataItem.findByIdAndUpdate(dataItem._id, {
|
||||
status: 0,
|
||||
$push: {
|
||||
result: {
|
||||
$each: splitResponse
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log('生成成功,time:', `${(Date.now() - startTime) / 1000}s`);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('error: 生成QA错误', dataItem?._id);
|
||||
console.log('statusText:', error?.response?.statusText);
|
||||
// 重置状态
|
||||
if (dataItem?._id) {
|
||||
await DataItem.findByIdAndUpdate(dataItem._id, {
|
||||
status: dataItem.times > 0 ? 1 : 0 // 还有重试次数则可以继续进行
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
generateQA(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文本是否按格式返回
|
||||
*/
|
||||
function splitText(text: string) {
|
||||
const regex = /Q\d+:\s(.+)?\nA\d+:\s(.+)?/g; // 匹配Q和A的正则表达式
|
||||
const matches = text.matchAll(regex); // 获取所有匹配到的结果
|
||||
|
||||
const result = []; // 存储最终的结果
|
||||
for (const match of matches) {
|
||||
const q = match[1];
|
||||
const a = match[2];
|
||||
if (q && a) {
|
||||
result.push({ q, a }); // 如果Q和A都存在,就将其添加到结果中
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -27,6 +27,8 @@ export const pushBill = async ({
|
||||
// 插入 Bill 记录
|
||||
const res = await Bill.create({
|
||||
userId,
|
||||
type: 'chat',
|
||||
modelName: modelItem.model,
|
||||
chatId,
|
||||
textLen,
|
||||
price
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Schema, model, models } from 'mongoose';
|
||||
import { ModelList } from '@/constants/model';
|
||||
|
||||
const BillSchema = new Schema({
|
||||
userId: {
|
||||
@@ -6,6 +7,16 @@ const BillSchema = new Schema({
|
||||
ref: 'user',
|
||||
required: true
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
enum: ['chat', 'generateData', 'return'],
|
||||
required: true
|
||||
},
|
||||
modelName: {
|
||||
type: String,
|
||||
enum: ModelList.map((item) => item.model),
|
||||
required: true
|
||||
},
|
||||
chatId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'chat',
|
||||
|
||||
@@ -6,21 +6,13 @@ const DataSchema = new Schema({
|
||||
ref: 'user',
|
||||
required: true
|
||||
},
|
||||
docId: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
createTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
},
|
||||
q: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
a: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
48
src/service/models/dataItem.ts
Normal file
48
src/service/models/dataItem.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { Schema, model, models } from 'mongoose';
|
||||
|
||||
const DataItemSchema = new Schema({
|
||||
userId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'user',
|
||||
required: true
|
||||
},
|
||||
dataId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'data',
|
||||
required: true
|
||||
},
|
||||
times: {
|
||||
type: Number,
|
||||
default: 3
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
temperature: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
result: {
|
||||
type: [
|
||||
{
|
||||
q: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
a: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
],
|
||||
default: []
|
||||
},
|
||||
status: {
|
||||
// 0-闲置,1-待生成,2-生成中
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
});
|
||||
|
||||
export const DataItem = models['dataItem'] || model('dataItem', DataItemSchema);
|
||||
@@ -1,5 +1,5 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
import { generateQA } from './events/generateQA';
|
||||
/**
|
||||
* 连接 MongoDB 数据库
|
||||
*/
|
||||
@@ -23,6 +23,9 @@ export async function connectToDatabase(): Promise<void> {
|
||||
console.log('error->', 'mongo connect error');
|
||||
global.mongodb = null;
|
||||
}
|
||||
|
||||
// 递归 QA 生成
|
||||
generateQA();
|
||||
}
|
||||
|
||||
export * from './models/authCode';
|
||||
@@ -33,3 +36,4 @@ export * from './models/training';
|
||||
export * from './models/bill';
|
||||
export * from './models/pay';
|
||||
export * from './models/data';
|
||||
export * from './models/dataItem';
|
||||
|
||||
@@ -55,8 +55,7 @@ export const getUserOpenaiKey = async (userId: string) => {
|
||||
};
|
||||
|
||||
/* 获取key,如果没有就用平台的,用平台记得加账单 */
|
||||
export const getOpenApiKey = async (authorization?: string) => {
|
||||
const userId = await authToken(authorization);
|
||||
export const getOpenApiKey = async (userId: string) => {
|
||||
const user = await User.findById<UserModelSchema>(userId);
|
||||
|
||||
if (!user) return Promise.reject('用户不存在');
|
||||
@@ -66,7 +65,6 @@ export const getOpenApiKey = async (authorization?: string) => {
|
||||
// 有自己的key, 直接使用
|
||||
if (userApiKey) {
|
||||
return {
|
||||
userId,
|
||||
userApiKey: await getUserOpenaiKey(userId),
|
||||
systemKey: ''
|
||||
};
|
||||
@@ -78,7 +76,6 @@ export const getOpenApiKey = async (authorization?: string) => {
|
||||
}
|
||||
|
||||
return {
|
||||
userId,
|
||||
userApiKey: '',
|
||||
systemKey: process.env.OPENAIKEY as string
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user