This commit is contained in:
archer
2023-07-01 13:09:02 +08:00
parent 4c54e1821b
commit 9bdd5f522d
85 changed files with 4738 additions and 1236 deletions

View File

@@ -12,6 +12,7 @@ interface Props {
export const moduleFetch = ({ url, data, res }: Props) =>
new Promise<Record<string, any>>(async (resolve, reject) => {
try {
const abortSignal = new AbortController();
const baseUrl = `http://localhost:3000/api`;
const requestUrl = url.startsWith('/') ? `${baseUrl}${url}` : url;
const response = await fetch(requestUrl, {
@@ -19,9 +20,15 @@ export const moduleFetch = ({ url, data, res }: Props) =>
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
body: JSON.stringify(data),
signal: abortSignal.signal
});
if (response.status >= 300 || response.status < 200) {
const err = await response.json();
return reject(err);
}
if (!response?.body) {
throw new Error('Request Error');
}
@@ -34,14 +41,19 @@ export const moduleFetch = ({ url, data, res }: Props) =>
const reader = response.body?.getReader();
let chatResponse = {};
let chatResponse: Record<string, any> = {};
const read = async () => {
try {
const { done, value } = await reader.read();
if (done) {
return resolve(chatResponse);
} else if (res.closed) {
resolve(chatResponse);
abortSignal.abort();
return;
}
const chunkResponse = parseStreamChunk(value);
chunkResponse.forEach((item) => {
@@ -53,12 +65,25 @@ export const moduleFetch = ({ url, data, res }: Props) =>
return {};
}
})();
if (item.event === sseResponseEventEnum.moduleFetchResponse) {
if (!res.closed && item.event === sseResponseEventEnum.moduleFetchResponse) {
chatResponse = {
...chatResponse,
...data
};
} else if (item.event === sseResponseEventEnum.answer && data?.choices?.[0]?.delta) {
} else if (
!res.closed &&
item.event === sseResponseEventEnum.answer &&
data?.choices?.[0]?.delta
) {
// save answer
const answer: string = data?.choices?.[0].delta.content || '';
if (answer) {
chatResponse = {
...chatResponse,
answer: chatResponse.answer ? chatResponse.answer + answer : answer
};
}
sseResponse({
res,
event: sseResponseEventEnum.answer,
@@ -68,6 +93,9 @@ export const moduleFetch = ({ url, data, res }: Props) =>
});
read();
} catch (err: any) {
if (err?.message === 'The operation was aborted.') {
return;
}
reject(getErrText(err, '请求异常'));
}
};

View File

@@ -1,8 +1,8 @@
import { Schema, model, models, Model as MongoModel } from 'mongoose';
import { ModelSchema as ModelType } from '@/types/mongoSchema';
import { AppSchema as ModelType } from '@/types/mongoSchema';
import { ChatModelMap, OpenAiChatEnum } from '@/constants/model';
const ModelSchema = new Schema({
const AppSchema = new Schema({
userId: {
type: Schema.Types.ObjectId,
ref: 'user',
@@ -91,14 +91,18 @@ const ModelSchema = new Schema({
type: Number,
default: 0
}
},
modules: {
type: Array,
default: []
}
});
try {
ModelSchema.index({ updateTime: -1 });
ModelSchema.index({ 'share.collection': -1 });
AppSchema.index({ updateTime: -1 });
AppSchema.index({ 'share.collection': -1 });
} catch (error) {
console.log(error);
}
export const Model: MongoModel<ModelType> = models['model'] || model('model', ModelSchema);
export const Model: MongoModel<ModelType> = models['model'] || model('model', AppSchema);

View File

@@ -55,7 +55,7 @@ export const jsonRes = <T = any>(
console.log(error);
}
res.json({
res.status(code).json({
code,
statusText: '',
message: msg,
@@ -92,7 +92,7 @@ export const sseErrRes = (res: NextApiResponse, error: any) => {
} else if (openaiError[error?.response?.statusText]) {
msg = openaiError[error.response.statusText];
}
console.log(error);
console.log('sse error', error);
sseResponse({
res,

View File

@@ -2,10 +2,10 @@ import type { NextApiRequest } from 'next';
import jwt from 'jsonwebtoken';
import Cookie from 'cookie';
import { Chat, Model, OpenApi, User, ShareChat, KB } from '../mongo';
import type { ModelSchema } from '@/types/mongoSchema';
import type { AppSchema } from '@/types/mongoSchema';
import type { ChatItemType } from '@/types/chat';
import mongoose from 'mongoose';
import { defaultModel } from '@/constants/model';
import { defaultApp } from '@/constants/model';
import { formatPrice } from '@/utils/user';
import { ERROR_ENUM } from '../errorCode';
import { ChatModelType, OpenAiChatEnum } from '@/constants/model';
@@ -204,22 +204,22 @@ export const getApiKey = async ({
};
// 模型使用权校验
export const authModel = async ({
modelId,
export const authApp = async ({
appId,
userId,
authUser = true,
authOwner = true,
reserveDetail = false
}: {
modelId: string;
appId: string;
userId: string;
authUser?: boolean;
authOwner?: boolean;
reserveDetail?: boolean; // focus reserve detail
}) => {
// 获取 model 数据
const model = await Model.findById<ModelSchema>(modelId);
if (!model) {
const app = await Model.findById<AppSchema>(appId);
if (!app) {
return Promise.reject('模型不存在');
}
@@ -228,21 +228,21 @@ export const authModel = async ({
1. authOwner=true or authUser = true , just owner can use
2. authUser = false and share, anyone can use
*/
if (authOwner || (authUser && !model.share.isShare)) {
if (userId !== String(model.userId)) return Promise.reject(ERROR_ENUM.unAuthModel);
if (authOwner || (authUser && !app.share.isShare)) {
if (userId !== String(app.userId)) return Promise.reject(ERROR_ENUM.unAuthModel);
}
// do not share detail info
if (!reserveDetail && !model.share.isShareDetail && userId !== String(model.userId)) {
model.chat = {
...defaultModel.chat,
chatModel: model.chat.chatModel
if (!reserveDetail && !app.share.isShareDetail && userId !== String(app.userId)) {
app.chat = {
...defaultApp.chat,
chatModel: app.chat.chatModel
};
}
return {
model,
showModelDetail: userId === String(model.userId)
app,
showModelDetail: userId === String(app.userId)
};
};
@@ -270,9 +270,9 @@ export const authChat = async ({
}) => {
const { userId } = await authUser({ req, authToken: true });
// 获取 model 数据
const { model, showModelDetail } = await authModel({
modelId,
// 获取 app 数据
const { app, showModelDetail } = await authApp({
appId: modelId,
userId,
authOwner: false,
reserveDetail: true
@@ -304,7 +304,7 @@ export const authChat = async ({
}
// 获取 user 的 apiKey
const { userOpenAiKey, systemAuthKey } = await getApiKey({
model: model.chat.chatModel,
model: app.chat.chatModel,
userId
});
@@ -313,7 +313,7 @@ export const authChat = async ({
systemAuthKey,
content,
userId,
model,
model: app,
showModelDetail
};
};