V4.8.14 dev (#3234)

* feat: rewrite chat context (#3176)

* feat: add app auto execute (#3115)

* feat: add app auto execute

* auto exec configtion

* chatting animation

* change icon

* fix

* fix

* fix link

* feat: add chat context to all chatbox

* perf: loading ui

---------

Co-authored-by: heheer <heheer@sealos.io>

* app auto exec (#3179)

* add chat records loaded state (#3184)

* perf: chat store reset storage (#3186)

* perf: chat store reset storage

* perf: auto exec code

* chore: workflow ui (#3175)

* chore: workflow ui

* fix

* change icon color config

* change popover to mymenu

* 4.8.14 test (#3189)

* update doc

* fix: token check

* perf: icon button

* update doc

* feat: share page support configuration Whether to allow the original view (#3194)

* update doc

* perf: fix index (#3206)

* perf: i18n

* perf: Add service entry (#3226)

* 4.8.14 test (#3228)

* fix: ai log

* fix: text splitter

* fix: reference unselect & user form description & simple to advance (#3229)

* fix: reference unselect & user form description & simple to advance

* change abort position

* perf

* perf: code (#3232)

* perf: code

* update doc

* fix: create btn permission (#3233)

* update doc

* fix: refresh chatbox listener

* perf: check invalid reference

* perf: check invalid reference

* update doc

* fix: ui props

---------

Co-authored-by: heheer <heheer@sealos.io>
This commit is contained in:
Archer
2024-11-26 12:02:58 +08:00
committed by GitHub
parent 7e1d31b5a9
commit 8aa6b53760
221 changed files with 3831 additions and 2737 deletions

View File

@@ -12,5 +12,7 @@ export const fileImgs = [
];
export function getFileIcon(name = '', defaultImg = 'file/fill/file') {
return fileImgs.find((item) => new RegExp(item.suffix, 'gi').test(name))?.src || defaultImg;
return (
fileImgs.find((item) => new RegExp(`\.${item.suffix}`, 'gi').test(name))?.src || defaultImg
);
}

View File

@@ -3,6 +3,7 @@ import { BucketNameEnum } from './constants';
export type FileTokenQuery = {
bucketName: `${BucketNameEnum}`;
teamId: string;
tmbId: string;
uid: string; // tmbId/ share uid/ teamChat uid
fileId: string;
customExpireMinutes?: number;
};

View File

@@ -140,9 +140,10 @@ const commonSplit = (props: SplitProps): SplitResponse => {
const customRegLen = customReg.length;
const checkIsCustomStep = (step: number) => step < customRegLen;
const checkIsMarkdownSplit = (step: number) => step >= customRegLen && step <= markdownIndex;
const checkIsMarkdownSplit = (step: number) =>
step >= customRegLen && step <= markdownIndex + customRegLen;
+customReg.length;
const checkForbidOverlap = (step: number) => step <= forbidOverlapIndex + customReg.length;
const checkForbidOverlap = (step: number) => step <= forbidOverlapIndex + customRegLen;
// if use markdown title split, Separate record title
const getSplitTexts = ({ text, step }: { text: string; step: number }) => {

View File

@@ -49,6 +49,7 @@ export type ChatCompletionMessageParam = (
| CustomChatCompletionAssistantMessageParam
) & {
dataId?: string;
hideInUI?: boolean;
};
export type SdkChatCompletionMessageParam = SdkChatCompletionMessageParam;

View File

@@ -1,4 +1,9 @@
import { AppTTSConfigType, AppFileSelectConfigType, AppWhisperConfigType } from './type';
import {
AppTTSConfigType,
AppFileSelectConfigType,
AppWhisperConfigType,
AppAutoExecuteConfigType
} from './type';
export enum AppTypeEnum {
folder = 'folder',
@@ -12,6 +17,11 @@ export const AppFolderTypeList = [AppTypeEnum.folder, AppTypeEnum.httpPlugin];
export const defaultTTSConfig: AppTTSConfigType = { type: 'web' };
export const defaultAutoExecuteConfig: AppAutoExecuteConfigType = {
open: false,
defaultPrompt: ''
};
export const defaultWhisperConfig: AppWhisperConfigType = {
open: false,
autoSend: false,

View File

@@ -96,6 +96,7 @@ export type AppSimpleEditFormType = {
export type AppChatConfigType = {
welcomeText?: string;
variables?: VariableItemType[];
autoExecute?: AppAutoExecuteConfigType;
questionGuide?: boolean;
ttsConfig?: AppTTSConfigType;
whisperConfig?: AppWhisperConfigType;
@@ -158,6 +159,11 @@ export type AppScheduledTriggerConfigType = {
timezone: string;
defaultPrompt: string;
};
// auto execute
export type AppAutoExecuteConfigType = {
open: boolean;
defaultPrompt: string;
};
// File
export type AppFileSelectConfigType = {
canSelectFile: boolean;

View File

@@ -76,6 +76,7 @@ export const chats2GPTMessages = ({
results.push({
dataId,
hideInUI: item.hideInUI,
role: ChatCompletionRequestMessageRoleEnum.User,
content: simpleUserContentPart(value)
});
@@ -318,6 +319,7 @@ export const GPTMessages2Chats = (
return {
dataId: item.dataId,
obj,
hideInUI: item.hideInUI,
value
} as ChatItemType;
})

View File

@@ -56,6 +56,7 @@ export type UserChatItemValueItemType = {
export type UserChatItemType = {
obj: ChatRoleEnum.Human;
value: UserChatItemValueItemType[];
hideInUI?: boolean;
};
export type SystemChatItemValueItemType = {
type: ChatItemValueTypeEnum.text;

View File

@@ -101,7 +101,7 @@ export const filterPublicNodeResponseData = ({
for (let key in item) {
if (key === 'toolDetail' || key === 'pluginDetail') {
// @ts-ignore
obj[key] = filterPublicNodeResponseData({ flowResponses: item[key] });
obj[key] = filterPublicNodeResponseData({ flowResponses: item[key], responseDetail });
} else if (filedList.includes(key)) {
// @ts-ignore
obj[key] = item[key];

View File

@@ -204,7 +204,8 @@ export type DatasetFileSchema = {
contentType: string;
metadata: {
teamId: string;
tmbId: string;
tmbId?: string;
uid: string;
encoding?: string;
};
};

View File

@@ -106,6 +106,7 @@ export enum NodeInputKeyEnum {
variables = 'variables',
scheduleTrigger = 'scheduleTrigger',
chatInputGuide = 'chatInputGuide',
autoExecute = 'autoExecute',
// plugin config
instruction = 'instruction',

View File

@@ -25,10 +25,12 @@ import type {
AppWhisperConfigType,
AppScheduledTriggerConfigType,
ChatInputGuideConfigType,
AppChatConfigType
AppChatConfigType,
AppAutoExecuteConfigType
} from '../app/type';
import { EditorVariablePickerType } from '../../../web/components/common/Textarea/PromptEditor/type';
import {
defaultAutoExecuteConfig,
defaultChatInputGuideConfig,
defaultTTSConfig,
defaultWhisperConfig
@@ -69,34 +71,37 @@ export const getGuideModule = (modules: StoreNodeItemType[]) =>
);
export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
const welcomeText: string =
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.welcomeText)?.value || '';
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.welcomeText)?.value ?? '';
const variables: VariableItemType[] =
guideModules?.inputs.find((item) => item.key === NodeInputKeyEnum.variables)?.value || [];
guideModules?.inputs.find((item) => item.key === NodeInputKeyEnum.variables)?.value ?? [];
const questionGuide: boolean =
!!guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.questionGuide)?.value ||
!!guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.questionGuide)?.value ??
false;
const ttsConfig: AppTTSConfigType =
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.tts)?.value ||
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.tts)?.value ??
defaultTTSConfig;
const whisperConfig: AppWhisperConfigType =
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.whisper)?.value ||
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.whisper)?.value ??
defaultWhisperConfig;
const scheduledTriggerConfig: AppScheduledTriggerConfigType = guideModules?.inputs?.find(
(item) => item.key === NodeInputKeyEnum.scheduleTrigger
)?.value;
const scheduledTriggerConfig: AppScheduledTriggerConfigType =
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.scheduleTrigger)?.value ??
undefined;
const chatInputGuide: ChatInputGuideConfigType =
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.chatInputGuide)?.value ||
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.chatInputGuide)?.value ??
defaultChatInputGuideConfig;
// plugin
const instruction: string =
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.instruction)?.value || '';
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.instruction)?.value ?? '';
const autoExecute: AppAutoExecuteConfigType =
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.autoExecute)?.value ??
defaultAutoExecuteConfig;
return {
welcomeText,
@@ -106,7 +111,8 @@ export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
whisperConfig,
scheduledTriggerConfig,
chatInputGuide,
instruction
instruction,
autoExecute
};
};
@@ -132,7 +138,8 @@ export const getAppChatConfig = ({
whisperConfig,
scheduledTriggerConfig,
chatInputGuide,
instruction
instruction,
autoExecute
} = splitGuideModule(systemConfigNode);
const config: AppChatConfigType = {
@@ -142,6 +149,7 @@ export const getAppChatConfig = ({
scheduledTriggerConfig,
chatInputGuide,
instruction,
autoExecute,
...chatConfig,
variables: storeVariables ?? chatConfig?.variables ?? variables,
welcomeText: storeWelcomeText ?? chatConfig?.welcomeText ?? welcomeText

View File

@@ -32,7 +32,7 @@ export function getGridBucket(bucket: `${BucketNameEnum}`) {
export async function uploadFile({
bucketName,
teamId,
tmbId,
uid,
path,
filename,
contentType,
@@ -41,7 +41,7 @@ export async function uploadFile({
}: {
bucketName: `${BucketNameEnum}`;
teamId: string;
tmbId: string;
uid: string; // tmbId / outLinkUId
path: string;
filename: string;
contentType?: string;
@@ -58,7 +58,7 @@ export async function uploadFile({
// Add default metadata
metadata.teamId = teamId;
metadata.tmbId = tmbId;
metadata.uid = uid;
metadata.encoding = encoding;
// create a gridfs bucket

View File

@@ -4,7 +4,7 @@ import path from 'path';
import { BucketNameEnum, bucketNameMap } from '@fastgpt/global/common/file/constants';
import { getNanoid } from '@fastgpt/global/common/string/tools';
type FileType = {
export type FileType = {
fieldname: string;
originalname: string;
encoding: string;
@@ -41,7 +41,7 @@ export const getUploadModel = ({ maxSize = 500 }: { maxSize?: number }) => {
})
}).single('file');
async doUpload<T = Record<string, any>>(
async doUpload<T = any>(
req: NextApiRequest,
res: NextApiResponse,
originBucketName?: `${BucketNameEnum}`

View File

@@ -6,6 +6,7 @@ import {
} from '@fastgpt/global/core/ai/type';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { addLog } from '../../common/system/log';
import { i18nT } from '../../../web/i18n/utils';
export const openaiBaseUrl = process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1';
@@ -62,6 +63,7 @@ export const createChatCompletion = async <T extends CompletionsBodyType>({
}): Promise<{
response: InferResponseType<T>;
isStreamResponse: boolean;
getEmptyResponseTip: () => string;
}> => {
try {
const formatTimeout = timeout ? timeout : body.stream ? 60000 : 600000;
@@ -76,9 +78,21 @@ export const createChatCompletion = async <T extends CompletionsBodyType>({
response !== null &&
('iterator' in response || 'controller' in response);
const getEmptyResponseTip = () => {
addLog.warn(`LLM response empty`, {
baseUrl: userKey?.baseUrl,
requestBody: body
});
if (userKey?.baseUrl) {
return `您的 OpenAI key 没有响应: ${JSON.stringify(body)}`;
}
return i18nT('chat:LLM_model_response_empty');
};
return {
response: response as InferResponseType<T>,
isStreamResponse
isStreamResponse,
getEmptyResponseTip
};
} catch (error) {
addLog.error(`LLM response error`, error);

View File

@@ -17,7 +17,8 @@ export const chatConfigType = {
scheduledTriggerConfig: Object,
chatInputGuide: Object,
fileSelectConfig: Object,
instruction: String
instruction: String,
autoExecute: Object
};
// schema

View File

@@ -46,6 +46,10 @@ const ChatItemSchema = new Schema({
type: Date,
default: () => new Date()
},
hideInUI: {
type: Boolean,
default: false
},
obj: {
// chat role
type: String,

View File

@@ -1,15 +1,6 @@
import type {
AIChatItemType,
ChatItemType,
UserChatItemType
} from '@fastgpt/global/core/chat/type.d';
import axios from 'axios';
import type { AIChatItemType, UserChatItemType } from '@fastgpt/global/core/chat/type.d';
import { MongoApp } from '../app/schema';
import {
ChatItemValueTypeEnum,
ChatRoleEnum,
ChatSourceEnum
} from '@fastgpt/global/core/chat/constants';
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { MongoChatItem } from './chatItemSchema';
import { MongoChat } from './chatSchema';
import { addLog } from '../../common/system/log';
@@ -133,21 +124,15 @@ export async function saveChat({
export const updateInteractiveChat = async ({
chatId,
appId,
teamId,
tmbId,
userInteractiveVal,
aiResponse,
newVariables,
newTitle
newVariables
}: {
chatId: string;
appId: string;
teamId: string;
tmbId: string;
userInteractiveVal: string;
aiResponse: AIChatItemType & { dataId?: string };
newVariables?: Record<string, any>;
newTitle: string;
}) => {
if (!chatId) return;
@@ -232,7 +217,6 @@ export const updateInteractiveChat = async ({
{
$set: {
variables: newVariables,
title: newTitle,
updateTime: new Date()
}
},

View File

@@ -67,7 +67,7 @@ export async function createOneCollection({
fileId,
rawLink,
externalFileId,
...(externalFileId ? { externalFileId } : {}),
externalFileUrl,
rawTextLength,

View File

@@ -118,7 +118,7 @@ try {
{
unique: true,
partialFilterExpression: {
externalFileId: { $exists: true, $ne: '' }
externalFileId: { $exists: true }
}
}
);

View File

@@ -77,7 +77,7 @@ export async function pushDataListToTrainingQueue({
if (trainingMode === TrainingModeEnum.chunk) {
return {
maxToken: vectorModelData.maxToken * 1.3,
maxToken: vectorModelData.maxToken * 1.5,
model: vectorModelData.model,
weight: vectorModelData.weight
};
@@ -125,10 +125,7 @@ export async function pushDataListToTrainingQueue({
const text = item.q + item.a;
// count q token
const token = item.q.length;
if (token > maxToken) {
if (text.length > maxToken) {
filterResult.overToken.push(item);
return;
}

View File

@@ -27,7 +27,6 @@ import { computedMaxToken, llmCompletionsBodyFormat } from '../../../../ai/utils
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
import { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
import { i18nT } from '../../../../../../web/i18n/utils';
type FunctionRunResponseType = {
toolRunResponse: DispatchFlowResponse;
@@ -216,7 +215,11 @@ export const runToolWithFunctionCall = async (
// console.log(JSON.stringify(requestMessages, null, 2));
/* Run llm */
const { response: aiResponse, isStreamResponse } = await createChatCompletion({
const {
response: aiResponse,
isStreamResponse,
getEmptyResponseTip
} = await createChatCompletion({
body: requestBody,
userKey: user.openaiAccount,
options: {
@@ -256,6 +259,9 @@ export const runToolWithFunctionCall = async (
};
}
})();
if (!answer && functionCalls.length === 0) {
return Promise.reject(getEmptyResponseTip());
}
// Run the selected tool.
const toolsRunResponse = (
@@ -549,9 +555,5 @@ async function streamResponse({
}
}
if (!textAnswer && functionCalls.length === 0) {
return Promise.reject(i18nT('chat:LLM_model_response_empty'));
}
return { answer: textAnswer, functionCalls };
}

View File

@@ -29,7 +29,6 @@ import { WorkflowResponseType } from '../../type';
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
import { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
import { i18nT } from '../../../../../../web/i18n/utils';
type FunctionCallCompletion = {
id: string;
@@ -225,7 +224,11 @@ export const runToolWithPromptCall = async (
// console.log(JSON.stringify(requestMessages, null, 2));
/* Run llm */
const { response: aiResponse, isStreamResponse } = await createChatCompletion({
const {
response: aiResponse,
isStreamResponse,
getEmptyResponseTip
} = await createChatCompletion({
body: requestBody,
userKey: user.openaiAccount,
options: {
@@ -251,8 +254,11 @@ export const runToolWithPromptCall = async (
return result.choices?.[0]?.message?.content || '';
}
})();
const { answer: replaceAnswer, toolJson } = parseAnswer(answer);
if (!answer && !toolJson) {
return Promise.reject(getEmptyResponseTip());
}
// No tools
if (!toolJson) {
if (replaceAnswer === ERROR_TEXT) {
@@ -534,9 +540,6 @@ async function streamResponse({
}
}
if (!textAnswer) {
return Promise.reject(i18nT('chat:LLM_model_response_empty'));
}
return { answer: textAnswer.trim() };
}

View File

@@ -272,7 +272,11 @@ export const runToolWithToolChoice = async (
);
// console.log(JSON.stringify(requestBody, null, 2), '==requestBody');
/* Run llm */
const { response: aiResponse, isStreamResponse } = await createChatCompletion({
const {
response: aiResponse,
isStreamResponse,
getEmptyResponseTip
} = await createChatCompletion({
body: requestBody,
userKey: user.openaiAccount,
options: {
@@ -336,6 +340,9 @@ export const runToolWithToolChoice = async (
};
}
})();
if (!answer && toolCalls.length === 0) {
return Promise.reject(getEmptyResponseTip());
}
// Run the selected tool by LLM.
const toolsRunResponse = (
@@ -645,9 +652,5 @@ async function streamResponse({
}
}
if (!textAnswer && toolCalls.length === 0) {
return Promise.reject(i18nT('chat:LLM_model_response_empty'));
}
return { answer: textAnswer, toolCalls };
}

View File

@@ -33,15 +33,13 @@ import { getLLMModel, ModelTypeEnum } from '../../../ai/model';
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { getHistories } from '../utils';
import { checkQuoteQAValue, getHistories } from '../utils';
import { filterSearchResultsByMaxChars } from '../../utils';
import { getHistoryPreview } from '@fastgpt/global/core/chat/utils';
import { addLog } from '../../../../common/system/log';
import { computedMaxToken, llmCompletionsBodyFormat } from '../../../ai/utils';
import { WorkflowResponseType } from '../type';
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
import { AiChatQuoteRoleType } from '@fastgpt/global/core/workflow/template/system/aiChat/type';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { getFileContentFromLinks, getHistoryFileLinks } from '../tools/readFiles';
import { parseUrlToFileType } from '@fastgpt/global/common/file/tools';
import { i18nT } from '../../../../../web/i18n/utils';
@@ -93,6 +91,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
stream = stream && isResponseAnswerText;
const chatHistories = getHistories(history, histories);
quoteQA = checkQuoteQAValue(quoteQA);
const modelConstantsData = getLLMModel(model);
if (!modelConstantsData) {
@@ -169,99 +168,91 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
modelConstantsData
);
// console.log(JSON.stringify(requestBody, null, 2), '===');
try {
const { response, isStreamResponse } = await createChatCompletion({
body: requestBody,
userKey: user.openaiAccount,
options: {
headers: {
Accept: 'application/json, text/plain, */*'
}
const { response, isStreamResponse, getEmptyResponseTip } = await createChatCompletion({
body: requestBody,
userKey: user.openaiAccount,
options: {
headers: {
Accept: 'application/json, text/plain, */*'
}
});
}
});
const { answerText } = await (async () => {
if (res && isStreamResponse) {
// sse response
const { answer } = await streamResponse({
res,
stream: response,
workflowStreamResponse
const { answerText } = await (async () => {
if (res && isStreamResponse) {
// sse response
const { answer } = await streamResponse({
res,
stream: response,
workflowStreamResponse
});
return {
answerText: answer
};
} else {
const unStreamResponse = response as ChatCompletion;
const answer = unStreamResponse.choices?.[0]?.message?.content || '';
if (stream) {
// Some models do not support streaming
workflowStreamResponse?.({
event: SseResponseEventEnum.fastAnswer,
data: textAdaptGptResponse({
text: answer
})
});
if (!answer) {
return Promise.reject(i18nT('chat:LLM_model_response_empty'));
}
return {
answerText: answer
};
} else {
const unStreamResponse = response as ChatCompletion;
const answer = unStreamResponse.choices?.[0]?.message?.content || '';
if (stream) {
// Some models do not support streaming
workflowStreamResponse?.({
event: SseResponseEventEnum.fastAnswer,
data: textAdaptGptResponse({
text: answer
})
});
}
return {
answerText: answer
};
}
})();
const completeMessages = requestMessages.concat({
role: ChatCompletionRequestMessageRoleEnum.Assistant,
content: answerText
});
const chatCompleteMessages = GPTMessages2Chats(completeMessages);
return {
answerText: answer
};
}
})();
const tokens = await countMessagesTokens(chatCompleteMessages);
const { totalPoints, modelName } = formatModelChars2Points({
model,
if (!answerText) {
return Promise.reject(getEmptyResponseTip());
}
const completeMessages = requestMessages.concat({
role: ChatCompletionRequestMessageRoleEnum.Assistant,
content: answerText
});
const chatCompleteMessages = GPTMessages2Chats(completeMessages);
const tokens = await countMessagesTokens(chatCompleteMessages);
const { totalPoints, modelName } = formatModelChars2Points({
model,
tokens,
modelType: ModelTypeEnum.llm
});
return {
answerText,
[DispatchNodeResponseKeyEnum.nodeResponse]: {
totalPoints: user.openaiAccount?.key ? 0 : totalPoints,
model: modelName,
tokens,
modelType: ModelTypeEnum.llm
});
return {
answerText,
[DispatchNodeResponseKeyEnum.nodeResponse]: {
query: `${userChatInput}`,
maxToken: max_tokens,
historyPreview: getHistoryPreview(
chatCompleteMessages,
10000,
modelConstantsData.vision && aiChatVision
),
contextTotalLen: completeMessages.length
},
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [
{
moduleName: name,
totalPoints: user.openaiAccount?.key ? 0 : totalPoints,
model: modelName,
tokens,
query: `${userChatInput}`,
maxToken: max_tokens,
historyPreview: getHistoryPreview(
chatCompleteMessages,
10000,
modelConstantsData.vision && aiChatVision
),
contextTotalLen: completeMessages.length
},
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [
{
moduleName: name,
totalPoints: user.openaiAccount?.key ? 0 : totalPoints,
model: modelName,
tokens
}
],
[DispatchNodeResponseKeyEnum.toolResponses]: answerText,
history: chatCompleteMessages
};
} catch (error) {
if (user.openaiAccount?.baseUrl) {
return Promise.reject(`您的 OpenAI key 出错了: ${getErrText(error)}`);
}
return Promise.reject(error);
}
tokens
}
],
[DispatchNodeResponseKeyEnum.toolResponses]: answerText,
history: chatCompleteMessages
};
};
async function filterDatasetQuote({

View File

@@ -209,7 +209,6 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
try {
const { formatResponse, rawResponse } = await (async () => {
const systemPluginCb = global.systemPluginCb;
console.log(systemPluginCb, '-=', httpReqUrl);
if (systemPluginCb[httpReqUrl]) {
const pluginResult = await replaceSystemPluginResponse({
response: await systemPluginCb[httpReqUrl](requestBody),
@@ -395,7 +394,7 @@ async function replaceSystemPluginResponse({
response[key] = `${ReadFileBaseUrl}/${filename}?token=${await createFileToken({
bucketName: 'chat',
teamId,
tmbId,
uid: tmbId,
fileId
})}`;
} catch (error) {}

View File

@@ -13,6 +13,7 @@ import { responseWrite } from '../../../common/response';
import { NextApiResponse } from 'next';
import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { getNanoid } from '@fastgpt/global/common/string/tools';
import { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
export const getWorkflowResponseWrite = ({
res,
@@ -87,27 +88,6 @@ export const filterToolNodeIdByEdges = ({
.map((edge) => edge.target);
};
// export const checkTheModuleConnectedByTool = (
// modules: StoreNodeItemType[],
// node: StoreNodeItemType
// ) => {
// let sign = false;
// const toolModules = modules.filter((item) => item.flowNodeType === FlowNodeTypeEnum.tools);
// toolModules.forEach((item) => {
// const toolOutput = item.outputs.find(
// (output) => output.key === NodeOutputKeyEnum.selectedTools
// );
// toolOutput?.targets.forEach((target) => {
// if (target.moduleId === node.moduleId) {
// sign = true;
// }
// });
// });
// return sign;
// };
export const getHistories = (history?: ChatItemType[] | number, histories: ChatItemType[] = []) => {
if (!history) return [];
@@ -149,6 +129,13 @@ export const valueTypeFormat = (value: any, type?: WorkflowIOValueTypeEnum) => {
return value;
};
export const checkQuoteQAValue = (quoteQA: SearchDataResponseItemType[] = []) => {
if (quoteQA.some((item) => !item.q || !item.datasetId)) {
return undefined;
}
return quoteQA;
};
/* remove system variable */
export const removeSystemVariable = (variables: Record<string, any>) => {
const copyVariables = { ...variables };

View File

@@ -48,7 +48,8 @@ const OutLinkSchema = new Schema({
default: false
},
showNodeStatus: {
type: Boolean
type: Boolean,
default: true
},
showRawSource: {
type: Boolean

View File

@@ -7,7 +7,7 @@ import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { OwnerPermissionVal, ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { Permission } from '@fastgpt/global/support/permission/controller';
export async function authFile({
export const authCollectionFile = async ({
fileId,
per = OwnerPermissionVal,
...props
@@ -17,7 +17,7 @@ export async function authFile({
AuthResponseType & {
file: DatasetFileSchema;
}
> {
> => {
const authRes = await parseHeaderCert(props);
const { teamId, tmbId } = authRes;
@@ -33,7 +33,7 @@ export async function authFile({
const permission = new Permission({
per: ReadPermissionVal,
isOwner: file.metadata?.tmbId === tmbId
isOwner: file.metadata?.uid === tmbId || file.metadata?.tmbId === tmbId
});
if (!permission.checkPer(per)) {
@@ -45,4 +45,4 @@ export async function authFile({
permission,
file
};
}
};

View File

@@ -413,7 +413,8 @@ export const createFileToken = (data: FileTokenQuery) => {
return Promise.reject('System unset FILE_TOKEN_KEY');
}
const expireMinutes = bucketNameMap[data.bucketName].previewExpireMinutes;
const expireMinutes =
data.customExpireMinutes ?? bucketNameMap[data.bucketName].previewExpireMinutes;
const expiredTime = Math.floor(addMinutes(new Date(), expireMinutes).getTime() / 1000);
const key = (process.env.FILE_TOKEN_KEY as string) ?? 'filetoken';
@@ -435,14 +436,14 @@ export const authFileToken = (token?: string) =>
const key = (process.env.FILE_TOKEN_KEY as string) ?? 'filetoken';
jwt.verify(token, key, function (err, decoded: any) {
if (err || !decoded.bucketName || !decoded?.teamId || !decoded?.tmbId || !decoded?.fileId) {
if (err || !decoded.bucketName || !decoded?.teamId || !decoded?.fileId) {
reject(ERROR_ENUM.unAuthFile);
return;
}
resolve({
bucketName: decoded.bucketName,
teamId: decoded.teamId,
tmbId: decoded.tmbId,
uid: decoded.uid,
fileId: decoded.fileId
});
});

View File

@@ -62,14 +62,14 @@ export async function authOutLinkValid<T extends OutlinkAppType = undefined>({
if (!shareId) {
return Promise.reject(OutLinkErrEnum.linkUnInvalid);
}
const shareChat = (await MongoOutLink.findOne({ shareId }).lean()) as OutLinkSchema<T>;
const outLinkConfig = (await MongoOutLink.findOne({ shareId }).lean()) as OutLinkSchema<T>;
if (!shareChat) {
if (!outLinkConfig) {
return Promise.reject(OutLinkErrEnum.linkUnInvalid);
}
return {
appId: shareChat.appId,
shareChat
appId: outLinkConfig.appId,
outLinkConfig
};
}

View File

@@ -2,6 +2,7 @@ import { Permission } from '@fastgpt/global/support/permission/controller';
import { ApiRequestProps } from '../../type/next';
import type { PermissionValueType } from '@fastgpt/global/support/permission/type';
import { RequireAtLeastOne } from '@fastgpt/global/common/type/utils';
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
export type ReqHeaderAuthType = {
cookie?: string;

View File

@@ -23,9 +23,6 @@ declare global {
var whisperModel: WhisperModelType;
var reRankModels: ReRankModelItemType[];
var systemLoadedGlobalVariables: boolean;
var systemLoadedGlobalConfig: boolean;
var workerPoll: Record<WorkerNameEnum, WorkerPool>;
var appMarketTemplates: TemplateMarketItemType[];
}

View File

@@ -10,6 +10,8 @@ export const hasHttps = () => {
return window.location.protocol === 'https:';
};
export const subRoute = process.env.NEXT_PUBLIC_BASE_URL;
export const getWebReqUrl = (url: string = '') => {
if (!url) return '/';
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;

View File

@@ -0,0 +1,41 @@
import React from 'react';
import { Flex, FlexProps } from '@chakra-ui/react';
import MyIcon from './index';
type Props = FlexProps & {
icon: string;
size?: string;
onClick?: () => void;
hoverColor?: string;
};
const MyIconButton = ({
icon,
onClick,
hoverColor = 'primary.600',
size = '1rem',
...props
}: Props) => {
return (
<Flex
mr={1}
p={1}
color={'myGray.500'}
rounded={'sm'}
alignItems={'center'}
bg={'transparent'}
transition={'background 0.1s'}
cursor={'pointer'}
_hover={{
bg: 'myGray.05',
color: hoverColor
}}
onClick={onClick}
{...props}
>
<MyIcon name={icon as any} w={size} />
</Flex>
);
};
export default MyIconButton;

View File

@@ -5,6 +5,7 @@ export const iconPaths = {
change: () => import('./icons/change.svg'),
chatSend: () => import('./icons/chatSend.svg'),
check: () => import('./icons/check.svg'),
checkCircle: () => import('./icons/checkCircle.svg'),
closeSolid: () => import('./icons/closeSolid.svg'),
collectionLight: () => import('./icons/collectionLight.svg'),
collectionSolid: () => import('./icons/collectionSolid.svg'),
@@ -101,6 +102,7 @@ export const iconPaths = {
'core/app/schedulePlan': () => import('./icons/core/app/schedulePlan.svg'),
'core/app/simpleBot': () => import('./icons/core/app/simpleBot.svg'),
'core/app/simpleMode/ai': () => import('./icons/core/app/simpleMode/ai.svg'),
'core/app/simpleMode/autoExec': () => import('./icons/core/app/simpleMode/autoExec.svg'),
'core/app/simpleMode/chat': () => import('./icons/core/app/simpleMode/chat.svg'),
'core/app/simpleMode/dataset': () => import('./icons/core/app/simpleMode/dataset.svg'),
'core/app/simpleMode/file': () => import('./icons/core/app/simpleMode/file.svg'),
@@ -183,6 +185,7 @@ export const iconPaths = {
'core/workflow/debugNext': () => import('./icons/core/workflow/debugNext.svg'),
'core/workflow/debugResult': () => import('./icons/core/workflow/debugResult.svg'),
'core/workflow/edgeArrow': () => import('./icons/core/workflow/edgeArrow.svg'),
'core/workflow/edgeArrowBold': () => import('./icons/core/workflow/edgeArrowBold.svg'),
'core/workflow/grout': () => import('./icons/core/workflow/grout.svg'),
'core/workflow/inputType/array': () => import('./icons/core/workflow/inputType/array.svg'),
'core/workflow/inputType/customVariable': () =>

View File

@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 17" fill="none">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.5587 3.69438C13.9492 3.30386 14.5824 3.30386 14.9729 3.69438C15.3634 4.08491 15.3634 4.71807 14.9729 5.1086L7.63956 12.4419C7.24904 12.8325 6.61587 12.8325 6.22535 12.4419L2.89201 9.1086C2.50149 8.71807 2.50149 8.08491 2.89201 7.69438C3.28254 7.30386 3.9157 7.30386 4.30623 7.69438L6.93245 10.3206L13.5587 3.69438Z"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.8043 3.52859C14.0646 3.78894 14.0646 4.21105 13.8043 4.4714L6.47092 11.8047C6.21057 12.0651 5.78846 12.0651 5.52811 11.8047L2.19477 8.4714C1.93442 8.21105 1.93442 7.78894 2.19477 7.52859C2.45512 7.26824 2.87723 7.26824 3.13758 7.52859L5.99951 10.3905L12.8614 3.52859C13.1218 3.26824 13.5439 3.26824 13.8043 3.52859Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 452 B

After

Width:  |  Height:  |  Size: 453 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 17" fill="none">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.1848 3.90471C9.12756 3.43362 7.94633 3.31691 6.81731 3.572C5.6883 3.82708 4.67198 4.44029 3.91995 5.32018C3.16791 6.20006 2.72044 7.29947 2.64429 8.45443C2.56813 9.6094 2.86736 10.758 3.49735 11.7291C4.12734 12.7001 5.05433 13.4414 6.14008 13.8426C7.22582 14.2437 8.41215 14.2831 9.52213 13.9549C10.6321 13.6267 11.6063 12.9485 12.2993 12.0215C12.9923 11.0944 13.3671 9.96815 13.3678 8.81067V8.2559C13.3678 7.88771 13.6663 7.58924 14.0345 7.58924C14.4027 7.58924 14.7011 7.88771 14.7011 8.2559V8.81105C14.7003 10.2561 14.2324 11.6625 13.3672 12.8198C12.502 13.9771 11.2859 14.8238 9.90017 15.2335C8.51447 15.6432 7.03346 15.594 5.67801 15.0933C4.32255 14.5925 3.16529 13.667 2.37881 12.4548C1.59232 11.2425 1.21877 9.80857 1.31384 8.3667C1.40892 6.92484 1.96754 5.55233 2.90638 4.45388C3.84523 3.35543 5.114 2.5899 6.52347 2.27144C7.93294 1.95299 9.4076 2.09869 10.7275 2.6868C11.0638 2.83666 11.215 3.23077 11.0651 3.56709C10.9153 3.9034 10.5211 4.05456 10.1848 3.90471ZM14.5056 3.50856C14.7661 3.76878 14.7663 4.19089 14.5061 4.45137L8.47187 10.4917C8.34686 10.6168 8.17726 10.6871 8.00039 10.6871C7.82352 10.6872 7.65389 10.617 7.52882 10.4919L5.71855 8.68161C5.4582 8.42126 5.4582 7.99915 5.71855 7.7388C5.9789 7.47846 6.40101 7.47846 6.66136 7.7388L7.99999 9.07744L13.5628 3.50904C13.823 3.24856 14.2452 3.24835 14.5056 3.50856Z" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1 +1,6 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1694403033666" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4053" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M1016.32 494.08l-143.872-143.36c-9.728-9.728-26.112-9.728-35.84 0-9.728 9.728-9.728 26.112 0 35.84L936.96 486.4h-399.36V87.04l99.84 100.352c9.728 9.728 26.112 9.728 35.84 0 9.728-9.728 9.728-26.112 0-35.84l-143.36-143.872c-9.728-9.728-26.112-9.728-35.84 0l-143.36 143.872c-9.728 9.728-9.728 26.112 0 35.84 9.728 9.728 26.112 9.728 35.84 0L486.4 87.04v399.36H87.04l100.352-99.84c9.728-9.728 9.728-26.112 0-35.84-9.728-9.728-26.112-9.728-35.84 0l-143.872 143.36c-9.728 9.728-9.728 26.112 0 35.84l143.872 143.36c9.728 9.728 26.112 9.728 35.84 0 9.728-9.728 9.728-26.112 0-35.84L87.04 537.6h399.36v399.36l-99.84-100.352c-9.728-9.728-26.112-9.728-35.84 0-9.728 9.728-9.728 26.112 0 35.84l143.36 143.872c9.728 9.728 26.112 9.728 35.84 0l143.36-143.872c9.728-9.728 9.728-26.112 0-35.84-9.728-9.728-26.112-9.728-35.84 0L537.6 936.96v-399.36h399.36l-100.352 99.84c-9.728 9.728-9.728 26.112 0 35.84 9.728 9.728 26.112 9.728 35.84 0l143.872-143.36c10.24-9.728 10.24-26.112 0-35.84z" p-id="4054"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none">
<path d="M8.47188 1.52653C8.34159 1.39624 8.17079 1.33115 8.00003 1.33127C7.82926 1.33115 7.65847 1.39624 7.52818 1.52653C7.52123 1.53348 7.51447 1.54054 7.5079 1.54771L6.11486 2.94074C5.85451 3.20109 5.85451 3.6232 6.11486 3.88355C6.37521 4.1439 6.79732 4.1439 7.05767 3.88355L7.33381 3.60741V5.99835C7.33381 6.36654 7.63229 6.66502 8.00048 6.66502C8.36867 6.66502 8.66714 6.36654 8.66714 5.99835V3.60831L8.94239 3.88355C9.20274 4.1439 9.62485 4.1439 9.8852 3.88355C10.1455 3.6232 10.1455 3.20109 9.8852 2.94074L8.49216 1.54771C8.48559 1.54054 8.47883 1.53348 8.47188 1.52653Z" />
<path d="M7.33381 12.3926V10.0039C7.33381 9.6357 7.63229 9.33723 8.00048 9.33723C8.36867 9.33723 8.66714 9.6357 8.66714 10.0039V12.3917L8.94239 12.1164C9.20274 11.8561 9.62485 11.8561 9.8852 12.1164C10.1455 12.3768 10.1455 12.7989 9.8852 13.0593L8.49216 14.4523C8.48559 14.4595 8.47883 14.4665 8.47188 14.4735C8.34159 14.6038 8.17079 14.6688 8.00003 14.6687C7.82926 14.6688 7.65847 14.6038 7.52818 14.4735C7.52123 14.4665 7.51447 14.4595 7.5079 14.4523L6.11486 13.0593C5.85451 12.7989 5.85451 12.3768 6.11486 12.1164C6.37521 11.8561 6.79732 11.8561 7.05767 12.1164L7.33381 12.3926Z" />
<path d="M6.0646 7.33378C6.43279 7.33378 6.73126 7.63226 6.73126 8.00045C6.73126 8.36864 6.43279 8.66711 6.0646 8.66711H3.60834L3.88358 8.94236C4.14393 9.20271 4.14393 9.62482 3.88358 9.88517C3.62323 10.1455 3.20112 10.1455 2.94077 9.88517L1.54774 8.49213C1.54057 8.48556 1.53351 8.4788 1.52656 8.47185C1.39627 8.34156 1.33118 8.17075 1.3313 7.99998C1.33119 7.82922 1.39628 7.65843 1.52656 7.52815C1.53351 7.5212 1.54057 7.51444 1.54774 7.50786L2.94077 6.11483C3.20112 5.85448 3.62323 5.85448 3.88358 6.11483C4.14393 6.37518 4.14393 6.79729 3.88358 7.05764L3.60744 7.33378H6.0646Z" />
<path d="M13.0593 6.11483L14.4523 7.50786C14.4595 7.51444 14.4666 7.5212 14.4735 7.52815C14.6038 7.65843 14.6689 7.82923 14.6688 8C14.6689 8.17076 14.6038 8.34156 14.4735 8.47185C14.4666 8.4788 14.4595 8.48556 14.4523 8.49213L13.0593 9.88517C12.799 10.1455 12.3768 10.1455 12.1165 9.88517C11.8562 9.62482 11.8562 9.20271 12.1165 8.94236L12.3911 8.66779H9.92959C9.5614 8.66779 9.26292 8.36931 9.26292 8.00112C9.26292 7.63293 9.5614 7.33445 9.92959 7.33445H12.3933L12.1165 7.05764C11.8562 6.79729 11.8562 6.37518 12.1165 6.11483C12.3769 5.85448 12.799 5.85448 13.0593 6.11483Z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21" fill="none">
<path d="M7.56249 11.1348L9.12024 7.33546C9.17155 7.21031 9.2934 7.12858 9.42866 7.12858H11.6153C11.857 7.12858 12.0184 7.37785 11.9194 7.5984L10.9629 9.72956C10.9134 9.83984 10.9941 9.96447 11.1149 9.96447H12.7714C13.0487 9.96447 13.2048 10.2834 13.0346 10.5024L9.93738 14.4874C9.73038 14.7537 9.30408 14.5793 9.34309 14.2443L9.62999 11.7805C9.64152 11.6815 9.56413 11.5946 9.46444 11.5946H7.87091C7.63386 11.5946 7.47257 11.3541 7.56249 11.1348Z" fill="#8774EE"/>
<path d="M3.68233 14.3773C3.28604 14.6067 2.77464 14.4728 2.58571 14.0557C1.82751 12.3817 1.64076 10.4957 2.06882 8.69266C2.561 6.61955 3.82859 4.81371 5.61106 3.64631C7.39354 2.47891 9.55548 2.03863 11.6525 2.41596C13.4764 2.74413 15.1306 3.66906 16.3621 5.03305C16.6689 5.37293 16.5873 5.89525 16.2187 6.16683C15.85 6.43841 15.3344 6.3554 15.0192 6.02321C14.0456 4.99697 12.7652 4.301 11.3589 4.04796C9.67911 3.74571 7.94736 4.09838 6.51957 5.03349C5.09178 5.9686 4.07642 7.4151 3.68218 9.07569C3.35212 10.4659 3.47839 11.9178 4.03001 13.2204C4.20857 13.6421 4.07861 14.1479 3.68233 14.3773Z" fill="#8774EE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.04324 13.2533C4.0589 13.2943 4.07172 13.336 4.08171 13.3781C4.17284 13.7615 4.0302 14.1759 3.68233 14.3773C3.28604 14.6067 2.77464 14.4728 2.58571 14.0557C2.55736 13.9931 2.52981 13.9302 2.50307 13.867C2.48986 13.8358 2.47685 13.8046 2.46403 13.7733C1.80857 12.1713 1.66467 10.395 2.06882 8.69266C2.561 6.61955 3.82859 4.81371 5.61106 3.64631C7.39354 2.47891 9.55548 2.03863 11.6525 2.41596C13.3745 2.7258 14.9453 3.5676 16.1518 4.80865C16.1754 4.83292 16.1989 4.85734 16.2222 4.88192C16.2694 4.93168 16.316 4.98206 16.3621 5.03305C16.6689 5.37293 16.5873 5.89525 16.2187 6.16683C15.895 6.40524 15.4582 6.37039 15.1431 6.1336C15.1085 6.10762 15.0754 6.07921 15.0441 6.04846C15.0357 6.04021 15.0274 6.03179 15.0192 6.02321C14.0456 4.99697 12.7652 4.301 11.3589 4.04796C9.67911 3.74571 7.94736 4.09838 6.51957 5.03349C5.09178 5.9686 4.07642 7.4151 3.68218 9.07569C3.35212 10.4659 3.47839 11.9178 4.03001 13.2204C4.03463 13.2313 4.03904 13.2423 4.04324 13.2533Z" fill="#8774EE"/>
<path d="M17.123 7.77804C17.5469 7.60478 18.0353 7.80718 18.1656 8.24615C18.6407 9.84662 18.6258 11.5599 18.1122 13.1618C17.5139 15.028 16.277 16.6236 14.6189 17.6682C12.9608 18.7129 10.9876 19.1397 9.04598 18.8738C7.37931 18.6455 5.82746 17.9193 4.58891 16.7998C4.24921 16.4928 4.27748 15.9649 4.61675 15.6574C4.95601 15.3498 5.47737 15.3802 5.82456 15.6788C6.79537 16.5136 7.9909 17.0556 9.27099 17.2309C10.8262 17.444 12.4068 17.102 13.735 16.2652C15.0631 15.4285 16.0539 14.1504 16.5332 12.6556C16.9276 11.4252 16.9548 10.1128 16.6209 8.87674C16.5015 8.43469 16.6992 7.95131 17.123 7.77804Z" fill="#8774EE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.6123 8.8424C16.615 8.85387 16.6178 8.86532 16.6209 8.87674C16.9548 10.1128 16.9276 11.4252 16.5332 12.6556C16.0539 14.1504 15.0631 15.4285 13.735 16.2652C12.4068 17.102 10.8262 17.444 9.27099 17.2309C7.9909 17.0556 6.79537 16.5136 5.82456 15.6788C5.81558 15.671 5.8065 15.6635 5.7973 15.6561C5.76301 15.6287 5.72719 15.6038 5.69016 15.5815C5.3527 15.3778 4.91457 15.3874 4.61675 15.6574C4.27748 15.9649 4.24921 16.4928 4.58891 16.7998C4.63988 16.8459 4.69138 16.8913 4.74339 16.936C4.76907 16.9581 4.79489 16.98 4.82082 17.0018C6.01868 18.0067 7.48176 18.6596 9.04598 18.8738C10.9876 19.1397 12.9608 18.7129 14.6189 17.6682C16.277 16.6236 17.5139 15.028 18.1122 13.1618C18.5942 11.6584 18.637 10.0568 18.2476 8.54252C18.2392 8.50973 18.2306 8.47699 18.2217 8.44429C18.2038 8.37806 18.1851 8.31201 18.1656 8.24615C18.0353 7.80718 17.5469 7.60478 17.123 7.77804C16.751 7.93014 16.5532 8.32121 16.5912 8.71352C16.5953 8.75657 16.6024 8.79963 16.6123 8.8424Z" fill="#8774EE"/>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 16" fill="none">
<path d="M3.07373 0.535309C2.48828 -0.0505066 1.53809 -0.0505066 0.952637 0.535309C0.366699 1.12106 0.366699 2.07083 0.952637 2.65665L6.26123 7.96536L0.952637 13.2737C0.367188 13.8595 0.367188 14.8092 0.952637 15.395C1.53857 15.9807 2.48828 15.9807 3.07422 15.395L9.43799 9.03104C9.66016 8.80875 9.7959 8.53372 9.84961 8.24643C9.90283 7.97018 9.87842 7.68179 9.77588 7.41672C9.70264 7.22818 9.58984 7.05142 9.43799 6.89926L3.07373 0.535309Z"/>
</svg>

After

Width:  |  Height:  |  Size: 525 B

View File

@@ -1,7 +1,7 @@
import React from 'react';
import React, { ForwardedRef, forwardRef } from 'react';
import { Image, ImageProps } from '@chakra-ui/react';
import { getWebReqUrl } from '../../../common/system/utils';
const MyImage = (props: ImageProps) => {
const MyImage = (props: ImageProps, ref?: ForwardedRef<any>) => {
return <Image {...props} src={getWebReqUrl(props.src)} alt={props.alt || ''} />;
};
export default React.memo(MyImage);
export default forwardRef(MyImage);

View File

@@ -7,22 +7,26 @@ import {
useOutsideClick,
MenuButton,
MenuItemProps,
PlacementWithLogical
PlacementWithLogical,
AvatarProps,
BoxProps,
DividerProps
} from '@chakra-ui/react';
import MyDivider from '../MyDivider';
import type { IconNameType } from '../Icon/type';
import { useSystem } from '../../../hooks/useSystem';
import Avatar from '../Avatar';
export type MenuItemType = 'primary' | 'danger';
export type MenuItemType = 'primary' | 'danger' | 'gray' | 'grayBg';
export type MenuSizeType = 'sm' | 'md' | 'xs' | 'mini';
export type Props = {
width?: number | string;
offset?: [number, number];
Button: React.ReactNode;
trigger?: 'hover' | 'click';
iconSize?: string;
iconRadius?: string;
size?: MenuSizeType;
placement?: PlacementWithLogical;
menuList: {
@@ -39,18 +43,9 @@ export type Props = {
}[];
};
const MyMenu = ({
width = 'auto',
trigger = 'hover',
offset,
iconSize = '1rem',
Button,
menuList,
iconRadius,
placement = 'bottom-start'
}: Props) => {
const typeMapStyle: Record<MenuItemType, MenuItemProps> = {
primary: {
const typeMapStyle: Record<MenuItemType, { styles: MenuItemProps; iconColor?: string }> = {
primary: {
styles: {
_hover: {
backgroundColor: 'primary.50',
color: 'primary.600'
@@ -64,7 +59,44 @@ const MyMenu = ({
color: 'primary.600'
}
},
danger: {
iconColor: 'myGray.600'
},
gray: {
styles: {
_hover: {
backgroundColor: 'myGray.05',
color: 'primary.600'
},
_focus: {
backgroundColor: 'myGray.05',
color: 'primary.600'
},
_active: {
backgroundColor: 'myGray.05',
color: 'primary.600'
}
},
iconColor: 'myGray.400'
},
grayBg: {
styles: {
_hover: {
backgroundColor: 'myGray.05',
color: 'primary.600'
},
_focus: {
backgroundColor: 'myGray.05',
color: 'primary.600'
},
_active: {
backgroundColor: 'myGray.05',
color: 'primary.600'
}
},
iconColor: 'myGray.600'
},
danger: {
styles: {
color: 'red.600',
_hover: {
background: 'red.1'
@@ -75,9 +107,97 @@ const MyMenu = ({
_active: {
background: 'red.1'
}
},
iconColor: 'red.600'
}
};
const sizeMapStyle: Record<
MenuSizeType,
{
iconStyle: AvatarProps;
labelStyle: BoxProps;
dividerStyle: DividerProps;
menuItemStyle: MenuItemProps;
}
> = {
mini: {
iconStyle: {
w: '14px'
},
labelStyle: {
fontSize: 'mini'
},
dividerStyle: {
my: 0.5
},
menuItemStyle: {
py: 1.5,
px: 2
}
};
},
xs: {
iconStyle: {
w: '14px'
},
labelStyle: {
fontSize: 'sm'
},
dividerStyle: {
my: 0.5
},
menuItemStyle: {
py: 1.5,
px: 2
}
},
sm: {
iconStyle: {
w: '1rem'
},
labelStyle: {
fontSize: 'sm'
},
dividerStyle: {
my: 1
},
menuItemStyle: {
py: 2,
px: 3,
_notLast: {
mb: 0.5
}
}
},
md: {
iconStyle: {
w: '2rem',
borderRadius: '6px'
},
labelStyle: {
fontSize: 'sm'
},
dividerStyle: {
my: 1
},
menuItemStyle: {
py: 2,
px: 3,
_notLast: {
mb: 0.5
}
}
}
};
const MyMenu = ({
width = 'auto',
trigger = 'hover',
size = 'sm',
offset,
Button,
menuList,
placement = 'bottom-start'
}: Props) => {
const { isPc } = useSystem();
const ref = useRef<HTMLDivElement>(null);
const closeTimer = useRef<any>();
@@ -165,7 +285,7 @@ const MyMenu = ({
return (
<Box key={i}>
{item.label && <Box fontSize={'sm'}>{item.label}</Box>}
{i !== 0 && <MyDivider h={'1.5px'} my={1} />}
{i !== 0 && <MyDivider h={'1.5px'} {...sizeMapStyle[size].dividerStyle} />}
{item.children.map((child, index) => (
<MenuItem
key={index}
@@ -177,29 +297,36 @@ const MyMenu = ({
child.onClick();
}
}}
py={2}
px={3}
alignItems={'center'}
fontSize={'sm'}
color={child.isActive ? 'primary.700' : 'myGray.600'}
whiteSpace={'pre-wrap'}
_notLast={{ mb: 0.5 }}
{...typeMapStyle[child.type || 'primary']}
{...typeMapStyle[child.type || 'primary'].styles}
{...sizeMapStyle[size].menuItemStyle}
{...child.menuItemStyles}
>
{!!child.icon && (
<Avatar
src={child.icon as any}
borderRadius={iconRadius}
w={iconSize}
mr={3}
mr={2}
{...sizeMapStyle[size].iconStyle}
color={
child.isActive
? 'inherit'
: typeMapStyle[child.type || 'primary'].iconColor
}
sx={{
'[role="menuitem"]:hover &': {
color: 'inherit'
}
}}
/>
)}
<Box w={'100%'}>
<Box
w={'100%'}
color={child.description ? 'myGray.900' : 'inherit'}
fontSize={'sm'}
{...sizeMapStyle[size].labelStyle}
>
{child.label}
</Box>

View File

@@ -60,7 +60,9 @@ export const MultipleRowSelect = ({
const newValue = [...cloneValue];
if (item.value === selectedValue) {
newValue[index] = undefined;
for (let i = index; i < newValue.length; i++) {
newValue[i] = undefined;
}
setCloneValue(newValue);
onSelect(newValue);
} else {

View File

@@ -18,12 +18,13 @@ const FillRowTabs = ({ list, value, onChange, py = '7px', px = '12px', ...props
display={'inline-flex'}
px={'3px'}
py={'3px'}
borderRadius={'md'}
borderRadius={'sm'}
borderWidth={'1px'}
borderColor={'borderColor.base'}
borderColor={'myGray.200'}
bg={'myGray.50'}
gap={'4px'}
fontSize={'sm'}
fontWeight={'medium'}
{...props}
>
{list.map((item) => (
@@ -33,7 +34,7 @@ const FillRowTabs = ({ list, value, onChange, py = '7px', px = '12px', ...props
alignItems={'center'}
justifyContent={'center'}
cursor={'pointer'}
borderRadius={'md'}
borderRadius={'xs'}
px={px}
py={py}
userSelect={'none'}
@@ -45,10 +46,14 @@ const FillRowTabs = ({ list, value, onChange, py = '7px', px = '12px', ...props
color: 'primary.600'
}
: {
color: 'myGray.500',
_hover: {
color: 'primary.600'
},
onClick: () => onChange(item.value)
})}
>
{item.icon && <MyIcon name={item.icon as any} mr={1} w={'14px'} />}
{item.icon && <MyIcon name={item.icon as any} mr={1.5} w={'18px'} />}
<Box>{item.label}</Box>
</Flex>
))}

View File

@@ -224,8 +224,8 @@ const JSONEditor = ({
{resize && (
<Box
position={'absolute'}
right={'0'}
bottom={'0'}
right={'-2'}
bottom={'-3'}
zIndex={10}
cursor={'ns-resize'}
px={'4px'}
@@ -269,6 +269,8 @@ const JSONEditor = ({
fontSize={'xs'}
color={'myGray.500'}
display={placeholderDisplay}
pointerEvents={'none'}
userSelect={'none'}
>
{placeholder}
</Box>

View File

@@ -105,8 +105,8 @@ export default function Editor({
left={0}
right={0}
bottom={0}
py={2}
px={3}
py={3}
px={3.5}
pointerEvents={'none'}
overflow={'hidden'}
>

View File

@@ -1,5 +1,5 @@
import { ChevronRightIcon } from '@chakra-ui/icons';
import { Box } from '@chakra-ui/react';
import { Box, Flex } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import Avatar from '../../../../../../../components/common/Avatar';
@@ -28,7 +28,7 @@ export default function VariableLabel({
color={parentLabel !== 'undefined' ? 'myGray.900' : 'red.600'}
>
{parentLabel !== 'undefined' ? (
<span>
<Flex alignItems={'center'} color={'myGray.600'}>
<Avatar
src={nodeAvatar as any}
w={'1rem'}
@@ -36,12 +36,11 @@ export default function VariableLabel({
borderRadius={'xs'}
display={'inline-flex'}
verticalAlign={'middle'}
mb={'3px'}
/>
{parentLabel}
<ChevronRightIcon />
<ChevronRightIcon color={'myGray.500'} />
{childLabel}
</span>
</Flex>
) : (
<>
<Box>{t('common:invalid_variable')}</Box>

View File

@@ -6,7 +6,7 @@ import { TextNode } from 'lexical';
import { getHashtagRegexString } from './utils';
import { mergeRegister } from '@lexical/utils';
import { registerLexicalTextEntity } from '../../utils';
import { useTranslation } from 'react-i18next';
import { useTranslation } from 'next-i18next';
const REGEX = new RegExp(getHashtagRegexString(), 'i');

View File

@@ -1,13 +1,12 @@
import React, { useMemo, useRef } from 'react';
import MyMenu from '../../common/MyMenu';
import MyMenu, { MenuItemType } from '../../common/MyMenu';
import {
FlowNodeInputMap,
FlowNodeInputTypeEnum
} from '@fastgpt/global/core/workflow/node/constant';
import { Box, Button, useTheme } from '@chakra-ui/react';
import { Button, useTheme } from '@chakra-ui/react';
import MyIcon from '../../common/Icon';
import { useTranslation } from 'next-i18next';
import { useConfirm } from '../../../hooks/useConfirm';
const NodeInputSelect = ({
renderTypeList,
@@ -19,9 +18,6 @@ const NodeInputSelect = ({
onChange: (e: string) => void;
}) => {
const { t } = useTranslation();
const { openConfirm, ConfirmModal } = useConfirm({
title: t('common:core.workflow.Change input type tip')
});
const renderType = renderTypeList[renderTypeIndex];
const theme = useTheme();
@@ -136,7 +132,22 @@ const NodeInputSelect = ({
);
const filterMenuList = useMemo(
() => renderList.filter((item) => renderTypeList.includes(item.renderType)),
() =>
renderList
.filter((item) => renderTypeList.includes(item.renderType))
.map((item) => ({
...item,
type: 'gray' as MenuItemType,
menuItemStyles: {
fontWeight: 'medium',
minH: 7,
h: 7,
px: 1,
py: 0,
mb: 0,
borderRadius: 'xs'
}
})),
[renderTypeList, renderList]
);
const renderTypeData = useMemo(
@@ -148,24 +159,37 @@ const NodeInputSelect = ({
<MyMenu
offset={[-0.5, 0.5]}
trigger="click"
size="mini"
Button={
<Button
leftIcon={
<MyIcon name={renderTypeData.icon as any} w={'14px'} color={'primary.600'} mr={-0.5} />
}
rightIcon={<MyIcon name={'common/select'} w={'0.8rem'} color={'myGray.500'} ml={-1} />}
rightIcon={
<MyIcon
name={'common/select'}
w={'0.8rem'}
color={'myGray.500'}
mx={-1}
sx={{
'button:hover &': {
color: 'primary.600'
}
}}
/>
}
variant={'grayBase'}
border={theme.borders.base}
borderColor={'myGray.200'}
borderRadius={'sm'}
px={'10px'}
py={'6px'}
px={'8px'}
fontSize={'mini'}
color={'myGray.600'}
h={'28px'}
bg={'myGray.100'}
minH={'28px'}
h={'28px'}
>
<Box fontWeight={'medium'}>{renderTypeData.title}</Box>
{renderTypeData.title}
</Button>
}
menuList={[{ children: filterMenuList }]}

View File

@@ -1,5 +1,6 @@
import Cookies, { CookieAttributes } from 'js-cookie';
import { useTranslation } from 'next-i18next';
import { LangEnum } from '../../../projects/app/src/web/common/utils/i18n';
const setCookie = (key: string, value: string, options?: CookieAttributes) => {
Cookies.set(key, value, options);
@@ -13,11 +14,13 @@ const LANG_KEY = 'NEXT_LOCALE';
export const useI18nLng = () => {
const { i18n } = useTranslation();
const languageMap: Record<string, string> = {
zh: 'zh',
'zh-CN': 'zh',
'zh-Hans': 'zh',
en: 'en',
'en-US': 'en'
zh: LangEnum.zh_CN,
'zh-CN': LangEnum.zh_CN,
'zh-Hans': LangEnum.zh_CN,
'zh-HK': LangEnum.zh_CN,
'zh-TW': LangEnum.zh_TW,
en: LangEnum.en,
'en-US': LangEnum.en
};
const onChangeLng = (lng: string) => {

View File

@@ -188,7 +188,8 @@ export function useScrollPagination<
pageSize = 10,
params = {},
EmptyTip
EmptyTip,
showErrorToast = true
}: {
refreshDeps?: any[];
scrollLoadType?: 'top' | 'bottom';
@@ -196,6 +197,7 @@ export function useScrollPagination<
pageSize?: number;
params?: Record<string, any>;
EmptyTip?: React.JSX.Element;
showErrorToast?: boolean;
}
) {
const { t } = useTranslation();
@@ -249,10 +251,12 @@ export function useScrollPagination<
setData((prevData) => (offset === 0 ? res.list : [...prevData, ...res.list]));
}
} catch (error: any) {
toast({
title: getErrText(error, t('common:core.chat.error.data_error')),
status: 'error'
});
if (showErrorToast) {
toast({
title: getErrText(error, t('common:core.chat.error.data_error')),
status: 'error'
});
}
console.log(error);
}

View File

@@ -1,8 +1,10 @@
import { useToast as uToast, UseToastOptions } from '@chakra-ui/react';
import { CSSProperties, useCallback } from 'react';
import { useTranslation } from 'next-i18next';
export const useToast = (props?: UseToastOptions & { containerStyle?: CSSProperties }) => {
const { containerStyle, ...toastProps } = props || {};
const { t } = useTranslation();
const toast = uToast({
position: 'top',
@@ -17,7 +19,11 @@ export const useToast = (props?: UseToastOptions & { containerStyle?: CSSPropert
const myToast = useCallback(
(options?: UseToastOptions) => {
if (options?.title || options?.description) {
toast(options);
toast({
...(options.title && { title: t(options.title as any) }),
...(options.description && { description: t(options.description as any) }),
...options
});
}
},
[props]

View File

@@ -1,5 +1,5 @@
{
"Role_setting": "Role setting",
"Role_setting": "Permission",
"Run": "Execute",
"Team Tags Set": "Team tags",
"Team_Tags": "Team tags",
@@ -14,6 +14,8 @@
"app.version_past": "Previously Published",
"app.version_publish_tips": "This version will be saved to the team cloud, synchronized with the entire team, and update the app version on all release channels.",
"app_detail": "Application Details",
"auto_execute": "Automatic execution",
"auto_execute_default_prompt_placeholder": "Default questions sent when executing automatically",
"chat_debug": "Chat Preview",
"chat_logs": "Conversation Logs",
"chat_logs_tips": "Logs will record the online, shared, and API (requires chatId) conversation records of this app.",
@@ -36,10 +38,10 @@
"document_quote_tip": "Usually used to accept user-uploaded document content (requires document parsing), and can also be used to reference other string data.",
"document_upload": "Document Upload",
"edit_app": "Edit Application",
"edit_info": "Edit Information",
"edit_info": "Edit",
"execute_time": "Execution Time",
"export_config_successful": "Configuration copied, some sensitive information automatically filtered. Please check for any remaining sensitive data.",
"export_configs": "Export Configurations",
"export_configs": "Export",
"feedback_count": "User Feedback",
"file_quote_link": "Files",
"file_recover": "File will overwrite current content",
@@ -50,7 +52,7 @@
"go_to_run": "Go to Execution",
"image_upload": "Image Upload",
"image_upload_tip": "How to activate model image recognition capabilities",
"import_configs": "Import Configurations",
"import_configs": "Import",
"import_configs_failed": "Import configuration failed, please ensure the configuration is correct!",
"import_configs_success": "Import Successful",
"initial_form": "initial state",
@@ -77,6 +79,7 @@
"move.hint": "After moving, the selected application/folder will inherit the permission settings of the new folder, and the original permission settings will become invalid.",
"move_app": "Move Application",
"not_json_file": "Please select a JSON file",
"open_auto_execute": "Enable automatic execution",
"open_vision_function_tip": "Models with icon switches have image recognition capabilities. \nAfter being turned on, the model will parse the pictures in the file link and automatically parse the pictures in the user's question (user question ≤ 500 words).",
"or_drag_JSON": "or drag in JSON file",
"paste_config": "Paste Configuration",

View File

@@ -4,6 +4,7 @@
"LLM_model_response_empty": "The model flow response is empty, please check whether the model flow output is normal.",
"chat_history": "Conversation History",
"chat_input_guide_lexicon_is_empty": "Lexicon not configured yet",
"chat_test_app": "Debug-{{name}}",
"citations": "{{num}} References",
"click_contextual_preview": "Click to see contextual preview",
"config_input_guide": "Set Up Input Guide",

View File

@@ -268,9 +268,11 @@
"core.app.Api request": "API Request",
"core.app.Api request desc": "Integrate into existing systems through API, or WeChat Work, Feishu, etc.",
"core.app.App intro": "App Introduction",
"core.app.Auto execute": "Auto execute",
"core.app.Chat Variable": "Chat Variable",
"core.app.Config schedule plan": "Configure Scheduled Execution",
"core.app.Config whisper": "Configure Voice Input",
"core.app.Config_auto_execute": "Click to configure automatic execution rules",
"core.app.Interval timer config": "Scheduled Execution Configuration",
"core.app.Interval timer run": "Scheduled Execution",
"core.app.Interval timer tip": "Can Execute App on Schedule",
@@ -428,7 +430,7 @@
"core.chat.logs.online": "Online Use",
"core.chat.logs.share": "External Link Call",
"core.chat.logs.team": "Team Space Chat",
"core.chat.logs.test": "Test",
"core.chat.logs.test": "Online debugging",
"core.chat.logs.wecom": "WeChat Work",
"core.chat.markdown.Edit Question": "Edit Question",
"core.chat.markdown.Quick Question": "Click to Ask Immediately",
@@ -732,11 +734,11 @@
"core.module.template.AI function": "AI Capability",
"core.module.template.AI response switch tip": "If you want the current node not to output content, you can turn off this switch. The content output by AI will not be displayed to the user, and you can manually use 'AI Response Content' for special processing.",
"core.module.template.AI support tool tip": "Models that support function calls can better use tool calls.",
"core.module.template.Basic Node": "Basic Function",
"core.module.template.Basic Node": "Basic",
"core.module.template.Query extension": "Question Optimization",
"core.module.template.System Plugin": "System Plugin",
"core.module.template.System Plugin": "System",
"core.module.template.System input module": "System Input",
"core.module.template.Team app": "Team App",
"core.module.template.Team app": "Team",
"core.module.template.Tool module": "Tool",
"core.module.template.UnKnow Module": "Unknown Module",
"core.module.template.ai_chat": "AI conversation",

View File

@@ -14,6 +14,9 @@
"app.version_past": "发布过",
"app.version_publish_tips": "该版本将被保存至团队云端,同步给整个团队,同时更新所有发布渠道的应用版本",
"app_detail": "应用详情",
"auto_execute": "自动执行",
"auto_execute_default_prompt_placeholder": "自动执行时,发送的默认问题",
"auto_execute_tip": "开启后用户进入对话界面将自动触发工作流。执行顺序1、对话开场白2、全局变量3、自动执行。",
"chat_debug": "调试预览",
"chat_logs": "对话日志",
"chat_logs_tips": "日志会记录该应用的在线、分享和 API需填写 chatId对话记录",
@@ -77,6 +80,7 @@
"move.hint": "移动后,所选应用/文件夹将继承新文件夹的权限设置,原先的权限设置失效。",
"move_app": "移动应用",
"not_json_file": "请选择JSON文件",
"open_auto_execute": "启用自动执行",
"open_vision_function_tip": "有图示开关的模型即拥有图片识别能力。若开启模型会解析文件链接里的图片并自动解析用户问题中的图片用户问题≤500字时生效。",
"or_drag_JSON": "或拖入JSON文件",
"paste_config": "粘贴配置",

View File

@@ -4,6 +4,7 @@
"LLM_model_response_empty": "模型流响应为空,请检查模型流输出是否正常",
"chat_history": "聊天记录",
"chat_input_guide_lexicon_is_empty": "还没有配置词库",
"chat_test_app": "调试-{{name}}",
"citations": "{{num}}条引用",
"click_contextual_preview": "点击查看上下文预览",
"config_input_guide": "配置输入引导",

View File

@@ -267,9 +267,11 @@
"core.app.Api request": "API 访问",
"core.app.Api request desc": "通过 API 接入到已有系统中,或企微、飞书等",
"core.app.App intro": "应用介绍",
"core.app.Auto execute": "自动执行",
"core.app.Chat Variable": "对话框变量",
"core.app.Config schedule plan": "配置定时执行",
"core.app.Config whisper": "配置语音输入",
"core.app.Config_auto_execute": "点击配置自动执行规则",
"core.app.Interval timer config": "定时执行配置",
"core.app.Interval timer run": "定时执行",
"core.app.Interval timer tip": "可定时执行应用",
@@ -427,7 +429,7 @@
"core.chat.logs.online": "在线使用",
"core.chat.logs.share": "外部链接调用",
"core.chat.logs.team": "团队空间对话",
"core.chat.logs.test": "试",
"core.chat.logs.test": "在线调试",
"core.chat.logs.wecom": "企业微信",
"core.chat.markdown.Edit Question": "编辑问题",
"core.chat.markdown.Quick Question": "点我立即提问",

View File

@@ -221,7 +221,6 @@ const Button = defineStyleConfig({
boxShadow: '0px 0px 1px 0px rgba(19, 51, 107, 0.08), 0px 1px 2px 0px rgba(19, 51, 107, 0.05)',
_hover: {
color: 'red.600',
background: 'red.1',
borderColor: 'red.300'
},
_active: {
@@ -251,6 +250,16 @@ const Button = defineStyleConfig({
color: 'red.600'
}
},
grayGhost: {
color: 'myGray.500',
fontWeight: '500',
p: 0,
bg: 'transparent',
transition: 'background 0.1s',
_hover: {
bg: 'myGray.05'
}
},
transparentBase: {
color: 'myGray.800',
fontWeight: '500',
@@ -570,6 +579,43 @@ const Table = tableMultiStyle({
}
})
},
variants: {
workflow: {
table: {
bg: 'white'
},
thead: {
tr: {
th: {
p: '0',
px: 4,
bg: 'myGray.50',
borderRadius: 'none !important',
borderBottom: 'none',
height: '32px',
fontSize: 'mini',
fontWeight: 'medium'
}
}
},
tbody: {
tr: {
td: {
p: '0',
px: 4,
fontSize: 'xs',
borderBottom: 'base',
height: '40px'
},
'&:last-child': {
td: {
borderBottom: 'none'
}
}
}
}
}
},
defaultProps: {
size: 'md'
}

View File

@@ -1,13 +1,13 @@
import 'i18next';
import common from '../i18n/zh/common.json';
import dataset from '../i18n/zh/dataset.json';
import app from '../i18n/zh/app.json';
import file from '../i18n/zh/file.json';
import publish from '../i18n/zh/publish.json';
import workflow from '../i18n/zh/workflow.json';
import user from '../i18n/zh/user.json';
import chat from '../i18n/zh/chat.json';
import login from '../i18n/zh/login.json';
import common from '../i18n/zh-CN/common.json';
import dataset from '../i18n/zh-CN/dataset.json';
import app from '../i18n/zh-CN/app.json';
import file from '../i18n/zh-CN/file.json';
import publish from '../i18n/zh-CN/publish.json';
import workflow from '../i18n/zh-CN/workflow.json';
import user from '../i18n/zh-CN/user.json';
import chat from '../i18n/zh-CN/chat.json';
import login from '../i18n/zh-CN/login.json';
export interface I18nNamespaces {
common: typeof common;