This commit is contained in:
Archer
2024-05-28 16:55:06 +08:00
committed by GitHub
parent 9639139b52
commit 8ba8488086
13 changed files with 152 additions and 86 deletions

View File

@@ -82,3 +82,27 @@ jobs:
run: docker tag ghcr.io/${{ github.repository_owner }}/fastgpt-sandbox:${{env.IMAGE_TAG}} ${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sandbox:${{env.IMAGE_TAG}} run: docker tag ghcr.io/${{ github.repository_owner }}/fastgpt-sandbox:${{env.IMAGE_TAG}} ${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sandbox:${{env.IMAGE_TAG}}
- name: Push image to Docker Hub - name: Push image to Docker Hub
run: docker push ${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sandbox:${{env.IMAGE_TAG}} run: docker push ${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sandbox:${{env.IMAGE_TAG}}
push-to-docker-hub:
needs: build-fastgpt-sandbox-images
runs-on: ubuntu-20.04
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_NAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Set DOCKER_REPO_TAGGED based on branch or tag
run: |
if [[ "${{ github.ref_name }}" == "main" ]]; then
echo "IMAGE_TAG=latest" >> $GITHUB_ENV
else
echo "IMAGE_TAG=${{ github.ref_name }}" >> $GITHUB_ENV
fi
- name: Pull image from GitHub Container Registry
run: docker pull ghcr.io/${{ github.repository_owner }}/fastgpt-sandbox:${{env.IMAGE_TAG}}
- name: Tag image with Docker Hub repository name and version tag
run: docker tag ghcr.io/${{ github.repository_owner }}/fastgpt-sandbox:${{env.IMAGE_TAG}} ${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sandbox:${{env.IMAGE_TAG}}
- name: Push image to Docker Hub
run: docker push ${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sandbox:${{env.IMAGE_TAG}}

View File

@@ -80,9 +80,9 @@ jobs:
- name: Pull image from GitHub Container Registry - name: Pull image from GitHub Container Registry
run: docker pull ghcr.io/${{ github.repository_owner }}/fastgpt:${{env.IMAGE_TAG}} run: docker pull ghcr.io/${{ github.repository_owner }}/fastgpt:${{env.IMAGE_TAG}}
- name: Tag image with Docker Hub repository name and version tag - name: Tag image with Docker Hub repository name and version tag
run: docker tag ghcr.io/${{ github.repository_owner }}/fastgpt:${{env.IMAGE_TAG}} ${{ secrets.DOCKER_IMAGE_NAME }}:${{env.IMAGE_TAG}} run: docker tag ghcr.io/${{ github.repository_owner }}/fastgpt:${{env.IMAGE_TAG}} ${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt:${{env.IMAGE_TAG}}
- name: Push image to Docker Hub - name: Push image to Docker Hub
run: docker push ${{ secrets.DOCKER_IMAGE_NAME }}:${{env.IMAGE_TAG}} run: docker push ${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt:${{env.IMAGE_TAG}}
push-to-ali-hub: push-to-ali-hub:
needs: build-fastgpt-images needs: build-fastgpt-images
if: github.repository == 'labring/FastGPT' if: github.repository == 'labring/FastGPT'
@@ -106,6 +106,6 @@ jobs:
- name: Pull image from GitHub Container Registry - name: Pull image from GitHub Container Registry
run: docker pull ghcr.io/${{ github.repository_owner }}/fastgpt:${{env.IMAGE_TAG}} run: docker pull ghcr.io/${{ github.repository_owner }}/fastgpt:${{env.IMAGE_TAG}}
- name: Tag image with Docker Hub repository name and version tag - name: Tag image with Docker Hub repository name and version tag
run: docker tag ghcr.io/${{ github.repository_owner }}/fastgpt:${{env.IMAGE_TAG}} ${{ secrets.ALI_IMAGE_NAME }}:${{env.IMAGE_TAG}} run: docker tag ghcr.io/${{ github.repository_owner }}/fastgpt:${{env.IMAGE_TAG}} ${{ secrets.ALI_IMAGE_NAME }}/fastgpt:${{env.IMAGE_TAG}}
- name: Push image to Docker Hub - name: Push image to Docker Hub
run: docker push ${{ secrets.ALI_IMAGE_NAME }}:${{env.IMAGE_TAG}} run: docker push ${{ secrets.ALI_IMAGE_NAME }}/fastgpt:${{env.IMAGE_TAG}}

View File

@@ -47,7 +47,7 @@ jobs:
-f projects/app/Dockerfile \ -f projects/app/Dockerfile \
--label "org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/FastGPT" \ --label "org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/FastGPT" \
--label "org.opencontainers.image.description=fastgpt-pr imae" \ --label "org.opencontainers.image.description=fastgpt-pr imae" \
--label "org.opencontainers.image.licenses=Apache" \g --label "org.opencontainers.image.licenses=Apache" \
--push \ --push \
--cache-from=type=local,src=/tmp/.buildx-cache \ --cache-from=type=local,src=/tmp/.buildx-cache \
--cache-to=type=local,dest=/tmp/.buildx-cache \ --cache-to=type=local,dest=/tmp/.buildx-cache \

View File

@@ -0,0 +1,33 @@
---
title: 'V4.8.2'
description: 'FastGPT V4.8.2 更新说明'
icon: 'upgrade'
draft: false
toc: true
weight: 822
---
## Sealos 升级说明
1. 在应用管理中新建一个应用镜像为registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.8.1
2. 无需外网访问地址
3. 部署完后,复制应用的内网地址
4. 点击变更`FastGPT - 修改环境变量,增加下面的环境变量即可
```
SANDBOX_URL=内网地址
```
## Docker 部署
可以拉取最新 [docker-compose.yml](https://github.com/labring/FastGPT/blob/main/files/deploy/fastgpt/docker-compose.yml) 文件参考
1. 新增一个容器 `sandbox`
2. fastgpt容器新增环境变量: `SANDBOX_URL`
3. sandbox 简易不要开启外网访问,未做凭证校验。
## V4.8.2 更新说明
1. 新增 - js代码运行节点更完整的type提醒后续继续完善
2. 修复 - 新增的站点同步无法使用
3. 修复 - 定时任务无法输入内容

View File

@@ -67,10 +67,17 @@ services:
# 等待docker-entrypoint.sh脚本执行的MongoDB服务进程 # 等待docker-entrypoint.sh脚本执行的MongoDB服务进程
wait $$! wait $$!
sandbox:
container_name: sandbox
image: ghcr.io/labring/fastgpt-sandbox:v4.8.2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.8.2 # 阿里云
networks:
- fastgpt
restart: always
fastgpt: fastgpt:
container_name: fastgpt container_name: fastgpt
image: ghcr.io/labring/fastgpt:v4.8.1 # git image: ghcr.io/labring/fastgpt:v4.8.2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 # 阿里云 # image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.2 # 阿里云
ports: ports:
- 3000:3000 - 3000:3000
networks: networks:
@@ -78,6 +85,7 @@ services:
depends_on: depends_on:
- mongo - mongo
- pg - pg
- sandbox
restart: always restart: always
environment: environment:
# root 密码,用户名为: root。如果需要修改 root 密码,直接修改这个环境变量,并重启即可。 # root 密码,用户名为: root。如果需要修改 root 密码,直接修改这个环境变量,并重启即可。
@@ -98,6 +106,8 @@ services:
- MONGODB_URI=mongodb://myusername:mypassword@mongo:27017/fastgpt?authSource=admin - MONGODB_URI=mongodb://myusername:mypassword@mongo:27017/fastgpt?authSource=admin
# pg 连接参数 # pg 连接参数
- PG_URL=postgresql://username:password@pg:5432/postgres - PG_URL=postgresql://username:password@pg:5432/postgres
# sandbox 地址
- SANDBOX_URL=http://sandbox:3000
volumes: volumes:
- ./config.json:/app/data/config.json - ./config.json:/app/data/config.json
- ./fastgpt/tmp:/app/tmp - ./fastgpt/tmp:/app/tmp

View File

@@ -1,32 +1,12 @@
### FastGPT V4.8 ### FastGPT V4.8.2
本次更新的重点是对工作流 (高级编排) 进行了重构,使其更加简洁和强大。但由于新旧工作流机制有较大变化,尽管我们进行了一定的自动转换,仍有部分工作流需要您手动重建。请尽快更新到新版本,并对工作流进行必要的调试和重新发布。 - 新增 - 知识库重新选择向量模型重建
- 新增 - 对话框支持问题模糊检索提示,可自定义预设问题词库
❗ 重要提示: - 新增 - js代码运行节点
1⃣ 旧工作流更新后暂不失效,打开旧工作流会弹出自动转换提示,重新编排后点 “发布” 按钮发布新工作流 - 新增 - 外部文件源知识库: [点击查看文档](https://doc.fastai.site/docs/course/externalfile/)
2⃣ 发布新工作流前,工作流自动保存功能暂不生效 - 新增 - 内容提取节点增加完全提取成功输出
3⃣ 应用和插件新增 version 字段,标识适用新/旧版工作流,以实现兼容 - 新增 - HTTP节点增加错误输出可以自行判断处理
- 优化 - 插件输入的 debug 模式,支持全量参数输入渲染
✨ 新增功能亮点:
1⃣ 判断器:支持 if/elseIf/else 判断逻辑,工作流控制更灵活
2⃣ 变量更新节点:运行中可动态修改工作流输出变量或全局变量值
3⃣ 工作流自动保存和版本管理:自动保存修改,支持查看和回滚历史版本
4⃣ 工作流调试模式:更直观高效,可调试单节点或逐步执行,实时查看输入输出数据
5⃣ 定时执行应用:支持简单配置实现各种定时任务
🛠️ 其他优化与修复:
- 优化工作流节点连线方式,支持四向连接,易构建循环工作流
- 显著提升工作流上下文数据传递性能
- 简易模式下修改配置自动刷新调试框,免手动保存
- 改进 worker 进程管理,支持 Token 计算任务分配,提高效率
- 工具调用支持 string、boolean、number 数据类型
- 完善 completions 接口对 size 参数限制
- 重构 Node.js API 中间件和服务端代码
- 对话记录长度调整为偶数,最大长度增至 50 轮,避免奇数导致部分模型不兼容
- HTTP 节点出错将终止进程,避免异常影响
- 修复工具调用名称不能以数字开头问题
- 修复分享链接 query 参数缓存 bug
- 修复工具调用和 HTTP 模块兼容性问题
- [点击查看高级编排介绍文档](https://doc.fastgpt.in/docs/workflow/intro) - [点击查看高级编排介绍文档](https://doc.fastgpt.in/docs/workflow/intro)
- [使用文档](https://doc.fastgpt.in/docs/intro/) - [使用文档](https://doc.fastgpt.in/docs/intro/)
- [点击查看商业版](https://doc.fastgpt.in/docs/commercial/) - [点击查看商业版](https://doc.fastgpt.in/docs/commercial/)

View File

@@ -99,7 +99,7 @@ const ScheduledTriggerConfig = ({
const timezone = value?.timezone; const timezone = value?.timezone;
const cronString = value?.cronString; const cronString = value?.cronString;
const defaultPrompt = value?.defaultPrompt || ''; const defaultPrompt = value?.defaultPrompt;
const cronSelectList = useRef<MultipleSelectProps['list']>([ const cronSelectList = useRef<MultipleSelectProps['list']>([
{ {
@@ -134,15 +134,10 @@ const ScheduledTriggerConfig = ({
timezone?: string; timezone?: string;
defaultPrompt?: string; defaultPrompt?: string;
}) => { }) => {
if (!cronString) {
onChange(undefined);
return;
}
onChange({ onChange({
...value, cronString: cronString ?? value?.cronString ?? '0 0 * * *',
cronString, timezone: timezone ?? value?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone,
timezone: timezone || Intl.DateTimeFormat().resolvedOptions().timeZone, defaultPrompt: defaultPrompt ?? value?.defaultPrompt ?? ''
defaultPrompt: defaultPrompt || ''
}); });
}, },
[onChange, value] [onChange, value]
@@ -314,7 +309,7 @@ const ScheduledTriggerConfig = ({
</Box> </Box>
</Flex> </Flex>
<Box mt={5}> <Box mt={5}>
<Box>{t('core.app.schedule.Default prompt')}</Box> <Box mb={1}>{t('core.app.schedule.Default prompt')}</Box>
<Textarea <Textarea
value={defaultPrompt} value={defaultPrompt}
rows={8} rows={8}

View File

@@ -7,9 +7,10 @@ import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '../../context'; import { WorkflowContext } from '../../context';
const ButtonEdge = (props: EdgeProps) => { const ButtonEdge = (props: EdgeProps) => {
const nodes = useContextSelector(WorkflowContext, (v) => v.nodes); const { nodes, setEdges, workflowDebugData, hoverEdgeId } = useContextSelector(
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges); WorkflowContext,
const workflowDebugData = useContextSelector(WorkflowContext, (v) => v.workflowDebugData); (v) => v
);
const { const {
id, id,
@@ -50,6 +51,7 @@ const ButtonEdge = (props: EdgeProps) => {
}); });
const isToolEdge = sourceHandleId === NodeOutputKeyEnum.selectedTools; const isToolEdge = sourceHandleId === NodeOutputKeyEnum.selectedTools;
const isHover = hoverEdgeId === id;
const { newTargetX, newTargetY } = useMemo(() => { const { newTargetX, newTargetY } = useMemo(() => {
if (targetPosition === 'left') { if (targetPosition === 'left') {
@@ -116,24 +118,23 @@ const ButtonEdge = (props: EdgeProps) => {
})(); })();
return ( return (
<EdgeLabelRenderer> <EdgeLabelRenderer>
{highlightEdge && ( <Flex
<Flex display={isHover || highlightEdge ? 'flex' : 'none'}
alignItems={'center'} alignItems={'center'}
justifyContent={'center'} justifyContent={'center'}
position={'absolute'} position={'absolute'}
transform={`translate(-55%, -50%) translate(${labelX}px,${labelY}px)`} transform={`translate(-55%, -50%) translate(${labelX}px,${labelY}px)`}
pointerEvents={'all'} pointerEvents={'all'}
w={'17px'} w={'17px'}
h={'17px'} h={'17px'}
bg={'white'} bg={'white'}
borderRadius={'17px'} borderRadius={'17px'}
cursor={'pointer'} cursor={'pointer'}
zIndex={1000} zIndex={1000}
onClick={() => onDelConnect(id)} onClick={() => onDelConnect(id)}
> >
<MyIcon name={'core/workflow/closeEdge'} w={'100%'}></MyIcon> <MyIcon name={'core/workflow/closeEdge'} w={'100%'}></MyIcon>
</Flex> </Flex>
)}
{!isToolEdge && ( {!isToolEdge && (
<Flex <Flex
alignItems={'center'} alignItems={'center'}
@@ -161,6 +162,7 @@ const ButtonEdge = (props: EdgeProps) => {
</EdgeLabelRenderer> </EdgeLabelRenderer>
); );
}, [ }, [
isHover,
highlightEdge, highlightEdge,
labelX, labelX,
labelY, labelY,

View File

@@ -11,7 +11,8 @@ import ReactFlow, {
NodeChange, NodeChange,
OnConnectStartParams, OnConnectStartParams,
addEdge, addEdge,
EdgeChange EdgeChange,
Edge
} from 'reactflow'; } from 'reactflow';
import { Box, Flex, IconButton, useDisclosure } from '@chakra-ui/react'; import { Box, Flex, IconButton, useDisclosure } from '@chakra-ui/react';
import { SmallCloseIcon } from '@chakra-ui/icons'; import { SmallCloseIcon } from '@chakra-ui/icons';
@@ -74,13 +75,16 @@ const Container = React.memo(function Container() {
}); });
const { isDowningCtrl } = useKeyboard(); const { isDowningCtrl } = useKeyboard();
const setConnectingEdge = useContextSelector(WorkflowContext, (v) => v.setConnectingEdge); const {
const reactFlowWrapper = useContextSelector(WorkflowContext, (v) => v.reactFlowWrapper); setConnectingEdge,
const nodes = useContextSelector(WorkflowContext, (v) => v.nodes); reactFlowWrapper,
const onNodesChange = useContextSelector(WorkflowContext, (v) => v.onNodesChange); nodes,
const edges = useContextSelector(WorkflowContext, (v) => v.edges); onNodesChange,
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges); edges,
const onEdgesChange = useContextSelector(WorkflowContext, (v) => v.onEdgesChange); setEdges,
onEdgesChange,
setHoverEdgeId
} = useContextSelector(WorkflowContext, (v) => v);
/* node */ /* node */
const handleNodesChange = useCallback( const handleNodesChange = useCallback(
@@ -159,6 +163,17 @@ const Container = React.memo(function Container() {
[onConnect, t, toast] [onConnect, t, toast]
); );
/* edge */
const onEdgeMouseEnter = useCallback(
(e: any, edge: Edge) => {
setHoverEdgeId(edge.id);
},
[setHoverEdgeId]
);
const onEdgeMouseLeave = useCallback(() => {
setHoverEdgeId(undefined);
}, [setHoverEdgeId]);
return ( return (
<> <>
<ReactFlow <ReactFlow
@@ -178,6 +193,8 @@ const Container = React.memo(function Container() {
onConnect={customOnConnect} onConnect={customOnConnect}
onConnectStart={onConnectStart} onConnectStart={onConnectStart}
onConnectEnd={onConnectEnd} onConnectEnd={onConnectEnd}
onEdgeMouseEnter={onEdgeMouseEnter}
onEdgeMouseLeave={onEdgeMouseLeave}
> >
<FlowController /> <FlowController />
</ReactFlow> </ReactFlow>

View File

@@ -70,6 +70,8 @@ type WorkflowContextType = {
sourceHandle?: string | undefined; sourceHandle?: string | undefined;
targetHandle?: string | undefined; targetHandle?: string | undefined;
}) => void; }) => void;
hoverEdgeId?: string;
setHoverEdgeId: React.Dispatch<React.SetStateAction<string | undefined>>;
// connect // connect
connectingEdge?: OnConnectStartParams; connectingEdge?: OnConnectStartParams;
@@ -216,6 +218,9 @@ export const WorkflowContext = createContext<WorkflowContextType>({
isShowVersionHistories: false, isShowVersionHistories: false,
setIsShowVersionHistories: function (value: React.SetStateAction<boolean>): void { setIsShowVersionHistories: function (value: React.SetStateAction<boolean>): void {
throw new Error('Function not implemented.'); throw new Error('Function not implemented.');
},
setHoverEdgeId: function (value: React.SetStateAction<string | undefined>): void {
throw new Error('Function not implemented.');
} }
}); });
@@ -233,6 +238,7 @@ const WorkflowContextProvider = ({
/* edge */ /* edge */
const [edges, setEdges, onEdgesChange] = useEdgesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const [hoverEdgeId, setHoverEdgeId] = useState<string>();
const onDelEdge = useCallback( const onDelEdge = useCallback(
({ ({
nodeId, nodeId,
@@ -673,6 +679,8 @@ const WorkflowContextProvider = ({
// edge // edge
edges, edges,
setEdges, setEdges,
hoverEdgeId,
setHoverEdgeId,
onEdgesChange, onEdgesChange,
connectingEdge, connectingEdge,
setConnectingEdge, setConnectingEdge,

View File

@@ -78,17 +78,16 @@ const CollectionPageContextProvider = ({ children }: { children: ReactNode }) =>
mutationFn: async (websiteConfig: DatasetSchemaType['websiteConfig']) => { mutationFn: async (websiteConfig: DatasetSchemaType['websiteConfig']) => {
onCloseWebsiteModal(); onCloseWebsiteModal();
await checkTeamWebSyncLimit(); await checkTeamWebSyncLimit();
const billId = await postCreateTrainingUsage({
name: t('core.dataset.training.Website Sync'),
datasetId: datasetId
});
await postWebsiteSync({ datasetId: datasetId, billId });
await updateDataset({ await updateDataset({
id: datasetId, id: datasetId,
websiteConfig, websiteConfig,
status: DatasetStatusEnum.syncing status: DatasetStatusEnum.syncing
}); });
const billId = await postCreateTrainingUsage({
name: t('core.dataset.training.Website Sync'),
datasetId: datasetId
});
await postWebsiteSync({ datasetId: datasetId, billId });
return; return;
}, },

View File

@@ -39,7 +39,6 @@ import { useToast } from '@fastgpt/web/hooks/useToast';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { useUserStore } from '@/web/support/user/useUserStore'; import { useUserStore } from '@/web/support/user/useUserStore';
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant'; import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { DatasetCollectionSyncResultEnum } from '@fastgpt/global/core/dataset/constants'; import { DatasetCollectionSyncResultEnum } from '@fastgpt/global/core/dataset/constants';
import MyBox from '@fastgpt/web/components/common/MyBox'; import MyBox from '@fastgpt/web/components/common/MyBox';
import { useContextSelector } from 'use-context-selector'; import { useContextSelector } from 'use-context-selector';

View File

@@ -1,11 +1,10 @@
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant'; import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d'; import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
export const getChatModelNameListByModules = (modules: StoreNodeItemType[]): string[] => { export const getChatModelNameListByModules = (nodes: StoreNodeItemType[]): string[] => {
const chatModules = modules.filter((item) => item.flowNodeType === FlowNodeTypeEnum.chatNode); return nodes
return chatModules
.map((item) => { .map((item) => {
const model = item.inputs.find((input) => input.key === 'model')?.value; const model = item.inputs.find((input) => input.key === NodeInputKeyEnum.aiModel)?.value;
return global.llmModels.find((item) => item.model === model)?.name || ''; return global.llmModels.find((item) => item.model === model)?.name || '';
}) })
.filter(Boolean); .filter(Boolean);