Compare commits
4 Commits
v4.8-alpha
...
v4.8-alpha
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
917e4e9262 | ||
|
|
3c6e5a6e00 | ||
|
|
7b75a99ba2 | ||
|
|
2e468fc8ca |
@@ -2,7 +2,7 @@ import { ErrType } from '../errorCode';
|
|||||||
|
|
||||||
/* dataset: 502000 */
|
/* dataset: 502000 */
|
||||||
export enum AppErrEnum {
|
export enum AppErrEnum {
|
||||||
unExist = 'unExist',
|
unExist = 'appUnExist',
|
||||||
unAuthApp = 'unAuthApp'
|
unAuthApp = 'unAuthApp'
|
||||||
}
|
}
|
||||||
const appErrList = [
|
const appErrList = [
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { ErrType } from '../errorCode';
|
|||||||
|
|
||||||
/* dataset: 506000 */
|
/* dataset: 506000 */
|
||||||
export enum OpenApiErrEnum {
|
export enum OpenApiErrEnum {
|
||||||
unExist = 'unExist',
|
unExist = 'openapiUnExist',
|
||||||
unAuth = 'unAuth'
|
unAuth = 'openapiUnAuth'
|
||||||
}
|
}
|
||||||
const errList = [
|
const errList = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { ErrType } from '../errorCode';
|
|||||||
|
|
||||||
/* dataset: 505000 */
|
/* dataset: 505000 */
|
||||||
export enum OutLinkErrEnum {
|
export enum OutLinkErrEnum {
|
||||||
unExist = 'unExist',
|
unExist = 'outlinkUnExist',
|
||||||
unAuthLink = 'unAuthLink',
|
unAuthLink = 'unAuthLink',
|
||||||
linkUnInvalid = 'linkUnInvalid',
|
linkUnInvalid = 'linkUnInvalid',
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { ErrType } from '../errorCode';
|
|||||||
|
|
||||||
/* dataset: 507000 */
|
/* dataset: 507000 */
|
||||||
export enum PluginErrEnum {
|
export enum PluginErrEnum {
|
||||||
unExist = 'unExist',
|
unExist = 'pluginUnExist',
|
||||||
unAuth = 'unAuth'
|
unAuth = 'pluginUnAuth'
|
||||||
}
|
}
|
||||||
const errList = [
|
const errList = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
|
|||||||
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
|
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
|
||||||
const {
|
const {
|
||||||
welcomeText,
|
welcomeText,
|
||||||
variableModules,
|
variableNodes,
|
||||||
questionGuide,
|
questionGuide,
|
||||||
ttsConfig,
|
ttsConfig,
|
||||||
whisperConfig,
|
whisperConfig,
|
||||||
@@ -114,7 +114,7 @@ export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
|
|||||||
|
|
||||||
defaultAppForm.userGuide = {
|
defaultAppForm.userGuide = {
|
||||||
welcomeText: welcomeText,
|
welcomeText: welcomeText,
|
||||||
variables: variableModules,
|
variables: variableNodes,
|
||||||
questionGuide: questionGuide,
|
questionGuide: questionGuide,
|
||||||
tts: ttsConfig,
|
tts: ttsConfig,
|
||||||
whisper: whisperConfig,
|
whisper: whisperConfig,
|
||||||
|
|||||||
8
packages/global/core/chat/type.d.ts
vendored
8
packages/global/core/chat/type.d.ts
vendored
@@ -10,7 +10,7 @@ import {
|
|||||||
import { FlowNodeTypeEnum } from '../workflow/node/constant';
|
import { FlowNodeTypeEnum } from '../workflow/node/constant';
|
||||||
import { NodeOutputKeyEnum } from '../workflow/constants';
|
import { NodeOutputKeyEnum } from '../workflow/constants';
|
||||||
import { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
|
||||||
import { AppSchema } from '../app/type';
|
import { AppSchema, VariableItemType } from '../app/type';
|
||||||
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
|
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
|
||||||
import { DatasetSearchModeEnum } from '../dataset/constants';
|
import { DatasetSearchModeEnum } from '../dataset/constants';
|
||||||
import { ChatBoxInputType } from '../../../../projects/app/src/components/ChatBox/type';
|
import { ChatBoxInputType } from '../../../../projects/app/src/components/ChatBox/type';
|
||||||
@@ -27,11 +27,13 @@ export type ChatSchema = {
|
|||||||
title: string;
|
title: string;
|
||||||
customTitle: string;
|
customTitle: string;
|
||||||
top: boolean;
|
top: boolean;
|
||||||
variables: Record<string, any>;
|
|
||||||
source: `${ChatSourceEnum}`;
|
source: `${ChatSourceEnum}`;
|
||||||
shareId?: string;
|
shareId?: string;
|
||||||
outLinkUid?: string;
|
outLinkUid?: string;
|
||||||
content: ChatItemType[];
|
|
||||||
|
variableList?: VariableItemType[];
|
||||||
|
welcomeText?: string;
|
||||||
|
variables: Record<string, any>;
|
||||||
metadata?: Record<string, any>;
|
metadata?: Record<string, any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const VariableUpdateNode: FlowNodeTemplateType = {
|
|||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/variable.png',
|
avatar: '/imgs/workflow/variable.png',
|
||||||
name: '变量更新',
|
name: '变量更新',
|
||||||
intro: '可以更新指定节点的输出值和全局变量',
|
intro: '可以更新指定节点的输出值或更新全局变量',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
isTool: false,
|
isTool: false,
|
||||||
inputs: [
|
inputs: [
|
||||||
|
|||||||
@@ -36,13 +36,17 @@ export const checkInputIsReference = (input: FlowNodeInputItemType) => {
|
|||||||
|
|
||||||
/* node */
|
/* node */
|
||||||
export const getGuideModule = (modules: StoreNodeItemType[]) =>
|
export const getGuideModule = (modules: StoreNodeItemType[]) =>
|
||||||
modules.find((item) => item.flowNodeType === FlowNodeTypeEnum.systemConfig);
|
modules.find(
|
||||||
|
(item) =>
|
||||||
|
item.flowNodeType === FlowNodeTypeEnum.systemConfig ||
|
||||||
|
// @ts-ignore (adapt v1)
|
||||||
|
item.flowType === FlowNodeTypeEnum.systemConfig
|
||||||
|
);
|
||||||
export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
|
export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
|
||||||
const welcomeText: string =
|
const welcomeText: string =
|
||||||
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.welcomeText)?.value || '';
|
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.welcomeText)?.value || '';
|
||||||
|
|
||||||
const variableModules: VariableItemType[] =
|
const variableNodes: VariableItemType[] =
|
||||||
guideModules?.inputs.find((item) => item.key === NodeInputKeyEnum.variables)?.value || [];
|
guideModules?.inputs.find((item) => item.key === NodeInputKeyEnum.variables)?.value || [];
|
||||||
|
|
||||||
const questionGuide: boolean =
|
const questionGuide: boolean =
|
||||||
@@ -63,13 +67,43 @@ export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
welcomeText,
|
welcomeText,
|
||||||
variableModules,
|
variableNodes,
|
||||||
questionGuide,
|
questionGuide,
|
||||||
ttsConfig,
|
ttsConfig,
|
||||||
whisperConfig,
|
whisperConfig,
|
||||||
scheduledTriggerConfig
|
scheduledTriggerConfig
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
export const replaceAppChatConfig = ({
|
||||||
|
node,
|
||||||
|
variableList,
|
||||||
|
welcomeText
|
||||||
|
}: {
|
||||||
|
node?: StoreNodeItemType;
|
||||||
|
variableList?: VariableItemType[];
|
||||||
|
welcomeText?: string;
|
||||||
|
}): StoreNodeItemType | undefined => {
|
||||||
|
if (!node) return;
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
inputs: node.inputs.map((input) => {
|
||||||
|
if (input.key === NodeInputKeyEnum.variables && variableList) {
|
||||||
|
return {
|
||||||
|
...input,
|
||||||
|
value: variableList
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (input.key === NodeInputKeyEnum.welcomeText && welcomeText) {
|
||||||
|
return {
|
||||||
|
...input,
|
||||||
|
value: welcomeText
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const getOrInitModuleInputValue = (input: FlowNodeInputItemType) => {
|
export const getOrInitModuleInputValue = (input: FlowNodeInputItemType) => {
|
||||||
if (input.value !== undefined || !input.valueType) return input.value;
|
if (input.value !== undefined || !input.valueType) return input.value;
|
||||||
|
|||||||
@@ -28,6 +28,6 @@ try {
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MongoRwaTextBuffer: Model<RawTextBufferSchemaType> =
|
export const MongoRawTextBuffer: Model<RawTextBufferSchemaType> =
|
||||||
models[collectionName] || model(collectionName, RawTextBufferSchema);
|
models[collectionName] || model(collectionName, RawTextBufferSchema);
|
||||||
MongoRwaTextBuffer.syncIndexes();
|
MongoRawTextBuffer.syncIndexes();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { DatasetFileSchema } from '@fastgpt/global/core/dataset/type';
|
|||||||
import { MongoFileSchema } from './schema';
|
import { MongoFileSchema } from './schema';
|
||||||
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
||||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||||
import { MongoRwaTextBuffer } from '../../buffer/rawText/schema';
|
import { MongoRawTextBuffer } from '../../buffer/rawText/schema';
|
||||||
import { readFileRawContent } from '../read/utils';
|
import { readFileRawContent } from '../read/utils';
|
||||||
import { PassThrough } from 'stream';
|
import { PassThrough } from 'stream';
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ export const readFileContentFromMongo = async ({
|
|||||||
filename: string;
|
filename: string;
|
||||||
}> => {
|
}> => {
|
||||||
// read buffer
|
// read buffer
|
||||||
const fileBuffer = await MongoRwaTextBuffer.findOne({ sourceId: fileId }).lean();
|
const fileBuffer = await MongoRawTextBuffer.findOne({ sourceId: fileId }).lean();
|
||||||
if (fileBuffer) {
|
if (fileBuffer) {
|
||||||
return {
|
return {
|
||||||
rawText: fileBuffer.rawText,
|
rawText: fileBuffer.rawText,
|
||||||
@@ -208,7 +208,7 @@ export const readFileContentFromMongo = async ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (rawText.trim()) {
|
if (rawText.trim()) {
|
||||||
MongoRwaTextBuffer.create({
|
MongoRawTextBuffer.create({
|
||||||
sourceId: fileId,
|
sourceId: fileId,
|
||||||
rawText,
|
rawText,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ export function reRankRecall({
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
addLog.info('ReRank finish:', { time: Date.now() - start });
|
addLog.info('ReRank finish:', { time: Date.now() - start });
|
||||||
|
|
||||||
|
if (!data?.results || data?.results?.length === 0) {
|
||||||
|
addLog.error('ReRank error, empty result', data);
|
||||||
|
}
|
||||||
|
|
||||||
return data?.results?.map((item) => ({
|
return data?.results?.map((item) => ({
|
||||||
id: documents[item.index].id,
|
id: documents[item.index].id,
|
||||||
score: item.relevance_score
|
score: item.relevance_score
|
||||||
|
|||||||
@@ -61,7 +61,15 @@ const ChatSchema = new Schema({
|
|||||||
outLinkUid: {
|
outLinkUid: {
|
||||||
type: String
|
type: String
|
||||||
},
|
},
|
||||||
|
|
||||||
|
variableList: {
|
||||||
|
type: Array
|
||||||
|
},
|
||||||
|
welcomeText: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
variables: {
|
variables: {
|
||||||
|
// variable value
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {}
|
default: {}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
runtimeNodes,
|
runtimeNodes,
|
||||||
runtimeEdges,
|
runtimeEdges,
|
||||||
params,
|
params,
|
||||||
mode: 'test'
|
mode: props.mode === 'debug' ? 'test' : props.mode
|
||||||
};
|
};
|
||||||
|
|
||||||
// run module
|
// run module
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
|||||||
detail,
|
detail,
|
||||||
appId,
|
appId,
|
||||||
chatId,
|
chatId,
|
||||||
|
stream,
|
||||||
responseChatItemId,
|
responseChatItemId,
|
||||||
variables,
|
variables,
|
||||||
node: { outputs },
|
node: { outputs },
|
||||||
@@ -132,7 +133,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
|||||||
results[key] = valueTypeFormat(formatResponse[key], output.valueType);
|
results[key] = valueTypeFormat(formatResponse[key], output.valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof formatResponse[NodeOutputKeyEnum.answerText] === 'string') {
|
if (stream && typeof formatResponse[NodeOutputKeyEnum.answerText] === 'string') {
|
||||||
responseWrite({
|
responseWrite({
|
||||||
res,
|
res,
|
||||||
event: detail ? SseResponseEventEnum.fastAnswer : undefined,
|
event: detail ? SseResponseEventEnum.fastAnswer : undefined,
|
||||||
|
|||||||
@@ -22,20 +22,55 @@ type Response = DispatchNodeResultType<{
|
|||||||
[NodeOutputKeyEnum.ifElseResult]: string;
|
[NodeOutputKeyEnum.ifElseResult]: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
function isEmpty(value: any) {
|
||||||
|
return (
|
||||||
|
// 检查未定义或null值
|
||||||
|
value === undefined ||
|
||||||
|
value === null ||
|
||||||
|
// 检查空字符串
|
||||||
|
(typeof value === 'string' && value.trim() === '') ||
|
||||||
|
// 检查NaN
|
||||||
|
(typeof value === 'number' && isNaN(value)) ||
|
||||||
|
// 检查空数组
|
||||||
|
(Array.isArray(value) && value.length === 0) ||
|
||||||
|
// 检查空对象
|
||||||
|
(typeof value === 'object' && Object.keys(value).length === 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInclude(value: any, target: any) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map((item: any) => String(item)).includes(target);
|
||||||
|
} else if (typeof value === 'string') {
|
||||||
|
return value.includes(target);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkCondition(condition: VariableConditionEnum, variableValue: any, value: string) {
|
function checkCondition(condition: VariableConditionEnum, variableValue: any, value: string) {
|
||||||
const operations = {
|
const operations = {
|
||||||
[VariableConditionEnum.isEmpty]: () => !variableValue,
|
[VariableConditionEnum.isEmpty]: () => isEmpty(variableValue),
|
||||||
[VariableConditionEnum.isNotEmpty]: () => !!variableValue,
|
[VariableConditionEnum.isNotEmpty]: () => !isEmpty(variableValue),
|
||||||
[VariableConditionEnum.equalTo]: () => variableValue === value,
|
|
||||||
[VariableConditionEnum.notEqual]: () => variableValue !== value,
|
[VariableConditionEnum.equalTo]: () => String(variableValue) === value,
|
||||||
|
[VariableConditionEnum.notEqual]: () => String(variableValue) !== value,
|
||||||
|
|
||||||
|
// number
|
||||||
[VariableConditionEnum.greaterThan]: () => Number(variableValue) > Number(value),
|
[VariableConditionEnum.greaterThan]: () => Number(variableValue) > Number(value),
|
||||||
[VariableConditionEnum.lessThan]: () => Number(variableValue) < Number(value),
|
[VariableConditionEnum.lessThan]: () => Number(variableValue) < Number(value),
|
||||||
[VariableConditionEnum.greaterThanOrEqualTo]: () => Number(variableValue) >= Number(value),
|
[VariableConditionEnum.greaterThanOrEqualTo]: () => Number(variableValue) >= Number(value),
|
||||||
[VariableConditionEnum.lessThanOrEqualTo]: () => Number(variableValue) <= Number(value),
|
[VariableConditionEnum.lessThanOrEqualTo]: () => Number(variableValue) <= Number(value),
|
||||||
[VariableConditionEnum.include]: () => variableValue?.includes(value),
|
|
||||||
[VariableConditionEnum.notInclude]: () => !variableValue?.includes(value),
|
// array or string
|
||||||
|
[VariableConditionEnum.include]: () => isInclude(variableValue, value),
|
||||||
|
[VariableConditionEnum.notInclude]: () => !isInclude(variableValue, value),
|
||||||
|
|
||||||
|
// string
|
||||||
[VariableConditionEnum.startWith]: () => variableValue?.startsWith(value),
|
[VariableConditionEnum.startWith]: () => variableValue?.startsWith(value),
|
||||||
[VariableConditionEnum.endWith]: () => variableValue?.endsWith(value),
|
[VariableConditionEnum.endWith]: () => variableValue?.endsWith(value),
|
||||||
|
|
||||||
|
// array
|
||||||
[VariableConditionEnum.lengthEqualTo]: () => variableValue?.length === Number(value),
|
[VariableConditionEnum.lengthEqualTo]: () => variableValue?.length === Number(value),
|
||||||
[VariableConditionEnum.lengthNotEqualTo]: () => variableValue?.length !== Number(value),
|
[VariableConditionEnum.lengthNotEqualTo]: () => variableValue?.length !== Number(value),
|
||||||
[VariableConditionEnum.lengthGreaterThan]: () => variableValue?.length > Number(value),
|
[VariableConditionEnum.lengthGreaterThan]: () => variableValue?.length > Number(value),
|
||||||
|
|||||||
@@ -44,9 +44,13 @@ const parsePowerPoint = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returning an array of all the xml contents read using fs.readFileSync
|
// Returning an array of all the xml contents read using fs.readFileSync
|
||||||
const xmlContentArray = files.map((file) =>
|
const xmlContentArray = files.map((file) => {
|
||||||
fs.readFileSync(`${decompressPath}/${file.path}`, encoding)
|
try {
|
||||||
);
|
return fs.readFileSync(`${decompressPath}/${file.path}`, encoding);
|
||||||
|
} catch (err) {
|
||||||
|
return fs.readFileSync(`${decompressPath}/${file.path}`, 'utf-8');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let responseArr: string[] = [];
|
let responseArr: string[] = [];
|
||||||
|
|
||||||
@@ -95,9 +99,15 @@ export const parseOffice = async ({
|
|||||||
// const decompressPath = `${DEFAULTDECOMPRESSSUBLOCATION}/test`;
|
// const decompressPath = `${DEFAULTDECOMPRESSSUBLOCATION}/test`;
|
||||||
|
|
||||||
// write new file
|
// write new file
|
||||||
fs.writeFileSync(filepath, buffer, {
|
try {
|
||||||
encoding
|
fs.writeFileSync(filepath, buffer, {
|
||||||
});
|
encoding
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
fs.writeFileSync(filepath, buffer, {
|
||||||
|
encoding: 'utf-8'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const text = await (async () => {
|
const text = await (async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -85,7 +85,22 @@
|
|||||||
"x": 1607.7142331269126,
|
"x": 1607.7142331269126,
|
||||||
"y": -151.8669210746189
|
"y": -151.8669210746189
|
||||||
},
|
},
|
||||||
"inputs": [],
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "text",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "text",
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"description": "",
|
||||||
|
"canEdit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"description": true,
|
||||||
|
"valueType": true
|
||||||
|
},
|
||||||
|
"value": ["CRT7oIEU8v2P", "pYKS0LB9gAr3"]
|
||||||
|
}
|
||||||
|
],
|
||||||
"outputs": []
|
"outputs": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -190,6 +205,13 @@
|
|||||||
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
||||||
"valueType": "any",
|
"valueType": "any",
|
||||||
"type": "static"
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "pYKS0LB9gAr3",
|
||||||
|
"type": "dynamic",
|
||||||
|
"key": "text",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "text"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -357,9 +357,16 @@ const MessageInput = ({
|
|||||||
// enter send.(pc or iframe && enter and unPress shift)
|
// enter send.(pc or iframe && enter and unPress shift)
|
||||||
const isEnter = e.keyCode === 13;
|
const isEnter = e.keyCode === 13;
|
||||||
if (isEnter && TextareaDom.current && (e.ctrlKey || e.altKey)) {
|
if (isEnter && TextareaDom.current && (e.ctrlKey || e.altKey)) {
|
||||||
TextareaDom.current.value += '\n';
|
// Add a new line
|
||||||
|
const index = TextareaDom.current.selectionStart;
|
||||||
|
const val = TextareaDom.current.value;
|
||||||
|
TextareaDom.current.value = `${val.slice(0, index)}\n${val.slice(index)}`;
|
||||||
|
TextareaDom.current.selectionStart = index + 1;
|
||||||
|
TextareaDom.current.selectionEnd = index + 1;
|
||||||
|
|
||||||
TextareaDom.current.style.height = textareaMinH;
|
TextareaDom.current.style.height = textareaMinH;
|
||||||
TextareaDom.current.style.height = `${TextareaDom.current.scrollHeight}px`;
|
TextareaDom.current.style.height = `${TextareaDom.current.scrollHeight}px`;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { ChatSiteItemType } from '@fastgpt/global/core/chat/type';
|
|||||||
|
|
||||||
type useChatStoreType = OutLinkChatAuthProps & {
|
type useChatStoreType = OutLinkChatAuthProps & {
|
||||||
welcomeText: string;
|
welcomeText: string;
|
||||||
variableModules: VariableItemType[];
|
variableNodes: VariableItemType[];
|
||||||
questionGuide: boolean;
|
questionGuide: boolean;
|
||||||
ttsConfig: AppTTSConfigType;
|
ttsConfig: AppTTSConfigType;
|
||||||
whisperConfig: AppWhisperConfigType;
|
whisperConfig: AppWhisperConfigType;
|
||||||
@@ -41,7 +41,7 @@ type useChatStoreType = OutLinkChatAuthProps & {
|
|||||||
};
|
};
|
||||||
const StateContext = createContext<useChatStoreType>({
|
const StateContext = createContext<useChatStoreType>({
|
||||||
welcomeText: '',
|
welcomeText: '',
|
||||||
variableModules: [],
|
variableNodes: [],
|
||||||
questionGuide: false,
|
questionGuide: false,
|
||||||
ttsConfig: {
|
ttsConfig: {
|
||||||
type: 'none',
|
type: 'none',
|
||||||
@@ -110,7 +110,7 @@ const Provider = ({
|
|||||||
}: ChatProviderProps) => {
|
}: ChatProviderProps) => {
|
||||||
const [chatHistories, setChatHistories] = useState<ChatSiteItemType[]>([]);
|
const [chatHistories, setChatHistories] = useState<ChatSiteItemType[]>([]);
|
||||||
|
|
||||||
const { welcomeText, variableModules, questionGuide, ttsConfig, whisperConfig } = useMemo(
|
const { welcomeText, variableNodes, questionGuide, ttsConfig, whisperConfig } = useMemo(
|
||||||
() => splitGuideModule(userGuideModule),
|
() => splitGuideModule(userGuideModule),
|
||||||
[userGuideModule]
|
[userGuideModule]
|
||||||
);
|
);
|
||||||
@@ -150,7 +150,7 @@ const Provider = ({
|
|||||||
teamId,
|
teamId,
|
||||||
teamToken,
|
teamToken,
|
||||||
welcomeText,
|
welcomeText,
|
||||||
variableModules,
|
variableNodes,
|
||||||
questionGuide,
|
questionGuide,
|
||||||
ttsConfig,
|
ttsConfig,
|
||||||
whisperConfig,
|
whisperConfig,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { VariableItemType } from '@fastgpt/global/core/app/type.d';
|
import { VariableItemType } from '@fastgpt/global/core/app/type.d';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React from 'react';
|
||||||
import { UseFormReturn } from 'react-hook-form';
|
import { UseFormReturn } from 'react-hook-form';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { Box, Button, Card, Input, Textarea } from '@chakra-ui/react';
|
import { Box, Button, Card, Input, Textarea } from '@chakra-ui/react';
|
||||||
@@ -12,34 +12,19 @@ import { ChatBoxInputFormType } from '../type.d';
|
|||||||
|
|
||||||
const VariableInput = ({
|
const VariableInput = ({
|
||||||
appAvatar,
|
appAvatar,
|
||||||
variableModules,
|
variableNodes,
|
||||||
variableIsFinish,
|
|
||||||
chatForm,
|
chatForm,
|
||||||
onSubmitVariables
|
onSubmitVariables
|
||||||
}: {
|
}: {
|
||||||
appAvatar?: string;
|
appAvatar?: string;
|
||||||
variableModules: VariableItemType[];
|
variableNodes: VariableItemType[];
|
||||||
variableIsFinish: boolean;
|
|
||||||
onSubmitVariables: (e: Record<string, any>) => void;
|
onSubmitVariables: (e: Record<string, any>) => void;
|
||||||
chatForm: UseFormReturn<ChatBoxInputFormType>;
|
chatForm: UseFormReturn<ChatBoxInputFormType>;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { register, unregister, setValue, handleSubmit: handleSubmitChat, watch } = chatForm;
|
const { register, setValue, handleSubmit: handleSubmitChat, watch } = chatForm;
|
||||||
const variables = watch('variables');
|
const variables = watch('variables');
|
||||||
|
const chatStarted = watch('chatStarted');
|
||||||
useEffect(() => {
|
|
||||||
// 重新注册所有字段
|
|
||||||
variableModules.forEach((item) => {
|
|
||||||
register(`variables.${item.key}`, { required: item.required });
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
// 组件卸载时注销所有字段
|
|
||||||
variableModules.forEach((item) => {
|
|
||||||
unregister(`variables.${item.key}`);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}, [register, unregister, variableModules]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={3}>
|
<Box py={3}>
|
||||||
@@ -55,7 +40,7 @@ const VariableInput = ({
|
|||||||
bg={'white'}
|
bg={'white'}
|
||||||
boxShadow={'0 0 8px rgba(0,0,0,0.15)'}
|
boxShadow={'0 0 8px rgba(0,0,0,0.15)'}
|
||||||
>
|
>
|
||||||
{variableModules.map((item) => (
|
{variableNodes.map((item) => (
|
||||||
<Box key={item.id} mb={4}>
|
<Box key={item.id} mb={4}>
|
||||||
<Box as={'label'} display={'inline-block'} position={'relative'} mb={1}>
|
<Box as={'label'} display={'inline-block'} position={'relative'} mb={1}>
|
||||||
{item.label}
|
{item.label}
|
||||||
@@ -73,7 +58,6 @@ const VariableInput = ({
|
|||||||
</Box>
|
</Box>
|
||||||
{item.type === VariableInputEnum.input && (
|
{item.type === VariableInputEnum.input && (
|
||||||
<Input
|
<Input
|
||||||
isDisabled={variableIsFinish}
|
|
||||||
bg={'myWhite.400'}
|
bg={'myWhite.400'}
|
||||||
{...register(`variables.${item.key}`, {
|
{...register(`variables.${item.key}`, {
|
||||||
required: item.required
|
required: item.required
|
||||||
@@ -82,7 +66,6 @@ const VariableInput = ({
|
|||||||
)}
|
)}
|
||||||
{item.type === VariableInputEnum.textarea && (
|
{item.type === VariableInputEnum.textarea && (
|
||||||
<Textarea
|
<Textarea
|
||||||
isDisabled={variableIsFinish}
|
|
||||||
bg={'myWhite.400'}
|
bg={'myWhite.400'}
|
||||||
{...register(`variables.${item.key}`, {
|
{...register(`variables.${item.key}`, {
|
||||||
required: item.required
|
required: item.required
|
||||||
@@ -94,7 +77,6 @@ const VariableInput = ({
|
|||||||
{item.type === VariableInputEnum.select && (
|
{item.type === VariableInputEnum.select && (
|
||||||
<MySelect
|
<MySelect
|
||||||
width={'100%'}
|
width={'100%'}
|
||||||
isDisabled={variableIsFinish}
|
|
||||||
list={(item.enums || []).map((item) => ({
|
list={(item.enums || []).map((item) => ({
|
||||||
label: item.value,
|
label: item.value,
|
||||||
value: item.value
|
value: item.value
|
||||||
@@ -110,7 +92,7 @@ const VariableInput = ({
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
{!variableIsFinish && (
|
{!chatStarted && (
|
||||||
<Button
|
<Button
|
||||||
leftIcon={<MyIcon name={'core/chat/chatFill'} w={'16px'} />}
|
leftIcon={<MyIcon name={'core/chat/chatFill'} w={'16px'} />}
|
||||||
size={'sm'}
|
size={'sm'}
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ import ChatProvider, { useChatProviderStore } from './Provider';
|
|||||||
import ChatItem from './components/ChatItem';
|
import ChatItem from './components/ChatItem';
|
||||||
|
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
|
import { useCreation, useUpdateEffect } from 'ahooks';
|
||||||
|
|
||||||
const ResponseTags = dynamic(() => import('./ResponseTags'));
|
const ResponseTags = dynamic(() => import('./ResponseTags'));
|
||||||
const FeedbackModal = dynamic(() => import('./FeedbackModal'));
|
const FeedbackModal = dynamic(() => import('./FeedbackModal'));
|
||||||
const ReadFeedbackModal = dynamic(() => import('./ReadFeedbackModal'));
|
const ReadFeedbackModal = dynamic(() => import('./ReadFeedbackModal'));
|
||||||
@@ -147,7 +149,7 @@ const ChatBox = (
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
welcomeText,
|
welcomeText,
|
||||||
variableModules,
|
variableNodes,
|
||||||
questionGuide,
|
questionGuide,
|
||||||
startSegmentedAudio,
|
startSegmentedAudio,
|
||||||
finishSegmentedAudio,
|
finishSegmentedAudio,
|
||||||
@@ -171,24 +173,10 @@ const ChatBox = (
|
|||||||
const chatStarted = watch('chatStarted');
|
const chatStarted = watch('chatStarted');
|
||||||
|
|
||||||
/* variable */
|
/* variable */
|
||||||
const variables = watch('variables');
|
const filterVariableNodes = useCreation(
|
||||||
const filterVariableModules = useMemo(
|
() => variableNodes.filter((item) => item.type !== VariableInputEnum.custom),
|
||||||
() => variableModules.filter((item) => item.type !== VariableInputEnum.custom),
|
[variableNodes]
|
||||||
[variableModules]
|
|
||||||
);
|
);
|
||||||
const variableIsFinish = (() => {
|
|
||||||
if (!filterVariableModules || filterVariableModules.length === 0 || chatHistories.length > 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
for (let i = 0; i < filterVariableModules.length; i++) {
|
|
||||||
const item = filterVariableModules[i];
|
|
||||||
if (item.required && !variables[item.key]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return chatStarted;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// 滚动到底部
|
// 滚动到底部
|
||||||
const scrollToBottom = (behavior: 'smooth' | 'auto' = 'smooth') => {
|
const scrollToBottom = (behavior: 'smooth' | 'auto' = 'smooth') => {
|
||||||
@@ -379,174 +367,185 @@ const ChatBox = (
|
|||||||
autoTTSResponse?: boolean;
|
autoTTSResponse?: boolean;
|
||||||
history?: ChatSiteItemType[];
|
history?: ChatSiteItemType[];
|
||||||
}) => {
|
}) => {
|
||||||
handleSubmit(async ({ variables }) => {
|
handleSubmit(
|
||||||
if (!onStartChat) return;
|
async ({ variables }) => {
|
||||||
if (isChatting) {
|
if (!onStartChat) return;
|
||||||
toast({
|
if (isChatting) {
|
||||||
title: '正在聊天中...请等待结束',
|
toast({
|
||||||
status: 'warning'
|
title: '正在聊天中...请等待结束',
|
||||||
});
|
status: 'warning'
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
abortRequest();
|
|
||||||
|
|
||||||
text = text.trim();
|
|
||||||
|
|
||||||
if (!text && files.length === 0) {
|
|
||||||
toast({
|
|
||||||
title: '内容为空',
|
|
||||||
status: 'warning'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const responseChatId = getNanoid(24);
|
|
||||||
questionGuideController.current?.abort('stop');
|
|
||||||
|
|
||||||
// set auto audio playing
|
|
||||||
if (autoTTSResponse) {
|
|
||||||
await startSegmentedAudio();
|
|
||||||
setAudioPlayingChatId(responseChatId);
|
|
||||||
}
|
|
||||||
|
|
||||||
const newChatList: ChatSiteItemType[] = [
|
|
||||||
...history,
|
|
||||||
{
|
|
||||||
dataId: getNanoid(24),
|
|
||||||
obj: ChatRoleEnum.Human,
|
|
||||||
value: [
|
|
||||||
...files.map((file) => ({
|
|
||||||
type: ChatItemValueTypeEnum.file,
|
|
||||||
file: {
|
|
||||||
type: file.type,
|
|
||||||
name: file.name,
|
|
||||||
url: file.url || ''
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
...(text
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
type: ChatItemValueTypeEnum.text,
|
|
||||||
text: {
|
|
||||||
content: text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
: [])
|
|
||||||
] as UserChatItemValueItemType[],
|
|
||||||
status: 'finish'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataId: responseChatId,
|
|
||||||
obj: ChatRoleEnum.AI,
|
|
||||||
value: [
|
|
||||||
{
|
|
||||||
type: ChatItemValueTypeEnum.text,
|
|
||||||
text: {
|
|
||||||
content: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
status: 'loading'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 插入内容
|
|
||||||
setChatHistories(newChatList);
|
|
||||||
|
|
||||||
// 清空输入内容
|
|
||||||
resetInputVal({});
|
|
||||||
setQuestionGuide([]);
|
|
||||||
setTimeout(() => {
|
|
||||||
scrollToBottom();
|
|
||||||
}, 100);
|
|
||||||
try {
|
|
||||||
// create abort obj
|
|
||||||
const abortSignal = new AbortController();
|
|
||||||
chatController.current = abortSignal;
|
|
||||||
|
|
||||||
const messages = chats2GPTMessages({ messages: newChatList, reserveId: true });
|
|
||||||
|
|
||||||
const {
|
|
||||||
responseData,
|
|
||||||
responseText,
|
|
||||||
newVariables,
|
|
||||||
isNewChat = false
|
|
||||||
} = await onStartChat({
|
|
||||||
chatList: newChatList,
|
|
||||||
messages,
|
|
||||||
controller: abortSignal,
|
|
||||||
generatingMessage: (e) => generatingMessage({ ...e, autoTTSResponse }),
|
|
||||||
variables
|
|
||||||
});
|
|
||||||
|
|
||||||
newVariables && setValue('variables', newVariables);
|
|
||||||
|
|
||||||
isNewChatReplace.current = isNewChat;
|
|
||||||
|
|
||||||
// set finish status
|
|
||||||
setChatHistories((state) =>
|
|
||||||
state.map((item, index) => {
|
|
||||||
if (index !== state.length - 1) return item;
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
status: 'finish',
|
|
||||||
responseData
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
setTimeout(() => {
|
|
||||||
createQuestionGuide({
|
|
||||||
history: newChatList.map((item, i) =>
|
|
||||||
i === newChatList.length - 1
|
|
||||||
? {
|
|
||||||
...item,
|
|
||||||
value: [
|
|
||||||
{
|
|
||||||
type: ChatItemValueTypeEnum.text,
|
|
||||||
text: {
|
|
||||||
content: responseText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
: item
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
generatingScroll();
|
return;
|
||||||
isPc && TextareaDom.current?.focus();
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
// tts audio
|
|
||||||
autoTTSResponse && splitText2Audio(responseText, true);
|
|
||||||
} catch (err: any) {
|
|
||||||
toast({
|
|
||||||
title: t(getErrText(err, 'core.chat.error.Chat error')),
|
|
||||||
status: 'error',
|
|
||||||
duration: 5000,
|
|
||||||
isClosable: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!err?.responseText) {
|
|
||||||
resetInputVal({ text, files });
|
|
||||||
setChatHistories(newChatList.slice(0, newChatList.length - 2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set finish status
|
abortRequest();
|
||||||
setChatHistories((state) =>
|
|
||||||
state.map((item, index) => {
|
|
||||||
if (index !== state.length - 1) return item;
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
status: 'finish'
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
autoTTSResponse && finishSegmentedAudio();
|
text = text.trim();
|
||||||
})();
|
|
||||||
|
if (!text && files.length === 0) {
|
||||||
|
toast({
|
||||||
|
title: '内容为空',
|
||||||
|
status: 'warning'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete invalid variables, 只保留在 variableNodes 中的变量
|
||||||
|
const requestVariables: Record<string, any> = {};
|
||||||
|
variableNodes?.forEach((item) => {
|
||||||
|
requestVariables[item.key] = variables[item.key] || '';
|
||||||
|
});
|
||||||
|
|
||||||
|
const responseChatId = getNanoid(24);
|
||||||
|
questionGuideController.current?.abort('stop');
|
||||||
|
|
||||||
|
// set auto audio playing
|
||||||
|
if (autoTTSResponse) {
|
||||||
|
await startSegmentedAudio();
|
||||||
|
setAudioPlayingChatId(responseChatId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const newChatList: ChatSiteItemType[] = [
|
||||||
|
...history,
|
||||||
|
{
|
||||||
|
dataId: getNanoid(24),
|
||||||
|
obj: ChatRoleEnum.Human,
|
||||||
|
value: [
|
||||||
|
...files.map((file) => ({
|
||||||
|
type: ChatItemValueTypeEnum.file,
|
||||||
|
file: {
|
||||||
|
type: file.type,
|
||||||
|
name: file.name,
|
||||||
|
url: file.url || ''
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
...(text
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
type: ChatItemValueTypeEnum.text,
|
||||||
|
text: {
|
||||||
|
content: text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: [])
|
||||||
|
] as UserChatItemValueItemType[],
|
||||||
|
status: 'finish'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataId: responseChatId,
|
||||||
|
obj: ChatRoleEnum.AI,
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
type: ChatItemValueTypeEnum.text,
|
||||||
|
text: {
|
||||||
|
content: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
status: 'loading'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// 插入内容
|
||||||
|
setChatHistories(newChatList);
|
||||||
|
|
||||||
|
// 清空输入内容
|
||||||
|
resetInputVal({});
|
||||||
|
setQuestionGuide([]);
|
||||||
|
setTimeout(() => {
|
||||||
|
scrollToBottom();
|
||||||
|
}, 100);
|
||||||
|
try {
|
||||||
|
// create abort obj
|
||||||
|
const abortSignal = new AbortController();
|
||||||
|
chatController.current = abortSignal;
|
||||||
|
|
||||||
|
const messages = chats2GPTMessages({ messages: newChatList, reserveId: true });
|
||||||
|
|
||||||
|
const {
|
||||||
|
responseData,
|
||||||
|
responseText,
|
||||||
|
newVariables,
|
||||||
|
isNewChat = false
|
||||||
|
} = await onStartChat({
|
||||||
|
chatList: newChatList,
|
||||||
|
messages,
|
||||||
|
controller: abortSignal,
|
||||||
|
generatingMessage: (e) => generatingMessage({ ...e, autoTTSResponse }),
|
||||||
|
variables: requestVariables
|
||||||
|
});
|
||||||
|
|
||||||
|
newVariables && setValue('variables', newVariables);
|
||||||
|
|
||||||
|
isNewChatReplace.current = isNewChat;
|
||||||
|
|
||||||
|
// set finish status
|
||||||
|
setChatHistories((state) =>
|
||||||
|
state.map((item, index) => {
|
||||||
|
if (index !== state.length - 1) return item;
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
status: 'finish',
|
||||||
|
responseData
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
setTimeout(() => {
|
||||||
|
createQuestionGuide({
|
||||||
|
history: newChatList.map((item, i) =>
|
||||||
|
i === newChatList.length - 1
|
||||||
|
? {
|
||||||
|
...item,
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
type: ChatItemValueTypeEnum.text,
|
||||||
|
text: {
|
||||||
|
content: responseText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
: item
|
||||||
|
)
|
||||||
|
});
|
||||||
|
generatingScroll();
|
||||||
|
isPc && TextareaDom.current?.focus();
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
// tts audio
|
||||||
|
autoTTSResponse && splitText2Audio(responseText, true);
|
||||||
|
} catch (err: any) {
|
||||||
|
toast({
|
||||||
|
title: t(getErrText(err, 'core.chat.error.Chat error')),
|
||||||
|
status: 'error',
|
||||||
|
duration: 5000,
|
||||||
|
isClosable: true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!err?.responseText) {
|
||||||
|
resetInputVal({ text, files });
|
||||||
|
setChatHistories(newChatList.slice(0, newChatList.length - 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// set finish status
|
||||||
|
setChatHistories((state) =>
|
||||||
|
state.map((item, index) => {
|
||||||
|
if (index !== state.length - 1) return item;
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
status: 'finish'
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
autoTTSResponse && finishSegmentedAudio();
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err?.variables);
|
||||||
|
}
|
||||||
|
)();
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
abortRequest,
|
abortRequest,
|
||||||
@@ -566,7 +565,8 @@ const ChatBox = (
|
|||||||
splitText2Audio,
|
splitText2Audio,
|
||||||
startSegmentedAudio,
|
startSegmentedAudio,
|
||||||
t,
|
t,
|
||||||
toast
|
toast,
|
||||||
|
variableNodes
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -630,7 +630,7 @@ const ChatBox = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[onDelMessage]
|
[onDelMessage, setChatHistories]
|
||||||
);
|
);
|
||||||
// admin mark
|
// admin mark
|
||||||
const onMark = useCallback(
|
const onMark = useCallback(
|
||||||
@@ -796,7 +796,19 @@ const ChatBox = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[appId, chatId]
|
[appId, chatId, setChatHistories]
|
||||||
|
);
|
||||||
|
|
||||||
|
const resetVariables = useCallback(
|
||||||
|
(e: Record<string, any> = {}) => {
|
||||||
|
const value: Record<string, any> = { ...e };
|
||||||
|
filterVariableNodes?.forEach((item) => {
|
||||||
|
value[item.key] = e[item.key] || '';
|
||||||
|
});
|
||||||
|
|
||||||
|
setValue('variables', value);
|
||||||
|
},
|
||||||
|
[filterVariableNodes, setValue]
|
||||||
);
|
);
|
||||||
|
|
||||||
const showEmpty = useMemo(
|
const showEmpty = useMemo(
|
||||||
@@ -804,13 +816,13 @@ const ChatBox = (
|
|||||||
feConfigs?.show_emptyChat &&
|
feConfigs?.show_emptyChat &&
|
||||||
showEmptyIntro &&
|
showEmptyIntro &&
|
||||||
chatHistories.length === 0 &&
|
chatHistories.length === 0 &&
|
||||||
!filterVariableModules?.length &&
|
!filterVariableNodes?.length &&
|
||||||
!welcomeText,
|
!welcomeText,
|
||||||
[
|
[
|
||||||
chatHistories.length,
|
chatHistories.length,
|
||||||
feConfigs?.show_emptyChat,
|
feConfigs?.show_emptyChat,
|
||||||
showEmptyIntro,
|
showEmptyIntro,
|
||||||
filterVariableModules?.length,
|
filterVariableNodes?.length,
|
||||||
welcomeText
|
welcomeText
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -869,14 +881,7 @@ const ChatBox = (
|
|||||||
// output data
|
// output data
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
getChatHistories: () => chatHistories,
|
getChatHistories: () => chatHistories,
|
||||||
resetVariables(e) {
|
resetVariables,
|
||||||
const defaultVal: Record<string, any> = {};
|
|
||||||
filterVariableModules?.forEach((item) => {
|
|
||||||
defaultVal[item.key] = '';
|
|
||||||
});
|
|
||||||
|
|
||||||
setValue('variables', e || defaultVal);
|
|
||||||
},
|
|
||||||
resetHistory(e) {
|
resetHistory(e) {
|
||||||
abortRequest();
|
abortRequest();
|
||||||
setValue('chatStarted', e.length > 0);
|
setValue('chatStarted', e.length > 0);
|
||||||
@@ -891,7 +896,7 @@ const ChatBox = (
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex flexDirection={'column'} h={'100%'}>
|
<Flex flexDirection={'column'} h={'100%'} position={'relative'}>
|
||||||
<Script src="/js/html2pdf.bundle.min.js" strategy="lazyOnload"></Script>
|
<Script src="/js/html2pdf.bundle.min.js" strategy="lazyOnload"></Script>
|
||||||
{/* chat box container */}
|
{/* chat box container */}
|
||||||
<Box ref={ChatBoxRef} flex={'1 0 0'} h={0} w={'100%'} overflow={'overlay'} px={[4, 0]} pb={3}>
|
<Box ref={ChatBoxRef} flex={'1 0 0'} h={0} w={'100%'} overflow={'overlay'} px={[4, 0]} pb={3}>
|
||||||
@@ -899,11 +904,10 @@ const ChatBox = (
|
|||||||
{showEmpty && <Empty />}
|
{showEmpty && <Empty />}
|
||||||
{!!welcomeText && <WelcomeBox appAvatar={appAvatar} welcomeText={welcomeText} />}
|
{!!welcomeText && <WelcomeBox appAvatar={appAvatar} welcomeText={welcomeText} />}
|
||||||
{/* variable input */}
|
{/* variable input */}
|
||||||
{!!filterVariableModules?.length && (
|
{!!filterVariableNodes?.length && (
|
||||||
<VariableInput
|
<VariableInput
|
||||||
appAvatar={appAvatar}
|
appAvatar={appAvatar}
|
||||||
variableModules={filterVariableModules}
|
variableNodes={filterVariableNodes}
|
||||||
variableIsFinish={variableIsFinish}
|
|
||||||
chatForm={chatForm}
|
chatForm={chatForm}
|
||||||
onSubmitVariables={(data) => {
|
onSubmitVariables={(data) => {
|
||||||
setValue('chatStarted', true);
|
setValue('chatStarted', true);
|
||||||
@@ -995,7 +999,7 @@ const ChatBox = (
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
{/* message input */}
|
{/* message input */}
|
||||||
{onStartChat && variableIsFinish && active && (
|
{onStartChat && (chatStarted || filterVariableNodes.length === 0) && active && (
|
||||||
<MessageInput
|
<MessageInput
|
||||||
onSendMessage={sendPrompt}
|
onSendMessage={sendPrompt}
|
||||||
onStop={() => chatController.current?.abort('stop')}
|
onStop={() => chatController.current?.abort('stop')}
|
||||||
|
|||||||
@@ -34,11 +34,13 @@ export type ChatTestComponentRef = {
|
|||||||
const ChatTest = (
|
const ChatTest = (
|
||||||
{
|
{
|
||||||
app,
|
app,
|
||||||
|
isOpen,
|
||||||
nodes = [],
|
nodes = [],
|
||||||
edges = [],
|
edges = [],
|
||||||
onClose
|
onClose
|
||||||
}: {
|
}: {
|
||||||
app: AppSchema;
|
app: AppSchema;
|
||||||
|
isOpen: boolean;
|
||||||
nodes?: StoreNodeItemType[];
|
nodes?: StoreNodeItemType[];
|
||||||
edges?: StoreEdgeItemType[];
|
edges?: StoreEdgeItemType[];
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@@ -48,7 +50,6 @@ const ChatTest = (
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const ChatBoxRef = useRef<ComponentRef>(null);
|
const ChatBoxRef = useRef<ComponentRef>(null);
|
||||||
const { userInfo } = useUserStore();
|
const { userInfo } = useUserStore();
|
||||||
const isOpen = useMemo(() => nodes && nodes.length > 0, [nodes]);
|
|
||||||
|
|
||||||
const startChat = useCallback(
|
const startChat = useCallback(
|
||||||
async ({ chatList, controller, generatingMessage, variables }: StartChatFnProps) => {
|
async ({ chatList, controller, generatingMessage, variables }: StartChatFnProps) => {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
arrayConditionList,
|
arrayConditionList,
|
||||||
booleanConditionList,
|
booleanConditionList,
|
||||||
numberConditionList,
|
numberConditionList,
|
||||||
|
objectConditionList,
|
||||||
stringConditionList
|
stringConditionList
|
||||||
} from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
} from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
@@ -133,7 +134,8 @@ const ListItem = ({
|
|||||||
if (index === i) {
|
if (index === i) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
variable: e
|
variable: e,
|
||||||
|
condition: undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
@@ -334,10 +336,10 @@ const ConditionSelect = ({
|
|||||||
valueType === WorkflowIOValueTypeEnum.arrayBoolean ||
|
valueType === WorkflowIOValueTypeEnum.arrayBoolean ||
|
||||||
valueType === WorkflowIOValueTypeEnum.arrayNumber ||
|
valueType === WorkflowIOValueTypeEnum.arrayNumber ||
|
||||||
valueType === WorkflowIOValueTypeEnum.arrayObject ||
|
valueType === WorkflowIOValueTypeEnum.arrayObject ||
|
||||||
valueType === WorkflowIOValueTypeEnum.arrayString ||
|
valueType === WorkflowIOValueTypeEnum.arrayString
|
||||||
valueType === WorkflowIOValueTypeEnum.object
|
|
||||||
)
|
)
|
||||||
return arrayConditionList;
|
return arrayConditionList;
|
||||||
|
if (valueType === WorkflowIOValueTypeEnum.object) return objectConditionList;
|
||||||
|
|
||||||
if (valueType === WorkflowIOValueTypeEnum.any) return allConditionList;
|
if (valueType === WorkflowIOValueTypeEnum.any) return allConditionList;
|
||||||
|
|
||||||
@@ -395,6 +397,10 @@ const ConditionValueInput = ({
|
|||||||
onchange={onChange}
|
onchange={onChange}
|
||||||
value={value}
|
value={value}
|
||||||
placeholder={'选择值'}
|
placeholder={'选择值'}
|
||||||
|
isDisabled={
|
||||||
|
condition === VariableConditionEnum.isEmpty ||
|
||||||
|
condition === VariableConditionEnum.isNotEmpty
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import { getNanoid } from '@fastgpt/global/common/string/tools';
|
|||||||
import IOTitle from '../components/IOTitle';
|
import IOTitle from '../components/IOTitle';
|
||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
import { WorkflowContext } from '../../context';
|
import { WorkflowContext } from '../../context';
|
||||||
|
import { putUpdateTeam } from '@/web/support/user/team/api';
|
||||||
|
|
||||||
const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal'));
|
const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal'));
|
||||||
|
|
||||||
@@ -47,20 +48,11 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
|
|
||||||
const requestUrl = inputs.find((item) => item.key === NodeInputKeyEnum.httpReqUrl);
|
const requestUrl = inputs.find((item) => item.key === NodeInputKeyEnum.httpReqUrl);
|
||||||
|
|
||||||
const { userInfo } = useUserStore();
|
const { userInfo, initUserInfo } = useUserStore();
|
||||||
|
|
||||||
const token = userInfo?.team.lafAccount?.token;
|
const token = userInfo?.team.lafAccount?.token;
|
||||||
const appid = userInfo?.team.lafAccount?.appid;
|
const appid = userInfo?.team.lafAccount?.appid;
|
||||||
|
|
||||||
// not config laf
|
|
||||||
if (!token || !appid) {
|
|
||||||
return (
|
|
||||||
<NodeCard minW={'350px'} selected={selected} {...data}>
|
|
||||||
<ConfigLaf />
|
|
||||||
</NodeCard>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: lafData,
|
data: lafData,
|
||||||
isLoading: isLoadingFunctions,
|
isLoading: isLoadingFunctions,
|
||||||
@@ -69,24 +61,32 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
['getLafFunctionList'],
|
['getLafFunctionList'],
|
||||||
async () => {
|
async () => {
|
||||||
// load laf app detail
|
// load laf app detail
|
||||||
const appDetail = await getLafAppDetail(appid);
|
try {
|
||||||
|
const appDetail = await getLafAppDetail(appid || '');
|
||||||
|
// load laf app functions
|
||||||
|
const schemaUrl = `https://${appDetail?.domain.domain}/_/api-docs?token=${appDetail?.openapi_token}`;
|
||||||
|
|
||||||
// load laf app functions
|
const schema = await getApiSchemaByUrl(schemaUrl);
|
||||||
const schemaUrl = `https://${appDetail?.domain.domain}/_/api-docs?token=${appDetail?.openapi_token}`;
|
const openApiSchema = await str2OpenApiSchema(JSON.stringify(schema));
|
||||||
|
const filterPostSchema = openApiSchema.pathData.filter((item) => item.method === 'post');
|
||||||
|
|
||||||
const schema = await getApiSchemaByUrl(schemaUrl);
|
return {
|
||||||
const openApiSchema = await str2OpenApiSchema(JSON.stringify(schema));
|
lafApp: appDetail,
|
||||||
const filterPostSchema = openApiSchema.pathData.filter((item) => item.method === 'post');
|
lafFunctions: filterPostSchema.map((item) => ({
|
||||||
|
...item,
|
||||||
return {
|
requestUrl: `https://${appDetail?.domain.domain}${item.path}`
|
||||||
lafApp: appDetail,
|
}))
|
||||||
lafFunctions: filterPostSchema.map((item) => ({
|
};
|
||||||
...item,
|
} catch (err) {
|
||||||
requestUrl: `https://${appDetail?.domain.domain}${item.path}`
|
await putUpdateTeam({
|
||||||
}))
|
teamId: userInfo?.team.teamId || '',
|
||||||
};
|
lafAccount: { token: '', appid: '', pat: '' }
|
||||||
|
});
|
||||||
|
initUserInfo();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
enabled: !!token && !!appid,
|
||||||
onError(err) {
|
onError(err) {
|
||||||
toast({
|
toast({
|
||||||
status: 'error',
|
status: 'error',
|
||||||
@@ -155,14 +155,14 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
desc: bodyParams[key].description,
|
desc: bodyParams[key].description,
|
||||||
required: requiredParams?.includes(key) || false,
|
required: requiredParams?.includes(key) || false,
|
||||||
value: `{{${key}}}`,
|
value: `{{${key}}}`,
|
||||||
type: 'string'
|
type: bodyParams[key].type
|
||||||
}))
|
}))
|
||||||
].filter((item) => !inputs.find((input) => input.key === item.name));
|
].filter((item) => !inputs.find((input) => input.key === item.name));
|
||||||
|
|
||||||
allParams.forEach((param) => {
|
allParams.forEach((param) => {
|
||||||
const newInput: FlowNodeInputItemType = {
|
const newInput: FlowNodeInputItemType = {
|
||||||
key: param.name,
|
key: param.name,
|
||||||
valueType: WorkflowIOValueTypeEnum.string,
|
valueType: param.type,
|
||||||
label: param.name,
|
label: param.name,
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||||
required: param.required,
|
required: param.required,
|
||||||
@@ -215,54 +215,63 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
successToast: t('common.Sync success')
|
successToast: t('common.Sync success')
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
// not config laf
|
||||||
<NodeCard minW={'350px'} selected={selected} {...data}>
|
if (!token || !appid) {
|
||||||
<Container>
|
return (
|
||||||
{/* select function */}
|
<NodeCard minW={'350px'} selected={selected} {...data}>
|
||||||
<MySelect
|
<ConfigLaf />
|
||||||
isLoading={isLoadingFunctions}
|
</NodeCard>
|
||||||
list={lafFunctionSelectList}
|
);
|
||||||
placeholder={t('core.module.laf.Select laf function')}
|
} else {
|
||||||
onchange={(e) => {
|
return (
|
||||||
onChangeNode({
|
<NodeCard minW={'350px'} selected={selected} {...data}>
|
||||||
nodeId,
|
<Container>
|
||||||
type: 'updateInput',
|
{/* select function */}
|
||||||
key: NodeInputKeyEnum.httpReqUrl,
|
<MySelect
|
||||||
value: {
|
isLoading={isLoadingFunctions}
|
||||||
...requestUrl,
|
list={lafFunctionSelectList}
|
||||||
value: e
|
placeholder={t('core.module.laf.Select laf function')}
|
||||||
}
|
onchange={(e) => {
|
||||||
});
|
onChangeNode({
|
||||||
}}
|
nodeId,
|
||||||
value={selectedFunction}
|
type: 'updateInput',
|
||||||
/>
|
key: NodeInputKeyEnum.httpReqUrl,
|
||||||
{/* auto set params and go to edit */}
|
value: {
|
||||||
{!!selectedFunction && (
|
...requestUrl,
|
||||||
<Flex justifyContent={'flex-end'} mt={2} gap={2}>
|
value: e
|
||||||
<Button isLoading={isSyncing} variant={'grayBase'} size={'sm'} onClick={onSyncParams}>
|
}
|
||||||
{t('core.module.Laf sync params')}
|
});
|
||||||
</Button>
|
}}
|
||||||
<Button
|
value={selectedFunction}
|
||||||
variant={'grayBase'}
|
/>
|
||||||
size={'sm'}
|
{/* auto set params and go to edit */}
|
||||||
onClick={() => {
|
{!!selectedFunction && (
|
||||||
const lafFunction = lafData?.lafFunctions.find(
|
<Flex justifyContent={'flex-end'} mt={2} gap={2}>
|
||||||
(item) => item.requestUrl === selectedFunction
|
<Button isLoading={isSyncing} variant={'grayBase'} size={'sm'} onClick={onSyncParams}>
|
||||||
);
|
{t('core.module.Laf sync params')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={'grayBase'}
|
||||||
|
size={'sm'}
|
||||||
|
onClick={() => {
|
||||||
|
const lafFunction = lafData?.lafFunctions.find(
|
||||||
|
(item) => item.requestUrl === selectedFunction
|
||||||
|
);
|
||||||
|
|
||||||
if (!lafFunction) return;
|
if (!lafFunction) return;
|
||||||
const url = `${feConfigs.lafEnv}/app/${lafData?.lafApp?.appid}/function${lafFunction?.path}?templateid=FastGPT_Laf`;
|
const url = `${feConfigs.lafEnv}/app/${lafData?.lafApp?.appid}/function${lafFunction?.path}?templateid=FastGPT_Laf`;
|
||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('plugin.go to laf')}
|
{t('plugin.go to laf')}
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
{!!selectedFunction && <RenderIO {...props} />}
|
{!!selectedFunction && <RenderIO {...props} />}
|
||||||
</NodeCard>
|
</NodeCard>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
export default React.memo(NodeLaf);
|
export default React.memo(NodeLaf);
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export const ToolTargetHandle = ({ nodeId }: ToolHandleProps) => {
|
|||||||
edges.some((edge) => edge.targetHandle === getHandleId(nodeId, 'target', 'top')));
|
edges.some((edge) => edge.targetHandle === getHandleId(nodeId, 'target', 'top')));
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
const Render = useMemo(() => {
|
||||||
return (
|
return hidden ? null : (
|
||||||
<MyTooltip label={t('core.workflow.tool.Handle')} shouldWrapChildren={false}>
|
<MyTooltip label={t('core.workflow.tool.Handle')} shouldWrapChildren={false}>
|
||||||
<Handle
|
<Handle
|
||||||
style={{
|
style={{
|
||||||
@@ -49,7 +49,7 @@ export const ToolTargetHandle = ({ nodeId }: ToolHandleProps) => {
|
|||||||
border={'4px solid #8774EE'}
|
border={'4px solid #8774EE'}
|
||||||
transform={'translate(0,-30%) rotate(45deg)'}
|
transform={'translate(0,-30%) rotate(45deg)'}
|
||||||
pointerEvents={'none'}
|
pointerEvents={'none'}
|
||||||
visibility={hidden ? 'hidden' : 'visible'}
|
visibility={'visible'}
|
||||||
/>
|
/>
|
||||||
</Handle>
|
</Handle>
|
||||||
</MyTooltip>
|
</MyTooltip>
|
||||||
|
|||||||
@@ -200,14 +200,19 @@ const MyTargetHandle = React.memo(function MyTargetHandle({
|
|||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectingEdge?.handleId && !connectingEdge.handleId?.includes('source')) return false;
|
if (connectingEdge?.handleId && !connectingEdge.handleId?.includes('source')) return false;
|
||||||
|
|
||||||
// Same source node
|
// From same source node
|
||||||
if (connectedEdges.some((item) => item.target === nodeId && item.targetHandle !== handleId))
|
if (
|
||||||
|
connectedEdges.some(
|
||||||
|
(item) => item.source === connectingEdge?.nodeId && item.target === nodeId
|
||||||
|
)
|
||||||
|
)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, [connectedEdges, connectingEdge?.handleId, edges, handleId, node, nodeId]);
|
}, [connectedEdges, connectingEdge?.handleId, connectingEdge?.nodeId, edges, node, nodeId]);
|
||||||
|
|
||||||
const RenderHandle = useMemo(() => {
|
const RenderHandle = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -487,7 +487,6 @@ const WorkflowContextProvider = ({
|
|||||||
// 3. Set entry node status to running
|
// 3. Set entry node status to running
|
||||||
entryNodes.forEach((node) => {
|
entryNodes.forEach((node) => {
|
||||||
if (runtimeNodeStatus[node.nodeId] !== 'wait') {
|
if (runtimeNodeStatus[node.nodeId] !== 'wait') {
|
||||||
console.log(node.name);
|
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
nodeId: node.nodeId,
|
nodeId: node.nodeId,
|
||||||
type: 'attr',
|
type: 'attr',
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ const LafAccountModal = ({
|
|||||||
enabled: !!lafToken,
|
enabled: !!lafToken,
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
if (!getValues('appid') && data.length > 0) {
|
if (!getValues('appid') && data.length > 0) {
|
||||||
setValue('appid', data[0].appid);
|
setValue('appid', data.filter((app) => app.state === 'Running')[0]?.appid);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (err) => {
|
onError: (err) => {
|
||||||
@@ -175,7 +175,13 @@ const LafAccountModal = ({
|
|||||||
)}
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button variant={'whiteBase'} onClick={onClose}>
|
<Button
|
||||||
|
variant={'whiteBase'}
|
||||||
|
onClick={() => {
|
||||||
|
initUserInfo();
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
{t('common.Close')}
|
{t('common.Close')}
|
||||||
</Button>
|
</Button>
|
||||||
{appid && (
|
{appid && (
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@fastgpt/service/common/response';
|
import { jsonRes } from '@fastgpt/service/common/response';
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
|
||||||
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
||||||
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
|
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
||||||
import type { InitChatProps, InitChatResponse } from '@/global/core/chat/api.d';
|
import type { InitChatProps, InitChatResponse } from '@/global/core/chat/api.d';
|
||||||
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
|
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
|
||||||
@@ -10,74 +9,73 @@ import { getChatItems } from '@fastgpt/service/core/chat/controller';
|
|||||||
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
|
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
|
||||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import { getAppLatestVersion } from '@fastgpt/service/core/app/controller';
|
import { getAppLatestVersion } from '@fastgpt/service/core/app/controller';
|
||||||
|
import { NextAPI } from '@/service/middle/entry';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
async function handler(
|
||||||
try {
|
req: NextApiRequest,
|
||||||
await connectToDatabase();
|
res: NextApiResponse
|
||||||
|
): Promise<InitChatResponse | void> {
|
||||||
|
let { appId, chatId, loadCustomFeedbacks } = req.query as InitChatProps;
|
||||||
|
|
||||||
let { appId, chatId, loadCustomFeedbacks } = req.query as InitChatProps;
|
if (!appId) {
|
||||||
|
return jsonRes(res, {
|
||||||
if (!appId) {
|
code: 501,
|
||||||
return jsonRes(res, {
|
message: "You don't have an app yet"
|
||||||
code: 501,
|
|
||||||
message: "You don't have an app yet"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// auth app permission
|
|
||||||
const [{ app, tmbId }, chat] = await Promise.all([
|
|
||||||
authApp({
|
|
||||||
req,
|
|
||||||
authToken: true,
|
|
||||||
appId,
|
|
||||||
per: 'r'
|
|
||||||
}),
|
|
||||||
chatId ? MongoChat.findOne({ appId, chatId }) : undefined
|
|
||||||
]);
|
|
||||||
|
|
||||||
// auth chat permission
|
|
||||||
if (chat && !app.canWrite && String(tmbId) !== String(chat?.tmbId)) {
|
|
||||||
throw new Error(ChatErrEnum.unAuthChat);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get app and history
|
|
||||||
const [{ history }, { nodes }] = await Promise.all([
|
|
||||||
getChatItems({
|
|
||||||
appId,
|
|
||||||
chatId,
|
|
||||||
limit: 30,
|
|
||||||
field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback ${
|
|
||||||
DispatchNodeResponseKeyEnum.nodeResponse
|
|
||||||
} ${loadCustomFeedbacks ? 'customFeedbacks' : ''}`
|
|
||||||
}),
|
|
||||||
getAppLatestVersion(app._id, app)
|
|
||||||
]);
|
|
||||||
|
|
||||||
jsonRes<InitChatResponse>(res, {
|
|
||||||
data: {
|
|
||||||
chatId,
|
|
||||||
appId,
|
|
||||||
title: chat?.title || '新对话',
|
|
||||||
userAvatar: undefined,
|
|
||||||
variables: chat?.variables || {},
|
|
||||||
history,
|
|
||||||
app: {
|
|
||||||
userGuideModule: getGuideModule(nodes),
|
|
||||||
chatModels: getChatModelNameListByModules(nodes),
|
|
||||||
name: app.name,
|
|
||||||
avatar: app.avatar,
|
|
||||||
intro: app.intro
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error: err
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// auth app permission
|
||||||
|
const [{ app, tmbId }, chat] = await Promise.all([
|
||||||
|
authApp({
|
||||||
|
req,
|
||||||
|
authToken: true,
|
||||||
|
appId,
|
||||||
|
per: 'r'
|
||||||
|
}),
|
||||||
|
chatId ? MongoChat.findOne({ appId, chatId }) : undefined
|
||||||
|
]);
|
||||||
|
|
||||||
|
// auth chat permission
|
||||||
|
if (chat && !app.canWrite && String(tmbId) !== String(chat?.tmbId)) {
|
||||||
|
throw new Error(ChatErrEnum.unAuthChat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get app and history
|
||||||
|
const [{ history }, { nodes }] = await Promise.all([
|
||||||
|
getChatItems({
|
||||||
|
appId,
|
||||||
|
chatId,
|
||||||
|
limit: 30,
|
||||||
|
field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback ${
|
||||||
|
DispatchNodeResponseKeyEnum.nodeResponse
|
||||||
|
} ${loadCustomFeedbacks ? 'customFeedbacks' : ''}`
|
||||||
|
}),
|
||||||
|
getAppLatestVersion(app._id, app)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
chatId,
|
||||||
|
appId,
|
||||||
|
title: chat?.title || '新对话',
|
||||||
|
userAvatar: undefined,
|
||||||
|
variables: chat?.variables || {},
|
||||||
|
history,
|
||||||
|
app: {
|
||||||
|
userGuideModule: replaceAppChatConfig({
|
||||||
|
node: getGuideModule(nodes),
|
||||||
|
variableList: chat?.variableList,
|
||||||
|
welcomeText: chat?.welcomeText
|
||||||
|
}),
|
||||||
|
chatModels: getChatModelNameListByModules(nodes),
|
||||||
|
name: app.name,
|
||||||
|
avatar: app.avatar,
|
||||||
|
intro: app.intro
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default NextAPI(handler);
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
api: {
|
api: {
|
||||||
responseLimit: '10mb'
|
responseLimit: '10mb'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
|||||||
import { jsonRes } from '@fastgpt/service/common/response';
|
import { jsonRes } from '@fastgpt/service/common/response';
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import type { InitChatResponse, InitOutLinkChatProps } from '@/global/core/chat/api.d';
|
import type { InitChatResponse, InitOutLinkChatProps } from '@/global/core/chat/api.d';
|
||||||
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
|
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
||||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import { getChatItems } from '@fastgpt/service/core/chat/controller';
|
import { getChatItems } from '@fastgpt/service/core/chat/controller';
|
||||||
@@ -72,7 +72,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
variables: chat?.variables || {},
|
variables: chat?.variables || {},
|
||||||
history,
|
history,
|
||||||
app: {
|
app: {
|
||||||
userGuideModule: getGuideModule(nodes),
|
userGuideModule: replaceAppChatConfig({
|
||||||
|
node: getGuideModule(nodes),
|
||||||
|
variableList: chat?.variableList,
|
||||||
|
welcomeText: chat?.welcomeText
|
||||||
|
}),
|
||||||
chatModels: getChatModelNameListByModules(nodes),
|
chatModels: getChatModelNameListByModules(nodes),
|
||||||
name: app.name,
|
name: app.name,
|
||||||
avatar: app.avatar,
|
avatar: app.avatar,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@fastgpt/service/common/response';
|
import { jsonRes } from '@fastgpt/service/common/response';
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
|
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
||||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import type { InitChatResponse, InitTeamChatProps } from '@/global/core/chat/api.d';
|
import type { InitChatResponse, InitTeamChatProps } from '@/global/core/chat/api.d';
|
||||||
@@ -73,7 +73,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
variables: chat?.variables || {},
|
variables: chat?.variables || {},
|
||||||
history,
|
history,
|
||||||
app: {
|
app: {
|
||||||
userGuideModule: getGuideModule(nodes),
|
userGuideModule: replaceAppChatConfig({
|
||||||
|
node: getGuideModule(nodes),
|
||||||
|
variableList: chat?.variableList,
|
||||||
|
welcomeText: chat?.welcomeText
|
||||||
|
}),
|
||||||
chatModels: getChatModelNameListByModules(nodes),
|
chatModels: getChatModelNameListByModules(nodes),
|
||||||
name: app.name,
|
name: app.name,
|
||||||
avatar: app.avatar,
|
avatar: app.avatar,
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
|
||||||
import { jsonRes } from '@fastgpt/service/common/response';
|
|
||||||
import { pushChatUsage } from '@/service/support/wallet/usage/push';
|
import { pushChatUsage } from '@/service/support/wallet/usage/push';
|
||||||
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
|
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
|
||||||
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
||||||
@@ -9,8 +7,12 @@ import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
|||||||
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
|
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
|
||||||
import { PostWorkflowDebugProps, PostWorkflowDebugResponse } from '@/global/core/workflow/api';
|
import { PostWorkflowDebugProps, PostWorkflowDebugResponse } from '@/global/core/workflow/api';
|
||||||
import { authPluginCrud } from '@fastgpt/service/support/permission/auth/plugin';
|
import { authPluginCrud } from '@fastgpt/service/support/permission/auth/plugin';
|
||||||
|
import { NextAPI } from '@/service/middle/entry';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse
|
||||||
|
): Promise<PostWorkflowDebugResponse> {
|
||||||
const {
|
const {
|
||||||
nodes = [],
|
nodes = [],
|
||||||
edges = [],
|
edges = [],
|
||||||
@@ -18,72 +20,65 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
appId,
|
appId,
|
||||||
pluginId
|
pluginId
|
||||||
} = req.body as PostWorkflowDebugProps;
|
} = req.body as PostWorkflowDebugProps;
|
||||||
try {
|
|
||||||
await connectToDatabase();
|
|
||||||
if (!nodes) {
|
|
||||||
throw new Error('Prams Error');
|
|
||||||
}
|
|
||||||
if (!Array.isArray(nodes)) {
|
|
||||||
throw new Error('Nodes is not array');
|
|
||||||
}
|
|
||||||
if (!Array.isArray(edges)) {
|
|
||||||
throw new Error('Edges is not array');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* user auth */
|
if (!nodes) {
|
||||||
const [{ teamId, tmbId }] = await Promise.all([
|
throw new Error('Prams Error');
|
||||||
authCert({
|
|
||||||
req,
|
|
||||||
authToken: true
|
|
||||||
}),
|
|
||||||
appId && authApp({ req, authToken: true, appId, per: 'r' }),
|
|
||||||
pluginId && authPluginCrud({ req, authToken: true, pluginId, per: 'r' })
|
|
||||||
]);
|
|
||||||
|
|
||||||
// auth balance
|
|
||||||
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
|
|
||||||
|
|
||||||
/* start process */
|
|
||||||
const { flowUsages, flowResponses, debugResponse } = await dispatchWorkFlow({
|
|
||||||
res,
|
|
||||||
mode: 'debug',
|
|
||||||
teamId,
|
|
||||||
tmbId,
|
|
||||||
user,
|
|
||||||
appId,
|
|
||||||
runtimeNodes: nodes,
|
|
||||||
runtimeEdges: edges,
|
|
||||||
variables,
|
|
||||||
query: [],
|
|
||||||
histories: [],
|
|
||||||
stream: false,
|
|
||||||
detail: true,
|
|
||||||
maxRunTimes: 200
|
|
||||||
});
|
|
||||||
|
|
||||||
pushChatUsage({
|
|
||||||
appName: '工作流Debug',
|
|
||||||
appId,
|
|
||||||
teamId,
|
|
||||||
tmbId,
|
|
||||||
source: UsageSourceEnum.fastgpt,
|
|
||||||
flowUsages
|
|
||||||
});
|
|
||||||
|
|
||||||
jsonRes<PostWorkflowDebugResponse>(res, {
|
|
||||||
data: {
|
|
||||||
...debugResponse,
|
|
||||||
flowResponses
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (err: any) {
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error: err
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if (!Array.isArray(nodes)) {
|
||||||
|
throw new Error('Nodes is not array');
|
||||||
|
}
|
||||||
|
if (!Array.isArray(edges)) {
|
||||||
|
throw new Error('Edges is not array');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* user auth */
|
||||||
|
const [{ teamId, tmbId }] = await Promise.all([
|
||||||
|
authCert({
|
||||||
|
req,
|
||||||
|
authToken: true
|
||||||
|
}),
|
||||||
|
appId && authApp({ req, authToken: true, appId, per: 'r' }),
|
||||||
|
pluginId && authPluginCrud({ req, authToken: true, pluginId, per: 'r' })
|
||||||
|
]);
|
||||||
|
|
||||||
|
// auth balance
|
||||||
|
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
|
||||||
|
|
||||||
|
/* start process */
|
||||||
|
const { flowUsages, flowResponses, debugResponse } = await dispatchWorkFlow({
|
||||||
|
res,
|
||||||
|
mode: 'debug',
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
user,
|
||||||
|
appId,
|
||||||
|
runtimeNodes: nodes,
|
||||||
|
runtimeEdges: edges,
|
||||||
|
variables,
|
||||||
|
query: [],
|
||||||
|
histories: [],
|
||||||
|
stream: false,
|
||||||
|
detail: true,
|
||||||
|
maxRunTimes: 200
|
||||||
|
});
|
||||||
|
|
||||||
|
pushChatUsage({
|
||||||
|
appName: '工作流Debug',
|
||||||
|
appId,
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
source: UsageSourceEnum.fastgpt,
|
||||||
|
flowUsages
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...debugResponse,
|
||||||
|
flowResponses
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default NextAPI(handler);
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
api: {
|
api: {
|
||||||
bodyParser: {
|
bodyParser: {
|
||||||
|
|||||||
@@ -34,11 +34,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
|
|
||||||
if (!chatId || !chatItemId) {
|
if (!chatId || !chatItemId) {
|
||||||
return res.json({
|
return res.json({
|
||||||
[NodeOutputKeyEnum.answerText]: `\\n\\n**自动反馈调试**: "${customFeedback}"\\n\\n`
|
[NodeOutputKeyEnum.answerText]: `\\n\\n**自动反馈调试**: "${customFeedback}"\\n\\n`,
|
||||||
|
text: customFeedback
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.json({});
|
res.json({
|
||||||
|
text: customFeedback
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
res.status(500).send(getErrText(err));
|
res.status(500).send(getErrText(err));
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
appId: app._id,
|
appId: app._id,
|
||||||
teamId,
|
teamId,
|
||||||
tmbId: tmbId,
|
tmbId: tmbId,
|
||||||
|
nodes,
|
||||||
variables: newVariables,
|
variables: newVariables,
|
||||||
isUpdateUseTime: isOwnerUse && source === ChatSourceEnum.online, // owner update use time
|
isUpdateUseTime: isOwnerUse && source === ChatSourceEnum.online, // owner update use time
|
||||||
shareId,
|
shareId,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { Box, Flex, IconButton, useTheme, useDisclosure, Button } from '@chakra-ui/react';
|
import { Box, Flex, IconButton, useTheme, useDisclosure, Button } from '@chakra-ui/react';
|
||||||
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||||
import { AppSchema } from '@fastgpt/global/core/app/type.d';
|
import { AppSchema } from '@fastgpt/global/core/app/type.d';
|
||||||
@@ -25,7 +25,7 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
|||||||
import { formatTime2HM } from '@fastgpt/global/common/string/time';
|
import { formatTime2HM } from '@fastgpt/global/common/string/time';
|
||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
import { WorkflowContext, getWorkflowStore } from '@/components/core/workflow/context';
|
import { WorkflowContext, getWorkflowStore } from '@/components/core/workflow/context';
|
||||||
import { useInterval } from 'ahooks';
|
import { useInterval, useUpdateEffect } from 'ahooks';
|
||||||
|
|
||||||
const ImportSettings = dynamic(() => import('@/components/core/workflow/Flow/ImportSettings'));
|
const ImportSettings = dynamic(() => import('@/components/core/workflow/Flow/ImportSettings'));
|
||||||
const PublishHistories = dynamic(
|
const PublishHistories = dynamic(
|
||||||
@@ -341,6 +341,11 @@ const Header = (props: Props) => {
|
|||||||
nodes: StoreNodeItemType[];
|
nodes: StoreNodeItemType[];
|
||||||
edges: StoreEdgeItemType[];
|
edges: StoreEdgeItemType[];
|
||||||
}>();
|
}>();
|
||||||
|
const { isOpen: isOpenTest, onOpen: onOpenTest, onClose: onCloseTest } = useDisclosure();
|
||||||
|
|
||||||
|
useUpdateEffect(() => {
|
||||||
|
onOpenTest();
|
||||||
|
}, [workflowTestData]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -351,9 +356,10 @@ const Header = (props: Props) => {
|
|||||||
/>
|
/>
|
||||||
<ChatTest
|
<ChatTest
|
||||||
ref={ChatTestRef}
|
ref={ChatTestRef}
|
||||||
|
isOpen={isOpenTest}
|
||||||
{...workflowTestData}
|
{...workflowTestData}
|
||||||
app={app}
|
app={app}
|
||||||
onClose={() => setWorkflowTestData(undefined)}
|
onClose={onCloseTest}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ const EditForm = ({
|
|||||||
const selectLLMModel = watch('aiSettings.model');
|
const selectLLMModel = watch('aiSettings.model');
|
||||||
const datasetSearchSetting = watch('dataset');
|
const datasetSearchSetting = watch('dataset');
|
||||||
const variables = watch('userGuide.variables');
|
const variables = watch('userGuide.variables');
|
||||||
|
|
||||||
const formatVariables = useMemo(
|
const formatVariables = useMemo(
|
||||||
() => formatEditorVariablePickerIcon([...getSystemVariables(t), ...variables]),
|
() => formatEditorVariablePickerIcon([...getSystemVariables(t), ...variables]),
|
||||||
[t, variables]
|
[t, variables]
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import ChatTest from './ChatTest';
|
|||||||
import AppCard from './AppCard';
|
import AppCard from './AppCard';
|
||||||
import EditForm from './EditForm';
|
import EditForm from './EditForm';
|
||||||
import { AppSimpleEditFormType } from '@fastgpt/global/core/app/type';
|
import { AppSimpleEditFormType } from '@fastgpt/global/core/app/type';
|
||||||
|
import { v1Workflow2V2 } from '@/web/core/workflow/adapt';
|
||||||
|
|
||||||
const SimpleEdit = ({ appId }: { appId: string }) => {
|
const SimpleEdit = ({ appId }: { appId: string }) => {
|
||||||
const { isPc } = useSystemStore();
|
const { isPc } = useSystemStore();
|
||||||
@@ -28,6 +29,14 @@ const SimpleEdit = ({ appId }: { appId: string }) => {
|
|||||||
// show selected dataset
|
// show selected dataset
|
||||||
useMount(() => {
|
useMount(() => {
|
||||||
loadAllDatasets();
|
loadAllDatasets();
|
||||||
|
|
||||||
|
if (appDetail.version !== 'v2') {
|
||||||
|
editForm.reset(
|
||||||
|
appWorkflow2Form({
|
||||||
|
nodes: v1Workflow2V2((appDetail.modules || []) as any)?.nodes
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
import type {
|
import type { AIChatItemType, UserChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||||
AIChatItemType,
|
|
||||||
ChatItemType,
|
|
||||||
UserChatItemType
|
|
||||||
} from '@fastgpt/global/core/chat/type.d';
|
|
||||||
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||||
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
|
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
|
||||||
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
|
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
|
||||||
@@ -10,12 +6,15 @@ import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
|
|||||||
import { addLog } from '@fastgpt/service/common/system/log';
|
import { addLog } from '@fastgpt/service/common/system/log';
|
||||||
import { getChatTitleFromChatMessage } from '@fastgpt/global/core/chat/utils';
|
import { getChatTitleFromChatMessage } from '@fastgpt/global/core/chat/utils';
|
||||||
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||||
|
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type';
|
||||||
|
import { getGuideModule, splitGuideModule } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
appId: string;
|
appId: string;
|
||||||
teamId: string;
|
teamId: string;
|
||||||
tmbId: string;
|
tmbId: string;
|
||||||
|
nodes: StoreNodeItemType[];
|
||||||
variables?: Record<string, any>;
|
variables?: Record<string, any>;
|
||||||
isUpdateUseTime: boolean;
|
isUpdateUseTime: boolean;
|
||||||
source: `${ChatSourceEnum}`;
|
source: `${ChatSourceEnum}`;
|
||||||
@@ -30,6 +29,7 @@ export async function saveChat({
|
|||||||
appId,
|
appId,
|
||||||
teamId,
|
teamId,
|
||||||
tmbId,
|
tmbId,
|
||||||
|
nodes,
|
||||||
variables,
|
variables,
|
||||||
isUpdateUseTime,
|
isUpdateUseTime,
|
||||||
source,
|
source,
|
||||||
@@ -72,6 +72,8 @@ export async function saveChat({
|
|||||||
chat.variables = variables || {};
|
chat.variables = variables || {};
|
||||||
await chat.save({ session });
|
await chat.save({ session });
|
||||||
} else {
|
} else {
|
||||||
|
const { welcomeText, variableNodes } = splitGuideModule(getGuideModule(nodes));
|
||||||
|
|
||||||
await MongoChat.create(
|
await MongoChat.create(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@@ -79,6 +81,8 @@ export async function saveChat({
|
|||||||
teamId,
|
teamId,
|
||||||
tmbId,
|
tmbId,
|
||||||
appId,
|
appId,
|
||||||
|
variableList: variableNodes,
|
||||||
|
welcomeText,
|
||||||
variables,
|
variables,
|
||||||
title,
|
title,
|
||||||
source,
|
source,
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ export const getWorkflowGlobalVariables = (
|
|||||||
t: TFunction
|
t: TFunction
|
||||||
): EditorVariablePickerType[] => {
|
): EditorVariablePickerType[] => {
|
||||||
const globalVariables = formatEditorVariablePickerIcon(
|
const globalVariables = formatEditorVariablePickerIcon(
|
||||||
splitGuideModule(getGuideModule(nodes))?.variableModules || []
|
splitGuideModule(getGuideModule(nodes))?.variableNodes || []
|
||||||
).map((item) => ({
|
).map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
valueType: WorkflowIOValueTypeEnum.any
|
valueType: WorkflowIOValueTypeEnum.any
|
||||||
|
|||||||
Reference in New Issue
Block a user