mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-22 20:04:01 +00:00

* add manual create http toolset (#5743) * add manual create http toolset * optimize code * optimize * fix * fix * rename filename * feat: integrate ts-rest (#5741) * feat: integrate ts-rest * chore: classify core contract and pro contract * chore: update lockfile * chore: tweak dir structure * chore: tweak dir structure * update tsrest code (#5755) * doc * update tsrest code * fix http toolset (#5753) * fix http toolset * fix * perf: http toolset * fix: toolresponse result (#5760) * doc * fix: toolresponse result * fix: mongo watch * remove log * feat: integrated to minio (#5748) * feat: migrate to minio * feat: migrate apps' and dataset's avatar to minio * feat: migrate more avatars to minio * fix: lock file * feat: migrate copyright settings' logo to minio * feat: integrate minio * chore: improve code * chore: rename variables * refactor: s3 class * fix: s3 and mongo operations * chore: add session for avatar source * fix: init s3 buckets * fix: bugbot issues * expired time code * perf: avatar code * union type * export favouriteContract * empty bucket check --------- Co-authored-by: archer <545436317@qq.com> * refactor: zod schema to generate OpenAPI instead (#5771) * doc * fix: text split code (#5773) * fix: toolresponse result * remove log * stream remove * fix: text split code * fix: workflow (#5779) * fix: toolresponse result * remove log * fix: value check * fix: workflow * openapi doc * perf: bucket delete cron * doc * feat: apikey health * feat: export variables * api code move * perf: workflow performance (#5783) * perf: reactflow context * perf: workflow context split * perf: nodeList computed map * perf: nodes dependen * perf: workflow performance * workflow performance * removel og * lock * version * loop drag * reactflow size * reactflow size * fix: s3init (#5784) * doc * fix: s3init * perf: dynamic import * remove moongose dep * worker build * worker code * perf: worker build * fix: error throw * doc * doc * fix: build * fix: dockerfile * nextjs config * fix: worker * fix: build (#5791) * fix: build * vector cache code * fix: app info modal avatar upload method replace (#5787) * fix: app info modal avatar upload method replace * chore: replace all useSelectFile with useUploadAvatar * remove invalid code * add size * Update projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/CommonInputForm.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update projects/app/src/pageComponents/app/detail/WorkflowComponents/context/workflowInitContext.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: heheer <heheer@sealos.io> Co-authored-by: 伍闲犬 <whoeverimf5@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
167 lines
4.7 KiB
TypeScript
167 lines
4.7 KiB
TypeScript
import { type StoreSecretValueType } from '@fastgpt/global/common/secret/type';
|
|
import { getSecretValue } from '../../common/secret/utils';
|
|
import axios from 'axios';
|
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
|
import type { RequireOnlyOne } from '@fastgpt/global/common/type/utils';
|
|
import type { HttpToolConfigType } from '@fastgpt/global/core/app/type';
|
|
import { contentTypeMap, ContentTypes } from '@fastgpt/global/core/workflow/constants';
|
|
import { replaceEditorVariable } from '@fastgpt/global/core/workflow/runtime/utils';
|
|
|
|
export type RunHTTPToolParams = {
|
|
baseUrl: string;
|
|
toolPath: string;
|
|
method: string;
|
|
params: Record<string, any>;
|
|
headerSecret?: StoreSecretValueType;
|
|
customHeaders?: Record<string, string>;
|
|
staticParams?: HttpToolConfigType['staticParams'];
|
|
staticHeaders?: HttpToolConfigType['staticHeaders'];
|
|
staticBody?: HttpToolConfigType['staticBody'];
|
|
};
|
|
|
|
export type RunHTTPToolResult = RequireOnlyOne<{
|
|
data?: any;
|
|
errorMsg?: string;
|
|
}>;
|
|
|
|
const buildHttpRequest = ({
|
|
method,
|
|
params,
|
|
headerSecret,
|
|
customHeaders,
|
|
staticParams,
|
|
staticHeaders,
|
|
staticBody
|
|
}: Omit<RunHTTPToolParams, 'baseUrl' | 'toolPath'>) => {
|
|
const replaceVariables = (text: string) => {
|
|
return replaceEditorVariable({
|
|
text,
|
|
nodes: [],
|
|
variables: params
|
|
});
|
|
};
|
|
|
|
const body = (() => {
|
|
if (!staticBody || staticBody.type === ContentTypes.none) {
|
|
return ['POST', 'PUT', 'PATCH'].includes(method.toUpperCase()) ? {} : undefined;
|
|
}
|
|
|
|
if (staticBody.type === ContentTypes.json) {
|
|
const contentWithReplacedVars = staticBody.content
|
|
? replaceVariables(staticBody.content)
|
|
: '{}';
|
|
const staticContent = JSON.parse(contentWithReplacedVars);
|
|
return { ...staticContent };
|
|
}
|
|
|
|
if (staticBody.type === ContentTypes.formData) {
|
|
const formData = new (require('form-data'))();
|
|
staticBody.formData?.forEach(({ key, value }) => {
|
|
const replacedKey = replaceVariables(key);
|
|
const replacedValue = replaceVariables(value);
|
|
formData.append(replacedKey, replacedValue);
|
|
});
|
|
return formData;
|
|
}
|
|
|
|
if (staticBody.type === ContentTypes.xWwwFormUrlencoded) {
|
|
const urlencoded = new URLSearchParams();
|
|
staticBody.formData?.forEach(({ key, value }) => {
|
|
const replacedKey = replaceVariables(key);
|
|
const replacedValue = replaceVariables(value);
|
|
urlencoded.append(replacedKey, replacedValue);
|
|
});
|
|
return urlencoded.toString();
|
|
}
|
|
|
|
if (staticBody.type === ContentTypes.xml || staticBody.type === ContentTypes.raw) {
|
|
return replaceVariables(staticBody.content || '');
|
|
}
|
|
|
|
return undefined;
|
|
})();
|
|
|
|
const contentType = contentTypeMap[staticBody?.type || ContentTypes.none];
|
|
const headers = {
|
|
...(contentType && { 'Content-Type': contentType }),
|
|
...(customHeaders || {}),
|
|
...(headerSecret ? getSecretValue({ storeSecret: headerSecret }) : {}),
|
|
...(staticHeaders?.reduce(
|
|
(acc, { key, value }) => {
|
|
const replacedKey = replaceVariables(key);
|
|
const replacedValue = replaceVariables(value);
|
|
acc[replacedKey] = replacedValue;
|
|
return acc;
|
|
},
|
|
{} as Record<string, string>
|
|
) || {})
|
|
};
|
|
|
|
const queryParams = (() => {
|
|
const staticParamsObj =
|
|
staticParams?.reduce(
|
|
(acc, { key, value }) => {
|
|
const replacedKey = replaceVariables(key);
|
|
const replacedValue = replaceVariables(value);
|
|
acc[replacedKey] = replacedValue;
|
|
return acc;
|
|
},
|
|
{} as Record<string, any>
|
|
) || {};
|
|
|
|
const mergedParams =
|
|
method.toUpperCase() === 'GET' || staticParams
|
|
? { ...staticParamsObj, ...params }
|
|
: staticParamsObj;
|
|
|
|
return Object.keys(mergedParams).length > 0 ? mergedParams : undefined;
|
|
})();
|
|
|
|
return {
|
|
headers,
|
|
body,
|
|
queryParams
|
|
};
|
|
};
|
|
|
|
export const runHTTPTool = async ({
|
|
baseUrl,
|
|
toolPath,
|
|
method = 'POST',
|
|
params,
|
|
headerSecret,
|
|
customHeaders,
|
|
staticParams,
|
|
staticHeaders,
|
|
staticBody
|
|
}: RunHTTPToolParams): Promise<RunHTTPToolResult> => {
|
|
try {
|
|
const { headers, body, queryParams } = buildHttpRequest({
|
|
method,
|
|
params,
|
|
headerSecret,
|
|
customHeaders,
|
|
staticParams,
|
|
staticHeaders,
|
|
staticBody
|
|
});
|
|
|
|
const { data } = await axios({
|
|
method: method.toUpperCase(),
|
|
baseURL: baseUrl.startsWith('https://') ? baseUrl : `https://${baseUrl}`,
|
|
url: toolPath,
|
|
headers,
|
|
data: body,
|
|
params: queryParams,
|
|
timeout: 300000,
|
|
httpsAgent: new (require('https').Agent)({
|
|
rejectUnauthorized: false
|
|
})
|
|
});
|
|
|
|
return { data };
|
|
} catch (error: any) {
|
|
return { errorMsg: getErrText(error) };
|
|
}
|
|
};
|