Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,28 @@ LOG_LEVEL=info
# Model provider sort
MODEL_PROVIDER_PRIORITY=

# MinIO Config
# Customize MinIO Endpoint. Such as https://example.com The URL returned will be rewrite by this Endpoint: https://example.com/{{filename}}
MINIO_CUSTOM_ENDPOINT=
MINIO_ENDPOINT=localhost
MINIO_PORT=9000
MINIO_USE_SSL=false
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=minioadmin
MINIO_BUCKET=files
# Signoz
SIGNOZ_BASE_URL=
SIGNOZ_SERVICE_NAME=fastgpt-plugin

# S3 Config
# Customize S3 Base URL, for example: https://s3.example.com, make sure you can access your files via https://s3.example.com/[bucket]/[objectname]
S3_EXTERNAL_BASE_URL=
S3_ENDPOINT=localhost
S3_PORT=9000
S3_USE_SSL=false
S3_ACCESS_KEY=minioadmin
S3_SECRET_KEY=minioadmin
S3_TOOL_BUCKET=fastgpt-tool # 系统工具,创建的临时文件,存储的桶,要求公开读私有写。
S3_PLUGIN_BUCKET=fastgpt-plugin # 系统插件热安装文件的桶,私有读写。
RETENTION_DAYS=15 # 系统工具临时文件保存天数

# Signoz
SIGNOZ_BASE_URL=
SIGNOZ_SERVICE_NAME=fastgpt-plugin

# MongoDB connection string
# Replace 'myusername' and 'mypassword' with your actual MongoDB credentials and ensure the database 'fastgpt' exists.
MONGODB_URI=mongodb://myusername:mypassword@localhost:27017/fastgpt?authSource=admin&directConnection=true

