Files
FastGPT/packages/service/core/chat/saveChat.ts
Archer e9d52ada73 4.8.13 feature (#3118)
* chore(ui): login page & workflow page (#3046)

* login page & number input & multirow select & llm select

* workflow

* adjust nodes

* New file upload (#3058)

* feat: toolNode aiNode readFileNode adapt new version

* update docker-compose

* update tip

* feat: adapt new file version

* perf: file input

* fix: ts

* feat: add chat history time label (#3024)

* feat:add chat and logs time

* feat: add chat history time label

* code perf

* code perf

---------

Co-authored-by: 勤劳上班的卑微小张 <jiazhan.zhang@ggimage.com>

* add chatType (#3060)

* pref: slow query of full text search (#3044)

* Adapt findLast api;perf: markdown zh format. (#3066)

* perf: context code

* fix: adapt findLast api

* perf: commercial plugin run error

* perf: markdown zh format

* perf: dockerfile proxy (#3067)

* fix ui (#3065)

* fix ui

* fix

* feat: support array reference multi-select (#3041)

* feat: support array reference multi-select

* fix build

* fix

* fix loop multi-select

* adjust condition

* fix get value

* array and non-array conversion

* fix plugin input

* merge func

* feat: iframe code block;perf: workflow selector type (#3076)

* feat: iframe code block

* perf: workflow selector type

* node pluginoutput check (#3074)

* feat: View will move when workflow check error;fix: ui refresh error when continuous file upload (#3077)

* fix: plugin output check

* fix: ui refresh error when continuous file upload

* feat: View will move when workflow check error

* add dispatch try catch (#3075)

* perf: workflow context split (#3083)

* perf: workflow context split

* perf: context

* 4.8.13 test (#3085)

* perf: workflow node ui

* chat iframe url

* feat: support sub route config (#3071)

* feat: support sub route config

* dockerfile

* fix upload

* delete unused code

* 4.8.13 test (#3087)

* fix: image expired

* fix: datacard navbar ui

* perf: build action

* fix: workflow file upload refresh (#3088)

* fix: http tool response (#3097)

* loop node dynamic height (#3092)

* loop node dynamic height

* fix

* fix

* feat: support push chat log (#3093)

* feat: custom uid/metadata

* to: custom info

* fix: chat push latest

* feat: add chat log envs

* refactor: move timer to pushChatLog

* fix: using precise log

---------

Co-authored-by: Finley Ge <m13203533462@163.com>

* 4.8.13 test (#3098)

* perf: loop node refresh

* rename context

* comment

* fix: ts

* perf: push chat log

* array reference check & node ui (#3100)

* feat: loop start add index (#3101)

* feat: loop start add index

* update doc

* 4.8.13 test (#3102)

* fix: loop index;edge parent check

* perf: reference invalid check

* fix: ts

* fix: plugin select files and ai response check (#3104)

* fix: plugin select files and ai response check

* perf: text editor selector;tool call tip;remove invalid image url;

* perf: select file

* perf: drop files

* feat: source id prefix env (#3103)

* 4.8.13 test (#3106)

* perf: select file

* perf: drop files

* perf: env template

* 4.8.13 test (#3107)

* perf: select file

* perf: drop files

* fix: imple mode adapt files

* perf: push chat log (#3109)

* fix: share page load title error (#3111)

* 4.8.13 perf (#3112)

* fix: share page load title error

* update file input doc

* perf: auto add file urls

* perf: auto ser loop node offset height

* 4.8.13 test (#3117)

* perf: plugin

* updat eaction

* feat: add more share config (#3120)

* feat: add more share config

* add i18n en

* fix: missing subroute (#3121)

* perf: outlink config (#3128)

* update action

* perf: outlink config

* fix: ts (#3129)

* 更新 docSite 文档内容 (#3131)

* fix: null pointer (#3130)

* fix: null pointer

* perf: not input text

* update doc url

* perf: outlink default value (#3134)

* update doc (#3136)

* 4.8.13 test (#3137)

* update doc

* perf: completions chat api

* Restore docSite content based on upstream/4.8.13-dev (#3138)

* Restore docSite content based on upstream/4.8.13-dev

* 4813.md缺少更正

* update doc (#3141)

---------

Co-authored-by: heheer <heheer@sealos.io>
Co-authored-by: papapatrick <109422393+Patrickill@users.noreply.github.com>
Co-authored-by: 勤劳上班的卑微小张 <jiazhan.zhang@ggimage.com>
Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
Co-authored-by: a.e. <49438478+I-Info@users.noreply.github.com>
Co-authored-by: Finley Ge <m13203533462@163.com>
Co-authored-by: Jiangween <145003935+Jiangween@users.noreply.github.com>
2024-11-13 11:29:53 +08:00

245 lines
5.7 KiB
TypeScript

import type {
AIChatItemType,
ChatItemType,
UserChatItemType
} from '@fastgpt/global/core/chat/type.d';
import axios from 'axios';
import { MongoApp } from '../app/schema';
import {
ChatItemValueTypeEnum,
ChatRoleEnum,
ChatSourceEnum
} from '@fastgpt/global/core/chat/constants';
import { MongoChatItem } from './chatItemSchema';
import { MongoChat } from './chatSchema';
import { addLog } from '../../common/system/log';
import { mongoSessionRun } from '../../common/mongo/sessionRun';
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
import { getAppChatConfig, getGuideModule } from '@fastgpt/global/core/workflow/utils';
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
import { mergeChatResponseData } from '@fastgpt/global/core/chat/utils';
import { pushChatLog } from './pushChatLog';
type Props = {
chatId: string;
appId: string;
teamId: string;
tmbId: string;
nodes: StoreNodeItemType[];
appChatConfig?: AppChatConfigType;
variables?: Record<string, any>;
isUpdateUseTime: boolean;
newTitle: string;
source: string;
shareId?: string;
outLinkUid?: string;
content: [UserChatItemType & { dataId?: string }, AIChatItemType & { dataId?: string }];
metadata?: Record<string, any>;
};
export async function saveChat({
chatId,
appId,
teamId,
tmbId,
nodes,
appChatConfig,
variables,
isUpdateUseTime,
newTitle,
source,
shareId,
outLinkUid,
content,
metadata = {}
}: Props) {
try {
const chat = await MongoChat.findOne(
{
appId,
chatId
},
'_id metadata'
);
const metadataUpdate = {
...chat?.metadata,
...metadata
};
const { welcomeText, variables: variableList } = getAppChatConfig({
chatConfig: appChatConfig,
systemConfigNode: getGuideModule(nodes),
isPublicFetch: false
});
await mongoSessionRun(async (session) => {
const [{ _id: chatItemIdHuman }, { _id: chatItemIdAi }] = await MongoChatItem.insertMany(
content.map((item) => ({
chatId,
teamId,
tmbId,
appId,
...item
})),
{ session }
);
await MongoChat.updateOne(
{
appId,
chatId
},
{
$set: {
teamId,
tmbId,
appId,
chatId,
variableList,
welcomeText,
variables: variables || {},
title: newTitle,
source,
shareId,
outLinkUid,
metadata: metadataUpdate,
updateTime: new Date()
}
},
{
session,
upsert: true
}
);
pushChatLog({
chatId,
chatItemIdHuman: String(chatItemIdHuman),
chatItemIdAi: String(chatItemIdAi),
appId
});
});
if (isUpdateUseTime) {
await MongoApp.findByIdAndUpdate(appId, {
updateTime: new Date()
});
}
} catch (error) {
addLog.error(`update chat history error`, error);
}
}
export const updateInteractiveChat = async ({
chatId,
appId,
teamId,
tmbId,
userInteractiveVal,
aiResponse,
newVariables,
newTitle
}: {
chatId: string;
appId: string;
teamId: string;
tmbId: string;
userInteractiveVal: string;
aiResponse: AIChatItemType & { dataId?: string };
newVariables?: Record<string, any>;
newTitle: string;
}) => {
if (!chatId) return;
const chatItem = await MongoChatItem.findOne({ appId, chatId, obj: ChatRoleEnum.AI }).sort({
_id: -1
});
if (!chatItem || chatItem.obj !== ChatRoleEnum.AI) return;
// Update interactive value
const interactiveValue = chatItem.value[chatItem.value.length - 1];
if (
!interactiveValue ||
interactiveValue.type !== ChatItemValueTypeEnum.interactive ||
!interactiveValue.interactive?.params
) {
return;
}
const parsedUserInteractiveVal = (() => {
try {
return JSON.parse(userInteractiveVal);
} catch (err) {
return userInteractiveVal;
}
})();
if (interactiveValue.interactive.type === 'userSelect') {
interactiveValue.interactive = {
...interactiveValue.interactive,
params: {
...interactiveValue.interactive.params,
userSelectedVal: userInteractiveVal
}
};
} else if (
interactiveValue.interactive.type === 'userInput' &&
typeof parsedUserInteractiveVal === 'object'
) {
interactiveValue.interactive = {
...interactiveValue.interactive,
params: {
...interactiveValue.interactive.params,
inputForm: interactiveValue.interactive.params.inputForm.map((item) => {
const itemValue = parsedUserInteractiveVal[item.label];
return itemValue !== undefined
? {
...item,
value: itemValue
}
: item;
}),
submitted: true
}
};
}
if (aiResponse.customFeedbacks) {
chatItem.customFeedbacks = chatItem.customFeedbacks
? [...chatItem.customFeedbacks, ...aiResponse.customFeedbacks]
: aiResponse.customFeedbacks;
}
if (aiResponse.responseData) {
chatItem.responseData = chatItem.responseData
? mergeChatResponseData([...chatItem.responseData, ...aiResponse.responseData])
: aiResponse.responseData;
}
if (aiResponse.value) {
chatItem.value = chatItem.value ? [...chatItem.value, ...aiResponse.value] : aiResponse.value;
}
await mongoSessionRun(async (session) => {
await chatItem.save({ session });
await MongoChat.updateOne(
{
appId,
chatId
},
{
$set: {
variables: newVariables,
title: newTitle,
updateTime: new Date()
}
},
{
session
}
);
});
};