feat: gridfs save file

This commit is contained in:
archer
2023-09-01 17:43:31 +08:00
parent 1fe2c49204
commit 5157e62fed
15 changed files with 467 additions and 88 deletions

View File

@@ -39,7 +39,8 @@ export enum ERROR_ENUM {
unAuthorization = 'unAuthorization',
insufficientQuota = 'insufficientQuota',
unAuthModel = 'unAuthModel',
unAuthKb = 'unAuthKb'
unAuthKb = 'unAuthKb',
unAuthFile = 'unAuthFile'
}
export const ERROR_RESPONSE: Record<
any,
@@ -73,5 +74,11 @@ export const ERROR_RESPONSE: Record<
statusText: ERROR_ENUM.unAuthKb,
message: '无权使用该知识库',
data: null
},
[ERROR_ENUM.unAuthFile]: {
code: 513,
statusText: ERROR_ENUM.unAuthFile,
message: '无权阅读该文件',
data: null
}
};

View File

@@ -5,7 +5,7 @@ import { TrainingModeEnum } from '@/constants/plugin';
import { ERROR_ENUM } from '../errorCode';
import { sendInform } from '@/pages/api/user/inform/send';
import { authBalanceByUid } from '../utils/auth';
import { axiosConfig, getAIChatApi } from '../ai/openai';
import { axiosConfig, getAIChatApi } from '../lib/openai';
import { ChatCompletionRequestMessage } from 'openai';
import { modelToolMap } from '@/utils/plugin';
import { gptMessage2ChatType } from '@/utils/adapt';

View File

@@ -0,0 +1,119 @@
import mongoose, { Types } from 'mongoose';
import fs from 'fs';
import fsp from 'fs/promises';
import { ERROR_ENUM } from '../errorCode';
enum BucketNameEnum {
dataset = 'dataset'
}
type FileInfo = {
id: string;
filename: string;
size: number;
contentType: string;
encoding: string;
};
export class GridFSStorage {
readonly type = 'gridfs';
readonly bucket: `${BucketNameEnum}`;
readonly uid: string;
constructor(bucket: `${BucketNameEnum}`, uid: string) {
this.bucket = bucket;
this.uid = String(uid);
}
GridFSBucket() {
return new mongoose.mongo.GridFSBucket(mongoose.connection.db, {
bucketName: this.bucket
});
}
async save({
path,
filename,
metadata = {}
}: {
path: string;
filename: string;
metadata?: Record<string, any>;
}) {
if (!path) return Promise.reject(`filePath is empty`);
if (!filename) return Promise.reject(`filename is empty`);
const stats = await fsp.stat(path);
if (!stats.isFile()) return Promise.reject(`${path} is not a file`);
metadata.userId = this.uid;
// create a gridfs bucket
const bucket = this.GridFSBucket();
const stream = bucket.openUploadStream(filename, {
metadata,
contentType: metadata?.contentType
});
// save to gridfs
await new Promise((resolve, reject) => {
fs.createReadStream(path)
.pipe(stream as any)
.on('finish', resolve)
.on('error', reject);
});
return String(stream.id);
}
async findAndAuthFile(id: string): Promise<FileInfo> {
if (!id) {
return Promise.reject(`id is empty`);
}
// create a gridfs bucket
const bucket = this.GridFSBucket();
// check if file exists
const files = await bucket.find({ _id: new Types.ObjectId(id) }).toArray();
const file = files.shift();
if (!file) {
return Promise.reject(`file not found`);
}
if (String(file.metadata?.userId) !== this.uid) {
return Promise.reject(ERROR_ENUM.unAuthFile);
}
return {
id: String(file._id),
filename: file.filename,
contentType: file.metadata?.contentType,
encoding: file.metadata?.encoding,
size: file.length
};
}
async delete(id: string) {
await this.findAndAuthFile(id);
const bucket = this.GridFSBucket();
await bucket.delete(new Types.ObjectId(id));
return true;
}
async download(id: string) {
await this.findAndAuthFile(id);
const bucket = this.GridFSBucket();
const stream = bucket.openDownloadStream(new Types.ObjectId(id));
const buf: Buffer = await new Promise((resolve, reject) => {
const buffers: Buffer[] = [];
stream.on('data', (data) => buffers.push(data));
stream.on('error', reject);
stream.on('end', () => resolve(Buffer.concat(buffers)));
});
return buf;
}
}

View File

@@ -2,7 +2,7 @@ import { adaptChatItem_openAI } from '@/utils/plugin/openai';
import { ChatContextFilter } from '@/service/utils/chat/index';
import type { ChatHistoryItemResType, ChatItemType } from '@/types/chat';
import { ChatModuleEnum, ChatRoleEnum, TaskResponseKeyEnum } from '@/constants/chat';
import { getAIChatApi, axiosConfig } from '@/service/ai/openai';
import { getAIChatApi, axiosConfig } from '@/service/lib/openai';
import type { ClassifyQuestionAgentItemType } from '@/types/app';
import { countModelPrice } from '@/service/events/pushBill';
import { UserModelSchema } from '@/types/mongoSchema';

View File

@@ -2,7 +2,7 @@ import { adaptChatItem_openAI } from '@/utils/plugin/openai';
import { ChatContextFilter } from '@/service/utils/chat/index';
import type { ChatHistoryItemResType, ChatItemType } from '@/types/chat';
import { ChatModuleEnum, ChatRoleEnum, TaskResponseKeyEnum } from '@/constants/chat';
import { getAIChatApi, axiosConfig } from '@/service/ai/openai';
import { getAIChatApi, axiosConfig } from '@/service/lib/openai';
import type { ContextExtractAgentItemType } from '@/types/app';
import { ContextExtractEnum } from '@/constants/flow/flowField';
import { countModelPrice } from '@/service/events/pushBill';

View File

@@ -8,7 +8,7 @@ import type { ChatHistoryItemResType } from '@/types/chat';
import { ChatModuleEnum, ChatRoleEnum, sseResponseEventEnum } from '@/constants/chat';
import { SSEParseData, parseStreamChunk } from '@/utils/sse';
import { textAdaptGptResponse } from '@/utils/adapt';
import { getAIChatApi, axiosConfig } from '@/service/ai/openai';
import { getAIChatApi, axiosConfig } from '@/service/lib/openai';
import { TaskResponseKeyEnum } from '@/constants/chat';
import { getChatModel } from '@/service/utils/data';
import { countModelPrice } from '@/service/events/pushBill';

View File

@@ -1,34 +0,0 @@
import axios from 'axios';
{
/*Bing 搜索*/
}
const BingSearch = async (wait_val: string) => {
const response = await axios.post('newbing中转服务器', {
prompt: wait_val
});
const result = response.data.result;
return result;
};
{
/*google 搜索*/
}
const GoogleSearch = async (wait_val: string) => {
const response = await axios.get('https://www.googleapis.com/customsearch/v1', {
params: {
key: process.env.GOOGLE_KEY,
q: wait_val,
cx: process.env.searchEngineId,
start: 1,
num: 3,
dateRestrict: 'm[1]' //搜索结果限定为一个月内
}
});
const results = response.data.items;
if (results !== null) {
const result = results.map((item: { snippet: string }) => item.snippet).join('\n');
return result;
}
};
export { BingSearch, GoogleSearch };