mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-30 10:28:42 +00:00
feat: v4
This commit is contained in:
@@ -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, '请求异常'));
|
||||
}
|
||||
};
|
||||
|
@@ -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);
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
};
|
||||
};
|
||||
|
Reference in New Issue
Block a user