Skip to content
Open
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
22 changes: 22 additions & 0 deletions dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@ NODE_OPTIONS=--no-node-snapshot pnpm i

https://fael3z0zfze.feishu.cn/docx/ZOI1dABpxoGhS7xzhkXcKPxZnDL

## API

### Create an API

1. declare a contract at `packages/global/tsRest/fastgpt/contracts`

2. implement handler for the contract at `projects/app/src/pages/apiRouters`

By the way, you can use `restapi` snippet to quickly create a template of the handler implementation

3. import the handler to the relative api router object structure

4. create API, like `const getChatSetting = RestAPI(client.chat.setting.detail);`, at the relative `api` folder or `api.ts`

### If you need to forward a Pro API to fastgpt-pro

the steps of [Create an API](#create-an-api) should also be followed, and then:

1. declare the handler as `proApi` in the fastgpt's api router

2. implement handler at fastgpt-pro

## I18N

### Install i18n-ally Plugin
Expand Down
7 changes: 6 additions & 1 deletion document/content/docs/upgrading/4-13/4132.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ description: 'FastGPT V4.13.1 更新说明'

## 🚀 新增内容

1. HTTP 工具集支持手动创建模式。

## ⚙️ 优化

Expand All @@ -16,4 +17,8 @@ description: 'FastGPT V4.13.1 更新说明'

## 🔨 插件更新

1. Perplexity search 工具。
1. Perplexity search 工具。
2. Base64转文件工具。
3. MiniMax TTS 文件生成工具。
4. Openrouter nano banana 绘图工具。
5. 系统工具支持配置是否需要在 Worker 中运行。
3 changes: 2 additions & 1 deletion document/data/doc-last-modified.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
"document/content/docs/protocol/terms.en.mdx": "2025-08-03T22:37:45+08:00",
"document/content/docs/protocol/terms.mdx": "2025-08-03T22:37:45+08:00",
"document/content/docs/toc.en.mdx": "2025-08-04T13:42:36+08:00",
"document/content/docs/toc.mdx": "2025-09-29T11:34:11+08:00",
"document/content/docs/toc.mdx": "2025-10-09T15:10:19+08:00",
"document/content/docs/upgrading/4-10/4100.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-10/4101.mdx": "2025-09-08T20:07:20+08:00",
"document/content/docs/upgrading/4-11/4110.mdx": "2025-08-05T23:20:39+08:00",
Expand All @@ -113,6 +113,7 @@
"document/content/docs/upgrading/4-12/4124.mdx": "2025-09-17T22:29:56+08:00",
"document/content/docs/upgrading/4-13/4130.mdx": "2025-09-30T16:00:10+08:00",
"document/content/docs/upgrading/4-13/4131.mdx": "2025-09-30T15:47:06+08:00",
"document/content/docs/upgrading/4-13/4132.mdx": "2025-10-12T00:04:51+08:00",
"document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00",
Expand Down
13 changes: 13 additions & 0 deletions packages/global/common/tsRest/fastgpt/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { initClient } from '@ts-rest/core';
import { fastgptContract } from './contracts';

export function createFastGPTClient(options: {
baseUrl: string;
baseHeaders?: Record<string, string>;
api?: any;
credentials?: RequestCredentials;
throwOnUnknownStatus?: boolean;
validateResponse?: boolean;
}) {
return initClient(fastgptContract, options);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { settingContract } from './setting';
import { initContract } from '@ts-rest/core';
const c = initContract();

export const chatContract = c.router({
setting: settingContract
});
127 changes: 127 additions & 0 deletions packages/global/common/tsRest/fastgpt/contracts/core/chat/setting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import z from 'zod';
import {
ChatSettingResponseSchema,
ChatSettingSchema
} from '../../../../../../core/chat/setting/type';
import { ChatFavouriteAppResponseItemSchema } from '../../../../../../core/chat/favouriteApp/type';
import { ObjectIdSchema } from '../../../../../type';
import { initContract } from '@ts-rest/core';

const c = initContract();
const favouriteContract = c.router({
list: {
path: '/proApi/core/chat/setting/favourite/list',
method: 'GET',
query: z.object({
name: z.string().optional().openapi({ example: 'FastGPT' }),
tag: z.string().optional().openapi({ example: 'i7Ege2W2' })
}),
responses: {
200: z.array(ChatFavouriteAppResponseItemSchema)
},
metadata: {
tags: ['chat']
},
description: '获取精选应用列表',
summary: '获取精选应用列表'
},
update: {
path: '/proApi/core/chat/setting/favourite/update',
method: 'PUT',
body: z.array(
z.object({
appId: z.string(),
order: z.number()
})
),
responses: {
200: z.void()
},
metadata: {
tags: ['chat']
},
description: '更新精选应用',
summary: '更新精选应用'
},
delete: {
path: '/proApi/core/chat/setting/favourite/delete',
method: 'DELETE',
query: z.object({
id: ObjectIdSchema
}),
responses: {
200: z.void()
},
metadata: {
tags: ['chat']
},
description: '删除精选应用',
summary: '删除精选应用'
},
order: {
path: '/proApi/core/chat/setting/favourite/order',
method: 'PUT',
body: z.array(
z.object({
id: ObjectIdSchema,
order: z.number()
})
),
responses: {
200: z.void()
},
metadata: {
tags: ['chat']
},
description: '更新精选应用顺序',
summary: '更新精选应用顺序'
},
tags: {
path: '/proApi/core/chat/setting/favourite/tags',
method: 'PUT',
body: z.array(
z.object({
id: z.string(),
tags: z.array(z.string())
})
),
responses: {
200: z.void()
},
metadata: {
tags: ['chat']
},
description: '更新精选应用标签',
summary: '更新精选应用标签'
}
});

export const settingContract = c.router({
favourite: favouriteContract,

detail: {
path: '/proApi/core/chat/setting/detail',
method: 'GET',
responses: {
200: ChatSettingResponseSchema
},
metadata: {
tags: ['chat']
},
description: '获取聊天设置',
summary: '获取聊天设置'
},
update: {
path: '/proApi/core/chat/setting/update',
method: 'PUT',
body: ChatSettingSchema.partial(),
responses: {
200: z.void()
},
metadata: {
tags: ['chat']
},
description: '更新聊天设置',
summary: '更新聊天设置'
}
});
7 changes: 7 additions & 0 deletions packages/global/common/tsRest/fastgpt/contracts/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { initContract } from '@ts-rest/core';
import { chatContract } from './chat';
const c = initContract();

export const coreContract = c.router({
chat: chatContract
});
12 changes: 12 additions & 0 deletions packages/global/common/tsRest/fastgpt/contracts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { initContract } from '@ts-rest/core';
import { coreContract } from './core';
import { supportContract } from './support';

const c = initContract();

export const fastgptContract = c.router({
core: coreContract,
support: supportContract
});

export type FadtGPTContractType = typeof fastgptContract;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { userContract } from './user';
import { initContract } from '@ts-rest/core';
const c = initContract();

export const supportContract = c.router({
user: userContract
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { initContract } from '@ts-rest/core';
import z from 'zod';
const c = initContract();

export const accountContract = c.router({
loginout: {
path: '/support/user/account/loginout',
method: 'GET',
responses: {
200: z.void()
},
metadata: {
tags: ['support']
},
description: '退出登录',
summary: '退出登录'
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { accountContract } from './account';
import { initContract } from '@ts-rest/core';
const c = initContract();

export const userContract = c.router({
account: accountContract
});
36 changes: 36 additions & 0 deletions packages/global/common/tsRest/fastgpt/openapi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { fastgptContract, type FadtGPTContractType } from './contracts';
import { generateOpenApi } from '@ts-rest/open-api';

const hasCustomTags = (metadata: unknown): metadata is { tags: string[] } => {
return !!metadata && typeof metadata === 'object' && 'tags' in metadata;
};

type OpenAPIObject = ReturnType<typeof generateOpenApi>;
function generateOpenApiDocument(c: FadtGPTContractType): OpenAPIObject {
return generateOpenApi(
c,
{
info: {
title: 'FastGPT OpenAPI',
version: '4.13.2',
description: 'FastGPT OpenAPI'
},
servers: [{ url: '/api' }]
},
{
operationMapper(operation, appRoute) {
return {
...operation,
...(hasCustomTags(appRoute.metadata)
? {
tags: appRoute.metadata.tags
}
: {})
};
},
setOperationId: false
}
);
}

export const fastgptOpenApiDocument = generateOpenApiDocument(fastgptContract);
20 changes: 20 additions & 0 deletions packages/global/common/tsRest/fastgpt/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { fastgptContract } from './contracts';
import { createNextRoute, createNextRouter } from '@ts-rest/next';

/**
* 创建 FastGPT 单个路由
*/
export function createServerRoute(
implementation: Parameters<typeof createNextRoute<typeof fastgptContract>>[1]
) {
return createNextRoute(fastgptContract, implementation);
}

/**
* 创建 FastGPT 路由器([...ts-rest])
*/
export function createServerRouter(
router: Parameters<typeof createNextRouter<typeof fastgptContract>>[1]
) {
return createNextRouter(fastgptContract, router);
}
56 changes: 56 additions & 0 deletions packages/global/common/tsRest/fastgptpro/contracts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { chatContract } from '../../fastgpt/contracts/core/chat';
import { initContract } from '@ts-rest/core';
const c = initContract();

/**
* 转换路径前缀
* 将 /proApi 替换为空字符串,用于 Pro 后端
*/
function transformPaths<T extends Record<string, any>>(
router: T,
removePrefix: string = '/proApi',
replaceWith: string = ''
): T {
const transform = (obj: any): any => {
if (typeof obj !== 'object' || obj === null) return obj;

// 如果是路由定义(有 path 属性)
if ('path' in obj && typeof obj.path === 'string') {
return {
...obj,
path: obj.path.replace(removePrefix, replaceWith),
metadata: {
...obj.metadata,
originalPath: obj.path
}
};
}

// 递归处理嵌套的路由
const result: any = {};
for (const key in obj) {
result[key] = transform(obj[key]);
}
return result;
};

return transform(router) as T;
}

// 通过 FastGPT 后端转发到 Pro 后端使用的合约
const transformedProContract = c.router({
chat: transformPaths(chatContract)
});

// Pro 后端独有的接口
const proOnlyContract = c.router({
// TODO
// admin: adminContract,
});

// 最终的 Pro 合约 = 转换后的 Pro 接口 + Pro 后端独有的接口
// Pro 后端使用的合约
export const proContract = c.router({
...transformedProContract,
...proOnlyContract
});
Loading
Loading