REDIS_URL=redis://default:[email protected]:6379
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ node_modules
public/imgs/
.local
pnpm-lock.yaml
local/
77 changes: 73 additions & 4 deletions bun.lock

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions env.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
declare namespace NodeJS {
interface ProcessEnv {
MINIO_CUSTOM_ENDPOINT: string;
MINIO_ENDPOINT: string;
MINIO_PORT: string;
MINIO_USE_SSL: string;
MINIO_ACCESS_KEY: string;
MINIO_SECRET_KEY: string;
MINIO_BUCKET: string;
S3_EXTERNAL_BASE_URL: string;
S3_ENDPOINT: string;
S3_PORT: string;
S3_USE_SSL: string;
S3_ACCESS_KEY: string;
S3_SECRET_KEY: string;
S3_BUCKET: string;
MAX_FILE_SIZE: string;
RETENTION_DAYS: string;
}
Expand Down
66 changes: 37 additions & 29 deletions modules/model/init.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,44 @@
import alicloud from './provider/AliCloud/index';
import baai from './provider/BAAI/index';
import baichuan from './provider/Baichuan/index';
import chatglm from './provider/ChatGLM/index';
import claude from './provider/Claude/index';
import deepseek from './provider/DeepSeek/index';
import doubao from './provider/Doubao/index';
import ernie from './provider/Ernie/index';
import fishaudio from './provider/FishAudio/index';
import gemini from './provider/Gemini/index';
import grok from './provider/Grok/index';
import groq from './provider/Groq/index';
import hunyuan from './provider/Hunyuan/index';
import intern from './provider/InternLM/index';
import jina from './provider/Jina/index';
import meta from './provider/Meta/index';
import minimax from './provider/MiniMax/index';
import mistralai from './provider/MistralAI/index';
import moka from './provider/Moka/index';
import moonshot from './provider/Moonshot/index';
import ollama from './provider/Ollama/index';
import openai from './provider/OpenAI/index';
import other from './provider/Other/index';
import ppio from './provider/PPIO/index';
import qwen from './provider/Qwen/index';
import siliconflow from './provider/Siliconflow/index';
import sparkdesk from './provider/SparkDesk/index';
import stepfun from './provider/StepFun/index';
import yi from './provider/Yi/index';
import alicloud from './provider/AliCloud';
import baai from './provider/BAAI';
import baichuan from './provider/Baichuan';
import chatglm from './provider/ChatGLM';
import claude from './provider/Claude';
import deepseek from './provider/DeepSeek';
import doubao from './provider/Doubao';
import ernie from './provider/Ernie';
import fishaudio from './provider/FishAudio';
import gemini from './provider/Gemini';
import grok from './provider/Grok';
import groq from './provider/Groq';
import hunyuan from './provider/Hunyuan';
import intern from './provider/InternLM';
import jina from './provider/Jina';
import meta from './provider/Meta';
import minimax from './provider/MiniMax';
import mistralai from './provider/MistralAI';
import moka from './provider/Moka';
import moonshot from './provider/Moonshot';
import ollama from './provider/Ollama';
import openai from './provider/OpenAI';
import other from './provider/Other';
import ppio from './provider/PPIO';
import qwen from './provider/Qwen';
import siliconflow from './provider/Siliconflow';
import sparkdesk from './provider/SparkDesk';
import stepfun from './provider/StepFun';
import yi from './provider/Yi';
import ai360 from './provider/ai360';
import huggingface from './provider/HuggingFace';
import novita from './provider/novita';
import openrouter from './provider/OpenRouter';

import { ModelItemSchema, ModelTypeEnum, type ProviderConfigType } from './type';
import { modelsBuffer } from './constants';
import { addLog } from '@/utils/log';

// All providers array in alphabetical order
const allProviders: ProviderConfigType[] = [
ai360,
alicloud,
baai,
baichuan,
Expand All @@ -46,6 +51,7 @@ const allProviders: ProviderConfigType[] = [
gemini,
grok,
groq,
huggingface,
hunyuan,
intern,
jina,
Expand All @@ -54,8 +60,10 @@ const allProviders: ProviderConfigType[] = [
mistralai,
moka,
moonshot,
novita,
ollama,
openai,
openrouter,
other,
ppio,
qwen,
Expand Down
8 changes: 6 additions & 2 deletions modules/tool/api/list.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { s } from '@/router/init';
import { contract } from '@/contract';
import { tools } from '@tool/constants';
import { formatToolList } from '@tool/utils/tool';
import { builtinTools } from '@tool/constants';
import { getCachedData } from '@/cache';
import { SystemCacheKeyEnum } from '@/cache/type';

export const getToolsHandler = s.route(contract.tool.list, async () => {
// this list will only be called when syncKey is changed.
const uploadedTools = await getCachedData(SystemCacheKeyEnum.systemTool);
return {
status: 200,
body: formatToolList(tools)
body: formatToolList([...builtinTools, ...uploadedTools])
};
});
41 changes: 41 additions & 0 deletions modules/tool/api/upload/confirmUpload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { s } from '@/router/init';
import { contract } from '@/contract';
import { mongoSessionRun } from '@/mongo/utils';
import { downloadTool } from '@tool/controller';
import { MongoPluginModel, pluginTypeEnum } from '@/mongo/models/plugins';
import { refreshVersionKey } from '@/cache';
import { SystemCacheKeyEnum } from '@/cache/type';
import { addLog } from '@/utils/log';
import { pluginFileS3Server } from '@/s3';

export default s.route(contract.tool.upload.confirmUpload, async ({ body }) => {
const { objectName } = body;

await mongoSessionRun(async (session) => {
const toolId = await downloadTool(objectName);
if (!toolId) return Promise.reject('Can not parse ToolId from the tool, installation failed.');
const oldTool = await MongoPluginModel.findOneAndUpdate(
{
toolId
},
{
objectName,
type: pluginTypeEnum.Enum.tool
},
{
session,
upsert: true
}
);
if (oldTool?.objectName) pluginFileS3Server.removeFile(oldTool.objectName);
await refreshVersionKey(SystemCacheKeyEnum.systemTool);
addLog.info(`Upload tool success: ${toolId}`);
});

return {
status: 200,
body: {
message: 'ok'
}
};
});
31 changes: 31 additions & 0 deletions modules/tool/api/upload/delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { contract } from '@/contract';
import { MongoPluginModel } from '@/mongo/models/plugins';
import { mongoSessionRun } from '@/mongo/utils';
import { s } from '@/router/init';
import { pluginFileS3Server } from '@/s3';
import { refreshVersionKey } from '@/cache';
import { SystemCacheKeyEnum } from '@/cache/type';

export default s.route(contract.tool.upload.delete, async ({ query: { toolId: rawToolId } }) => {
const toolId = rawToolId.split('-').slice(1).join('-');
await mongoSessionRun(async (session) => {
const result = await MongoPluginModel.findOneAndDelete({ toolId }).session(session);
if (!result) {
return {
status: 404,
body: {
error: `Tool with toolId ${toolId} not found in MongoDB`
}
};
}
await pluginFileS3Server.removeFile(result.objectName);
await refreshVersionKey(SystemCacheKeyEnum.systemTool);
});

return {
status: 200,
body: {
message: 'Tool deleted successfully'
}
};
});
16 changes: 16 additions & 0 deletions modules/tool/api/upload/getUploadURL.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { s } from '@/router/init';
import { contract } from '@/contract';
import { pluginFileS3Server } from '@/s3';
import { UploadToolsS3Path } from '@tool/constants';
import { mimeMap } from '@/s3/const';

export default s.route(contract.tool.upload.getUploadURL, async ({ query: { filename } }) => {
return {
status: 200,
body: await pluginFileS3Server.generateUploadPresignedURL({
filepath: UploadToolsS3Path,
contentType: mimeMap['.js'],
filename
})
};
});
11 changes: 11 additions & 0 deletions modules/tool/api/upload/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { contract } from '@/contract';
import { s } from '@/router/init';
import confirmUpload from './confirmUpload';
import getUploadURL from './getUploadURL';
import deleteHandler from './delete';

export default s.router(contract.tool.upload, {
confirmUpload,
getUploadURL,
delete: deleteHandler
});
5 changes: 4 additions & 1 deletion modules/tool/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import type { ToolType } from './type';

export const tools: ToolType[] = [];
export const uploadedTools: ToolType[] = [];
export const builtinTools: ToolType[] = [];

export const UploadToolsS3Path = 'system/tools';
61 changes: 58 additions & 3 deletions modules/tool/contract.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,61 @@
import z from 'zod';
import { c } from '@/contract/init';
import { ToolListItemSchema, type ToolListItemType } from './type/api';
import { ToolTypeListSchema } from './controller';
import { ToolListItemSchema, type ToolListItemType, ToolTypeListSchema } from './type/api';

export const toolUploadContract = c.router(
{
getUploadURL: {
path: '/getUploadURL',
query: z.object({
filename: z.string()
}),
responses: {
200: z.object({
postURL: z.string(),
formData: z.record(z.any()),
objectName: z.string()
})
},
method: 'GET',
description: 'Get presigned upload URL'
},
delete: {
path: '/delete',
method: 'DELETE',
description: 'Delete a tool',
query: z.object({
toolId: z.string()
}),
responses: {
200: z.object({
message: z.string()
}),
400: z.object({
error: z.string()
}),
404: z.object({
error: z.string()
})
}
},
confirmUpload: {
path: '/confirmUpload',
method: 'POST',
description: 'Upload and install a tool plugin',
body: z.object({
objectName: z.string()
}),
responses: {
200: z.object({
message: z.string()
})
}
}
},
{
pathPrefix: '/upload'
}
);

export const toolContract = c.router(
{
Expand Down Expand Up @@ -31,7 +85,8 @@ export const toolContract = c.router(
responses: {
200: ToolTypeListSchema
}
}
},
upload: toolUploadContract
},
{
pathPrefix: '/tool'
Expand Down
Loading