Compare commits

..

28 Commits

Author SHA1 Message Date
Archer
e6efd3318d perf: long org name ui (#4347)
* sync collection

* remove lock

* perf: long org name ui
2025-03-26 22:22:20 +08:00
Finley Ge
95ffd710aa pref: member list (#4344)
* chore: search member new api

* chore: permission

* fix: ts error

* fix: member modal
2025-03-26 22:10:03 +08:00
Archer
097bb97417 perf: intro wrap (#4346)
* sync collection

* remove lock

* perf: intro wrap
2025-03-26 21:38:52 +08:00
Finley Ge
4faea8d2b8 fix: group (#4330) 2025-03-26 11:48:58 +08:00
Archer
7ecadb33d1 fix: ts (#4325)
* sync collection

* remove lock

* fix: ts
2025-03-26 10:48:33 +08:00
Archer
ce61bda223 perf: member group (#4324)
* sync collection

* remove lock

* perf: member group
2025-03-26 10:48:32 +08:00
Finley Ge
8dba01da73 fix: member list, login button (#4322) 2025-03-26 10:48:32 +08:00
Finley Ge
dcdad6fa39 pref: member/group/org (#4316)
* feat: change group owner api

* pref: member/org/group

* fix: member modal select clb

* fix: search member when change owner
2025-03-26 10:48:32 +08:00
Archer
11d080d521 update search filter code (#4317)
* sync collection

* remove lock

* update search filter code
2025-03-26 10:48:32 +08:00
Archer
2f954d2f3f perf: text splitter (#4313)
* sync collection

* remove lock

* perf: text splitter

* update comment
2025-03-26 10:48:31 +08:00
Archer
a956fbca73 tmp org api rewrite (#4304)
* sync collection

* remove lock

* tmp org api rewrite
2025-03-26 10:48:31 +08:00
Finley Ge
db7510c5eb pref: member/org/gourp list (#4295)
* refactor: org api

* refactor: org api

* pref: member/org/group list

* feat: change group owner api

* fix: manage org member

* pref: member search
2025-03-26 10:48:31 +08:00
Archer
b87cc353da perf: ai proxy log remove retry log;perf: workflow type auto parse;add chunk spliter test (#4296)
* sync collection

* remove lock

* perf: workflow type auto parse

* add chunk spliter test

* perf: ai proxy log remove retry log

* udpate ai proxy field
2025-03-26 10:48:31 +08:00
Archer
ff85121546 add model test log (#4272)
* sync collection

* remove lock

* add model test log

* update ui

* update log

* fix: channel test

* preview chunk ui

* test model ux

* test model log

* perf: dataset selector

* fix: system plugin auth

* update nextjs
2025-03-26 10:48:30 +08:00
heheer
79f9d83349 fix input form label overflow (#4266) 2025-03-26 10:48:30 +08:00
Archer
159bf17369 feat: chunk index independent config (#4271)
* sync collection

* remove lock

* feat: chunk index independent config

* feat: add max chunksize to split chunk function

* remove log

* update doc

* remove

* remove log
2025-03-26 10:48:29 +08:00
Finley Ge
4512b23d4d fix: member count (#4269) 2025-03-26 10:48:29 +08:00
Archer
5300ddf654 perf: ai proxy (#4265)
* sync collection

* remove lock

* perf: ai proxy
2025-03-26 10:48:29 +08:00
Archer
f1f0dfc691 update prompt version (#4242)
* sync collection

* remove lock

* update prompt version
2025-03-26 10:48:28 +08:00
heheer
e5acec8dc7 feat: node prompt version (#4141)
* feat: node prompt version

* fix

* delete unused code

* fix

* fix code
2025-03-26 10:48:28 +08:00
heheer
cb832b6305 fix variable sync & popover button height (#4227)
* fix variable sync & popover button height

* required
2025-03-26 10:48:28 +08:00
Finley Ge
ae9b8a2b8e Sso (#4235)
* feat: redirect url can be inner url (#4138)

* fix: update new user sync api (#4145)

* feat: post all params to backend (#4151)

* pref: sso getauthurl api (#4172)

* pref: sso getauthurl api

* pref: sso

* solve the rootorglist (#4234)

---------

Co-authored-by: gggaaallleee <91131304+gggaaallleee@users.noreply.github.com>
2025-03-26 10:48:27 +08:00
Archer
d209255015 fix ts (#4239)
* sync collection

* remove lock

* fix ts

* fix: ts
2025-03-26 10:48:27 +08:00
Archer
6eae841e4a feat: sync api collection will refresh title;perf: invite link ux (#4237)
* update queue

* feat: sync api collection will refresh title

* sync collection

* remove lock

* perf: invite link ux
2025-03-26 10:48:26 +08:00
Finley Ge
75c1631670 fix: invite link (#4229)
* fix: invite link

* feat: create invite link and copy it directly
2025-03-26 10:48:26 +08:00
Archer
97a182c7fd perf: custom varialbe (#4225) 2025-03-26 10:48:26 +08:00
heheer
a0ad450032 add external variable debug (#4204)
* add external variable debug

* fix ui

* plugin variables
2025-03-26 10:48:25 +08:00
Archer
74b36219e1 feat: custom dataset split sign (#4221)
* feat: custom dataset split sign

* feat: custom dataset split sign
2025-03-26 10:48:23 +08:00
319 changed files with 2862 additions and 10787 deletions

30
.github/gh-bot.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
version: v1
debug: true
action:
printConfig: false
release:
retry: 15s
actionName: Release
allowOps:
- cuisongliu
bot:
prefix: /
spe: _
allowOps:
- sealos-ci-robot
- sealos-release-robot
email: sealos-ci-robot@sealos.io
username: sealos-ci-robot
repo:
org: false
message:
success: |
🤖 says: Hooray! The action {{.Body}} has been completed successfully. 🎉
format_error: |
🤖 says: ‼️ There is a formatting issue with the action, kindly verify the action's format.
permission_error: |
🤖 says: ‼️ The action doesn't have permission to trigger.
release_error: |
🤖 says: ‼️ Release action failed.
Error details: {{.Error}}

View File

@@ -1,4 +1,4 @@
yangchuansheng/fastgpt-imgs:
- source: docSite/assets/imgs/
dest: imgs/
deleteOrphaned: true
deleteOrphaned: true

View File

@@ -10,13 +10,6 @@ on:
jobs:
build-fastgpt-docs-images:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -34,6 +27,7 @@ jobs:
with:
# list of Docker images to use as base name for tags
images: |
${{ secrets.DOCKER_HUB_NAME }}/fastgpt-docs
ghcr.io/${{ github.repository_owner }}/fastgpt-docs
registry.cn-hangzhou.aliyuncs.com/${{ secrets.ALI_HUB_USERNAME }}/fastgpt-docs
tags: |
@@ -46,12 +40,18 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_NAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
username: ${{ github.repository_owner }}
password: ${{ secrets.GH_PAT }}
- name: Login to Aliyun
uses: docker/login-action@v3
@@ -70,7 +70,6 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
outputs:
tags: ${{ steps.datetime.outputs.datetime }}
update-docs-image:
needs: build-fastgpt-docs-images
runs-on: ubuntu-20.04

View File

@@ -1,4 +1,4 @@
name: Deploy doc image to cf
name: Deploy doc image to vercel
on:
workflow_dispatch:
@@ -20,11 +20,6 @@ jobs:
# The type of runner that the job will run on
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
# Job outputs
outputs:
docs: ${{ steps.filter.outputs.docs }}
@@ -63,9 +58,20 @@ jobs:
- name: Build
run: cd docSite && hugo mod get -u github.com/colinwilson/lotusdocs@6d0568e && hugo -v --minify
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
if: github.ref == 'refs/heads/main'
# Step 5 - Push our generated site to Vercel
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
id: vercel-action
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
vercel-token: ${{ secrets.VERCEL_TOKEN }} # Required
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} #Required
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} #Required
github-comment: false
vercel-args: '--prod --local-config ../vercel.json' # Optional
working-directory: docSite/public
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GH_PAT }}
publish_dir: docSite/public

View File

@@ -10,12 +10,6 @@ on:
jobs:
# This workflow contains jobs "deploy-production"
deploy-preview:
permissions:
contents: read
packages: write
attestations: write
id-token: write
pull-requests: write
# The environment this job references
environment:
name: Preview
@@ -38,7 +32,6 @@ jobs:
repository: ${{ github.event.pull_request.head.repo.full_name }}
submodules: recursive # Fetch submodules
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
token: ${{ secrets.GITHUB_TOKEN }}
# Step 2 Detect changes to Docs Content
- name: Detect changes in doc content
@@ -50,6 +43,10 @@ jobs:
- 'docSite/content/docs/**'
base: main
- name: Add cdn for images
run: |
sed -i "s#\](/imgs/#\](https://cdn.jsdelivr.net/gh/yangchuansheng/fastgpt-imgs@main/imgs/#g" $(grep -rl "\](/imgs/" docSite/content/zh-cn/docs)
# Step 3 - Install Hugo (specific version)
- name: Install Hugo
uses: peaceiris/actions-hugo@v2
@@ -61,35 +58,39 @@ jobs:
- name: Build
run: cd docSite && hugo mod get -u github.com/colinwilson/lotusdocs@6d0568e && hugo -v --minify
# Step 5 - Push our generated site to Cloudflare
- name: Deploy to Cloudflare Pages
id: deploy
uses: cloudflare/wrangler-action@v3
# Step 5 - Push our generated site to Vercel
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
id: vercel-action
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy ./docSite/public --project-name=fastgpt-doc
packageManager: npm
- name: Create deployment status comment
if: always()
vercel-token: ${{ secrets.VERCEL_TOKEN }} # Required
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} #Required
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} #Required
github-comment: false
vercel-args: '--local-config ../vercel.json' # Optional
working-directory: docSite/public
alias-domains: | #Optional
fastgpt-staging.vercel.app
docsOutput:
needs: [deploy-preview]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Write md
run: |
echo "# 🤖 Generated by deploy action" > report.md
echo "[👀 Visit Preview](${{ needs.deploy-preview.outputs.url }})" >> report.md
cat report.md
- name: Gh Rebot for Sealos
uses: labring/gh-rebot@v0.0.6
if: ${{ (github.event_name == 'pull_request_target') }}
with:
version: v0.0.6
env:
JOB_STATUS: ${{ job.status }}
PREVIEW_URL: ${{ steps.deploy.outputs.deployment-url }}
uses: actions/github-script@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
script: |
const success = process.env.JOB_STATUS === 'success';
const deploymentUrl = `${process.env.PREVIEW_URL}`;
const status = success ? '✅ Success' : '❌ Failed';
console.log(process.env.JOB_STATUS);
const commentBody = `**Deployment Status: ${status}**
${success ? `🔗 Preview URL: ${deploymentUrl}` : ''}`;
await github.rest.issues.createComment({
...context.repo,
issue_number: context.payload.pull_request.number,
body: commentBody
});
GH_TOKEN: '${{ secrets.GH_PAT }}'
SEALOS_TYPE: 'pr_comment'
SEALOS_FILENAME: 'report.md'
SEALOS_REPLACE_TAG: 'DEFAULT_REPLACE_DEPLOY'

View File

@@ -1,6 +1,6 @@
name: Sync images
on:
pull_request:
pull_request_target:
branches:
- main
paths:
@@ -15,6 +15,13 @@ jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
if: ${{ (github.event_name == 'pull_request_target') }}
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Checkout
uses: actions/checkout@v3
@@ -25,4 +32,4 @@ jobs:
CONFIG_PATH: .github/sync_imgs.yml
ORIGINAL_MESSAGE: true
SKIP_PR: true
COMMIT_EACH_FILE: false
COMMIT_EACH_FILE: false

View File

@@ -9,11 +9,6 @@ on:
- 'main'
jobs:
build-fastgpt-images:
permissions:
packages: write
contents: read
attestations: write
id-token: write
runs-on: ubuntu-20.04
if: github.repository != 'labring/FastGPT'
steps:
@@ -37,7 +32,7 @@ jobs:
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ secrets.GH_PAT }}
- name: Set DOCKER_REPO_TAGGED based on branch or tag
run: |
echo "DOCKER_REPO_TAGGED=ghcr.io/${{ github.repository_owner }}/fastgpt:latest" >> $GITHUB_ENV

View File

@@ -9,11 +9,6 @@ on:
- 'v*'
jobs:
build-fastgpt-images:
permissions:
packages: write
contents: read
attestations: write
id-token: write
runs-on: ubuntu-20.04
steps:
# install env
@@ -44,7 +39,7 @@ jobs:
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ secrets.GH_PAT }}
- name: Login to Ali Hub
uses: docker/login-action@v2
with:
@@ -96,11 +91,6 @@ jobs:
-t ${Docker_Hub_Latest} \
.
build-fastgpt-images-sub-route:
permissions:
packages: write
contents: read
attestations: write
id-token: write
runs-on: ubuntu-20.04
steps:
# install env
@@ -131,7 +121,7 @@ jobs:
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ secrets.GH_PAT }}
- name: Login to Ali Hub
uses: docker/login-action@v2
with:
@@ -184,11 +174,6 @@ jobs:
-t ${Docker_Hub_Latest} \
.
build-fastgpt-images-sub-route-gchat:
permissions:
packages: write
contents: read
attestations: write
id-token: write
runs-on: ubuntu-20.04
steps:
# install env
@@ -219,7 +204,7 @@ jobs:
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ secrets.GH_PAT }}
- name: Login to Ali Hub
uses: docker/login-action@v2
with:

View File

@@ -5,13 +5,6 @@ on:
jobs:
preview-fastgpt-images:
permissions:
contents: read
packages: write
attestations: write
id-token: write
pull-requests: write
runs-on: ubuntu-20.04
steps:
- name: Checkout
@@ -19,9 +12,8 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
submodules: recursive # Fetch submodules
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
@@ -33,18 +25,15 @@ jobs:
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ secrets.GH_PAT }}
- name: Set DOCKER_REPO_TAGGED based on branch or tag
run: |
echo "DOCKER_REPO_TAGGED=ghcr.io/${{ github.repository_owner }}/fastgpt-pr:${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV
- name: Build image for PR
env:
DOCKER_REPO_TAGGED: ${{ env.DOCKER_REPO_TAGGED }}
@@ -59,13 +48,20 @@ jobs:
--cache-to=type=local,dest=/tmp/.buildx-cache \
-t ${DOCKER_REPO_TAGGED} \
.
- uses: actions/github-script@v7
# Add write md step after build
- name: Write md
run: |
echo "# 🤖 Generated by deploy action" > report.md
echo "📦 Preview Image: \`${DOCKER_REPO_TAGGED}\`" >> report.md
cat report.md
- name: Gh Rebot for Sealos
uses: labring/gh-rebot@v0.0.6
if: ${{ (github.event_name == 'pull_request_target') }}
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Preview Image: `${{ env.DOCKER_REPO_TAGGED }}`'
})
version: v0.0.6
env:
GH_TOKEN: '${{ secrets.GH_PAT }}'
SEALOS_TYPE: 'pr_comment'
SEALOS_FILENAME: 'report.md'
SEALOS_REPLACE_TAG: 'DEFAULT_REPLACE_DEPLOY'

View File

@@ -8,11 +8,6 @@ on:
jobs:
helm:
permissions:
packages: write
contents: read
attestations: write
id-token: write
runs-on: ubuntu-20.04
steps:
- name: Checkout
@@ -25,7 +20,7 @@ jobs:
run: echo "tag=$(git describe --tags)" >> $GITHUB_OUTPUT
- name: Release Helm
run: |
echo ${{ secrets.GITHUB_TOKEN }} | helm registry login ghcr.io -u ${{ github.repository_owner }} --password-stdin
echo ${{ secrets.GH_PAT }} | helm registry login ghcr.io -u ${{ github.repository_owner }} --password-stdin
export APP_VERSION=${{ steps.vars.outputs.tag }}
export HELM_VERSION=${{ steps.vars.outputs.tag }}
export HELM_REPO=ghcr.io/${{ github.repository_owner }}

View File

@@ -8,11 +8,6 @@ on:
- 'v*'
jobs:
build-fastgpt-sandbox-images:
permissions:
packages: write
contents: read
attestations: write
id-token: write
runs-on: ubuntu-20.04
steps:
# install env
@@ -43,7 +38,7 @@ jobs:
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ secrets.GH_PAT }}
- name: Login to Ali Hub
uses: docker/login-action@v2
with:

39
.vscode/launch.json vendored
View File

@@ -1,39 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Next.js: debug server-side",
"type": "node-terminal",
"request": "launch",
"command": "pnpm run dev",
"cwd": "${workspaceFolder}/projects/app"
},
{
"name": "Next.js: debug client-side",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000"
},
{
"name": "Next.js: debug client-side (Edge)",
"type": "msedge",
"request": "launch",
"url": "http://localhost:3000"
},
{
"name": "Next.js: debug full stack",
"type": "node-terminal",
"request": "launch",
"command": "pnpm run dev",
"cwd": "${workspaceFolder}/projects/app",
"skipFiles": ["<node_internals>/**"],
"serverReadyAction": {
"action": "debugWithEdge",
"killOnServerStop": true,
"pattern": "- Local:.+(https?://.+)",
"uriFormat": "%s",
"webRoot": "${workspaceFolder}/projects/app"
}
}
]
}

View File

@@ -110,31 +110,19 @@ services:
# 等待docker-entrypoint.sh脚本执行的MongoDB服务进程
wait $$!
redis:
image: redis:7.2-alpine
container_name: redis
# ports:
# - 6379:6379
networks:
- fastgpt
restart: always
command: |
redis-server --requirepass mypassword --loglevel warning --maxclients 10000 --appendonly yes --save 60 10 --maxmemory 4gb --maxmemory-policy noeviction
volumes:
- ./redis/data:/data
# fastgpt
sandbox:
container_name: sandbox
image: ghcr.io/labring/fastgpt-sandbox:v4.9.3 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.3 # 阿里云
image: ghcr.io/labring/fastgpt-sandbox:v4.9.1-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.1-fix2 # 阿里云
networks:
- fastgpt
restart: always
fastgpt:
container_name: fastgpt
image: ghcr.io/labring/fastgpt:v4.9.3 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.3 # 阿里云
image: ghcr.io/labring/fastgpt:v4.9.1-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.1-fix2 # 阿里云
ports:
- 3000:3000
networks:
@@ -169,8 +157,6 @@ services:
# zilliz 连接参数
- MILVUS_ADDRESS=http://milvusStandalone:19530
- MILVUS_TOKEN=none
# Redis 地址
- REDIS_URL=redis://default:mypassword@redis:6379
# sandbox 地址
- SANDBOX_URL=http://sandbox:3000
# 日志等级: debug, info, warn, error

View File

@@ -69,31 +69,18 @@ services:
# 等待docker-entrypoint.sh脚本执行的MongoDB服务进程
wait $$!
redis:
image: redis:7.2-alpine
container_name: redis
# ports:
# - 6379:6379
networks:
- fastgpt
restart: always
command: |
redis-server --requirepass mypassword --loglevel warning --maxclients 10000 --appendonly yes --save 60 10 --maxmemory 4gb --maxmemory-policy noeviction
volumes:
- ./redis/data:/data
# fastgpt
sandbox:
container_name: sandbox
image: ghcr.io/labring/fastgpt-sandbox:v4.9.3 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.3 # 阿里云
image: ghcr.io/labring/fastgpt-sandbox:v4.9.1-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.1-fix2 # 阿里云
networks:
- fastgpt
restart: always
fastgpt:
container_name: fastgpt
image: ghcr.io/labring/fastgpt:v4.9.3 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.3 # 阿里云
image: ghcr.io/labring/fastgpt:v4.9.1-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.1-fix2 # 阿里云
ports:
- 3000:3000
networks:
@@ -127,8 +114,6 @@ services:
- MONGODB_URI=mongodb://myusername:mypassword@mongo:27017/fastgpt?authSource=admin
# pg 连接参数
- PG_URL=postgresql://username:password@pg:5432/postgres
# Redis 连接参数
- REDIS_URL=redis://default:mypassword@redis:6379
# sandbox 地址
- SANDBOX_URL=http://sandbox:3000
# 日志等级: debug, info, warn, error
@@ -147,7 +132,7 @@ services:
# AI Proxy
aiproxy:
image: ghcr.io/labring/aiproxy:v0.1.5
image: ghcr.io/labring/aiproxy:v0.1.3
# image: registry.cn-hangzhou.aliyuncs.com/labring/aiproxy:v0.1.3 # 阿里云
container_name: aiproxy
restart: unless-stopped

View File

@@ -51,30 +51,17 @@ services:
# 等待docker-entrypoint.sh脚本执行的MongoDB服务进程
wait $$!
redis:
image: redis:7.2-alpine
container_name: redis
# ports:
# - 6379:6379
networks:
- fastgpt
restart: always
command: |
redis-server --requirepass mypassword --loglevel warning --maxclients 10000 --appendonly yes --save 60 10 --maxmemory 4gb --maxmemory-policy noeviction
volumes:
- ./redis/data:/data
sandbox:
container_name: sandbox
image: ghcr.io/labring/fastgpt-sandbox:v4.9.3 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.3 # 阿里云
image: ghcr.io/labring/fastgpt-sandbox:v4.9.1-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.1-fix2 # 阿里云
networks:
- fastgpt
restart: always
fastgpt:
container_name: fastgpt
image: ghcr.io/labring/fastgpt:v4.9.3 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.3 # 阿里云
image: ghcr.io/labring/fastgpt:v4.9.1-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.1-fix2 # 阿里云
ports:
- 3000:3000
networks:
@@ -105,8 +92,6 @@ services:
- FILE_TOKEN_KEY=filetoken
# MongoDB 连接参数. 用户名myusername,密码mypassword。
- MONGODB_URI=mongodb://myusername:mypassword@mongo:27017/fastgpt?authSource=admin
# Redis 连接参数
- REDIS_URI=redis://default:mypassword@redis:6379
# zilliz 连接参数
- MILVUS_ADDRESS=zilliz_cloud_address
- MILVUS_TOKEN=zilliz_cloud_token

View File

@@ -7,7 +7,7 @@ data:
"vectorMaxProcess": 15,
"qaMaxProcess": 15,
"vlmMaxProcess": 15,
"hnswEfSearch": 100
"pgHNSWEfSearch": 100
},
"llmModels": [
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

View File

@@ -25,7 +25,7 @@ weight: 707
"qaMaxProcess": 15, // 问答拆分线程数量
"vlmMaxProcess": 15, // 图片理解模型最大处理进程
"tokenWorkers": 50, // Token 计算线程保持数,会持续占用内存,不能设置太大。
"hnswEfSearch": 100, // 向量搜索参数,仅对 PG 和 OB 生效。越大搜索越精确但是速度越慢。设置为100有99%+精度。
"pgHNSWEfSearch": 100, // 向量搜索参数。越大搜索越精确但是速度越慢。设置为100有99%+精度。
"customPdfParse": { // 4.9.0 新增配置
"url": "", // 自定义 PDF 解析服务地址
"key": "", // 自定义 PDF 解析服务密钥

View File

@@ -31,9 +31,9 @@ weight: 920
3 个模型代码分别为:
1. [https://github.com/labring/FastGPT/tree/main/plugins/model/rerank-bge/bge-reranker-base](https://github.com/labring/FastGPT/tree/main/plugins/model/rerank-bge/bge-reranker-base)
2. [https://github.com/labring/FastGPT/tree/main/plugins/model/rerank-bge/bge-reranker-large](https://github.com/labring/FastGPT/tree/main/plugins/model/rerank-bge/bge-reranker-large)
3. [https://github.com/labring/FastGPT/tree/main/plugins/model/rerank-bge/bge-reranker-v2-m3](https://github.com/labring/FastGPT/tree/main/plugins/model/rerank-bge/bge-reranker-v2-m3)
1. [https://github.com/labring/FastGPT/tree/main/plugins/rerank-bge/bge-reranker-base](https://github.com/labring/FastGPT/tree/main/plugins/rerank-bge/bge-reranker-base)
2. [https://github.com/labring/FastGPT/tree/main/plugins/rerank-bge/bge-reranker-large](https://github.com/labring/FastGPT/tree/main/plugins/rerank-bge/bge-reranker-large)
3. [https://github.com/labring/FastGPT/tree/main/plugins/rerank-bge/bge-reranker-v2-m3](https://github.com/labring/FastGPT/tree/main/plugins/rerank-bge/bge-reranker-v2-m3)
### 3. 安装依赖

View File

@@ -46,7 +46,7 @@ ChatGLM2-6B 是开源中英双语对话模型 ChatGLM-6B 的第二代版本,
### 源码部署
1. 根据上面的环境配置配置好环境,具体教程自行 GPT
2. 下载 [python 文件](https://github.com/labring/FastGPT/blob/main/plugins/model/llm-ChatGLM2/openai_api.py)
2. 下载 [python 文件](https://github.com/labring/FastGPT/blob/main/files/models/ChatGLM2/openai_api.py)
3. 在命令行输入命令 `pip install -r requirements.txt`
4. 打开你需要启动的 py 文件,在代码的 `verify_token` 方法中配置 token这里的 token 只是加一层验证,防止接口被人盗用;
5. 执行命令 `python openai_api.py --model_name 16`。这里的数字根据上面的配置进行选择。

View File

@@ -71,7 +71,7 @@ Mongo 数据库需要注意,需要注意在连接地址中增加 `directConnec
- `vectorMaxProcess`: 向量生成最大进程,根据数据库和 key 的并发数来决定,通常单个 120 号2c4g 服务器设置 10~15。
- `qaMaxProcess`: QA 生成最大进程
- `vlmMaxProcess`: 图片理解模型最大进程
- `hnswEfSearch`: 向量搜索参数,仅对 PG 和 OB 生效,越大搜索精度越高但是速度越慢
- `pgHNSWEfSearch`: PostgreSQL vector 索引参数,越大搜索精度越高但是速度越慢,具体可看 pgvector 官方说明
### 5. 运行

View File

@@ -302,7 +302,7 @@ OneAPI 的语言识别接口,无法正确的识别其他模型(会始终识
"vectorMaxProcess": 15, // 向量处理线程数量
"qaMaxProcess": 15, // 问答拆分线程数量
"tokenWorkers": 50, // Token 计算线程保持数,会持续占用内存,不能设置太大。
"hnswEfSearch": 100 // 向量搜索参数,仅对 PG 和 OB 生效。越大搜索越精确但是速度越慢。设置为100有99%+精度。
"pgHNSWEfSearch": 100 // 向量搜索参数。越大搜索越精确但是速度越慢。设置为100有99%+精度。
},
"llmModels": [
{

View File

@@ -18,14 +18,12 @@ weight: 852
{{% alert icon="🤖 " context="success" %}}
* 该接口的 API Key 需使用`应用特定的 key`,否则会报错。
<!-- * 对话现在有`v1``v2`两个接口可以按需使用v2 自 4.9.4 版本新增v1 接口同时不再维护 -->
* 有些包调用时,`BaseUrl`需要添加`v1`路径有些不需要如果出现404情况可补充`v1`重试。
{{% /alert %}}
## 请求简易应用和工作流
`v1`对话接口兼容`GPT`的接口!如果你的项目使用的是标准的`GPT`官方接口,可以直接通过修改`BaseUrl``Authorization`来访问 FastGpt 应用,不过需要注意下面几个规则:
对话接口兼容`GPT`的接口!如果你的项目使用的是标准的`GPT`官方接口,可以直接通过修改`BaseUrl``Authorization`来访问 FastGpt 应用,不过需要注意下面几个规则:
{{% alert icon="🤖 " context="success" %}}
* 传入的`model``temperature`等参数字段均无效,这些字段由编排决定,不会根据 API 参数改变。
@@ -67,7 +65,7 @@ curl --location --request POST 'http://localhost:3000/api/v1/chat/completions' \
{{< markdownify >}}
*`messages`有部分区别,其他参数一致。
* 目前不支持上文件,需上传到自己的对象存储中,获取对应的文件链接。
* 目前不支持上文件,需上传到自己的对象存储中,获取对应的文件链接。
```bash
curl --location --request POST 'http://localhost:3000/api/v1/chat/completions' \
@@ -118,284 +116,14 @@ curl --location --request POST 'http://localhost:3000/api/v1/chat/completions' \
- variables: 模块变量,一个对象,会替换模块中,输入框内容里的`{{key}}`
{{% /alert %}}
{{< /markdownify >}}
{{< /tab >}}
{{< /tabs >}}
<!-- #### v2
v1,v2 接口请求参数一致,仅请求地址不一样。
{{< tabs tabTotal="3" >}}
{{< tab tabName="基础请求示例" >}}
{{< markdownify >}}
```bash
curl --location --request POST 'http://localhost:3000/api/v2/chat/completions' \
--header 'Authorization: fastgpt-xxxxxx' \
--header 'Content-Type: application/json' \
--data-raw '{
"chatId": "my_chatId",
"stream": false,
"detail": false,
"responseChatItemId": "my_responseChatItemId",
"variables": {
"uid": "asdfadsfasfd2323",
"name": "张三"
},
"messages": [
{
"role": "user",
"content": "你是谁"
}
]
}'
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="图片/文件请求示例" >}}
{{< markdownify >}}
*`messages`有部分区别,其他参数一致。
* 目前不支持上传文件,需上传到自己的对象存储中,获取对应的文件链接。
```bash
curl --location --request POST 'http://localhost:3000/api/v2/chat/completions' \
--header 'Authorization: Bearer fastgpt-xxxxxx' \
--header 'Content-Type: application/json' \
--data-raw '{
"chatId": "abcd",
"stream": false,
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "导演是谁"
},
{
"type": "image_url",
"image_url": {
"url": "图片链接"
}
},
{
"type": "file_url",
"name": "文件名",
"url": "文档链接,支持 txt md html word pdf ppt csv excel"
}
]
}
]
}'
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="参数说明" >}}
{{< markdownify >}}
{{% alert context="info" %}}
- headers.Authorization: Bearer {{apikey}}
- chatId: string | undefined 。
-`undefined` 时(不传入),不使用 FastGpt 提供的上下文功能,完全通过传入的 messages 构建上下文。
-`非空字符串`时,意味着使用 chatId 进行对话,自动从 FastGpt 数据库取历史记录,并使用 messages 数组最后一个内容作为用户问题,其余 message 会被忽略。请自行确保 chatId 唯一长度小于250通常可以是自己系统的对话框ID。
- messages: 结构与 [GPT接口](https://platform.openai.com/docs/api-reference/chat/object) chat模式一致。
- responseChatItemId: string | undefined 。如果传入,则会将该值作为本次对话的响应消息的 IDFastGPT 会自动将该 ID 存入数据库。请确保,在当前`chatId`下,`responseChatItemId`是唯一的。
- detail: 是否返回中间值(模块状态,响应的完整结果等),`stream模式`下会通过`event`进行区分,`非stream模式`结果保存在`responseData`中。
- variables: 模块变量,一个对象,会替换模块中,输入框内容里的`{{key}}`
{{% /alert %}}
{{< /markdownify >}}
{{< /tab >}}
{{< /tabs >}}
#### v1
### 响应
#### v2
v2 接口比起 v1主要变变化在于会在每个节点运行结束后及时返回 response而不是等工作流结束后再统一返回。
{{< tabs tabTotal="5" >}}
{{< tab tabName="detail=false,stream=false 响应" >}}
{{< markdownify >}}
```json
{
"id": "",
"model": "",
"usage": {
"prompt_tokens": 1,
"completion_tokens": 1,
"total_tokens": 1
},
"choices": [
{
"message": {
"role": "assistant",
"content": "我是一个人工智能助手,旨在回答问题和提供信息。如果你有任何问题或者需要帮助,随时问我!"
},
"finish_reason": "stop",
"index": 0
}
]
}
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="detail=false,stream=true 响应" >}}
{{< markdownify >}}
```bash
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"你好"},"index":0,"finish_reason":null}]}
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":""},"index":0,"finish_reason":null}]}
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"今天"},"index":0,"finish_reason":null}]}
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"过得怎么样?"},"index":0,"finish_reason":null}]}
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":null},"index":0,"finish_reason":"stop"}]}
data: [DONE]
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="detail=true,stream=false 响应" >}}
{{< markdownify >}}
```json
{
"responseData": [
{
"id": "iSol79OFrBH1I9kC",
"nodeId": "448745",
"moduleName": "common:core.module.template.work_start",
"moduleType": "workflowStart",
"runningTime": 0
},
{
"id": "t1T94WCy6Su3BK4V",
"nodeId": "fjLpE3XPegmoGtbU",
"moduleName": "AI 对话",
"moduleType": "chatNode",
"runningTime": 1.46,
"totalPoints": 0,
"model": "GPT-4o-mini",
"tokens": 64,
"inputTokens": 10,
"outputTokens": 54,
"query": "你是谁",
"reasoningText": "",
"historyPreview": [
{
"obj": "Human",
"value": "你是谁"
},
{
"obj": "AI",
"value": "我是一个人工智能助手,旨在帮助回答问题和提供信息。如果你有任何问题或需要帮助,请告诉我!"
}
],
"contextTotalLen": 2
}
],
"newVariables": {
},
"id": "",
"model": "",
"usage": {
"prompt_tokens": 1,
"completion_tokens": 1,
"total_tokens": 1
},
"choices": [
{
"message": {
"role": "assistant",
"content": "我是一个人工智能助手,旨在帮助回答问题和提供信息。如果你有任何问题或需要帮助,请告诉我!"
},
"finish_reason": "stop",
"index": 0
}
]
}
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="detail=true,stream=true 响应" >}}
{{< markdownify >}}
```bash
event: flowNodeResponse
data: {"id":"iYv2uA9rCWAtulWo","nodeId":"workflowStartNodeId","moduleName":"流程开始","moduleType":"workflowStart","runningTime":0}
event: flowNodeStatus
data: {"status":"running","name":"AI 对话"}
event: answer
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"你好"},"index":0,"finish_reason":null}]}
event: answer
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":""},"index":0,"finish_reason":null}]}
event: answer
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"今天"},"index":0,"finish_reason":null}]}
event: answer
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"过得怎么样?"},"index":0,"finish_reason":null}]}
event: flowNodeResponse
data: {"id":"pVzLBF7M3Ol4n7s6","nodeId":"ixe20AHN3jy74pKf","moduleName":"AI 对话","moduleType":"chatNode","runningTime":1.48,"totalPoints":0.0042,"model":"Qwen-plus","tokens":28,"inputTokens":8,"outputTokens":20,"query":"你好","reasoningText":"","historyPreview":[{"obj":"Human","value":"你好"},{"obj":"AI","value":"你好!今天过得怎么样?"}],"contextTotalLen":2}
event: answer
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":null},"index":0,"finish_reason":"stop"}]}
event: answer
data: [DONE]
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="event值" >}}
{{< markdownify >}}
event取值
- answer: 返回给客户端的文本(最终会算作回答)
- fastAnswer: 指定回复返回给客户端的文本(最终会算作回答)
- toolCall: 执行工具
- toolParams: 工具参数
- toolResponse: 工具返回
- flowNodeStatus: 运行到的节点状态
- flowNodeResponse: 单个节点详细响应
- updateVariables: 更新变量
- error: 报错
{{< /markdownify >}}
{{< /tab >}}
{{< /tabs >}}
#### v1 -->
{{< tabs tabTotal="5" >}}
{{< tab tabName="detail=false,stream=false 响应" >}}
{{< markdownify >}}
@@ -920,6 +648,8 @@ event取值
{{< /tab >}}
{{< /tabs >}}
# 对话 CRUD
{{% alert icon="🤖 " context="success" %}}

View File

@@ -39,7 +39,7 @@ curl --location --request POST 'https://{{host}}/api/admin/initv491' \
3. API 知识库支持 PDF 增强解析。
4. 邀请团队成员,改为邀请链接模式。
5. 支持混合检索权重设置。
6. 支持重排模型选择和权重设置,同时调整了知识库搜索权重计算方式,改成 搜索权重 + 重排权重,而不是向量检索权重+全文检索权重+重排权重。会对检索结果有一定影响,可以通过调整相关权重来进行数据适配。
6. 支持重排模型选择和权重设置,同时调整了知识库搜索权重计算方式,改成 搜索权重 + 重排权重,而不是向量检索权重+全文检索权重+重排权重。
## ⚙️ 优化

View File

@@ -1,43 +1,17 @@
---
title: 'V4.9.2'
title: 'V4.9.2(进行中)'
description: 'FastGPT V4.9.2 更新说明'
icon: 'upgrade'
draft: false
toc: true
weight: 798
weight: 799
---
## 更新指南
可直接升级v4.9.3v4.9.2存在一个工作流数据类型转化错误。
### 1. 做好数据库备份
### 2. SSO 迁移
使用了 SSO 或成员同步的商业版用户,并且是对接`钉钉``企微`的,需要迁移已有的 SSO 相关配置:
参考:[SSO & 外部成员同步](/docs/guide/admin/sso)中的配置进行`sso-service`的部署和配置。
1. 先将原商业版后台中的相关配置项复制备份出来(以企微为例,将 AppId, Secret 等复制出来)再进行镜像升级。
2. 参考上述文档,部署 SSO 服务,配置相关的环境变量
3. 如果原先使用企微组织架构同步的用户,升级完镜像后,需要在商业版后台切换团队模式为“同步模式”
### 3. 配置参数变更
修改`config.json`文件中`systemEnv.pgHNSWEfSearch`参数名,改成`hnswEfSearch`
商业版用户升级镜像后,直接在后台`系统配置-基础配置`中进行变更。
### 4. 更新镜像
- 更新 FastGPT 镜像 tag: v4.9.2
- 更新 FastGPT 商业版镜像 tag: v4.9.2
- Sandbox 镜像,可以不更新
- AIProxy 镜像修改为: registry.cn-hangzhou.aliyuncs.com/labring/aiproxy:v0.1.4
## 重要更新
## 重要提示
- 知识库导入数据 API 变更,增加`chunkSettingMode`,`chunkSplitMode`,`indexSize`可选参数,具体可参考 [知识库导入数据 API](/docs/development/openapi/dataset) 文档。
## 🚀 新增内容
1. 知识库分块优化:支持单独配置分块大小和索引大小,允许进行超大分块,以更大的输入 Tokens 换取完整分块。
@@ -45,9 +19,6 @@ weight: 798
3. 外部变量改名:自定义变量。 并且支持在测试时调试,在分享链接中,该变量直接隐藏。
4. 集合同步时,支持同步修改标题。
5. 团队成员管理重构,抽离主流 IM SSO企微、飞书、钉钉并支持通过自定义 SSO 接入 FastGPT。同时完善与外部系统的成员同步。
6. 支持 `oceanbase` 向量数据库。填写环境变量`OCEANBASE_URL`即可。
7. 基于 mistral-ocr 的 PDF 解析示例。
8. 基于 miner-u 的 PDF 解析示例。
## ⚙️ 优化
@@ -59,9 +30,7 @@ weight: 798
6. 工作流节点数组字符串类型,自动适配 string 输入。
7. 工作流节点数组类型,自动进行 JSON parse 解析 string 输入。
8. AI proxy 日志优化,去除重试失败的日志,仅保留最后一份错误日志。
9. 个人信息和通知展示优化。
10. 模型测试 loading 动画优化。
11. 分块算法小调整:
9. 分块算法小调整:
* 跨处理符号之间连续性更强。
* 代码块分割时,用 LLM 模型上下文作为分块大小,尽可能保证代码块完整性。
* 表格分割时,用 LLM 模型上下文作为分块大小,尽可能保证表格完整性。

View File

@@ -1,29 +0,0 @@
---
title: 'V4.9.3'
description: 'FastGPT V4.9.3 更新说明'
icon: 'upgrade'
draft: false
toc: true
weight: 797
---
## 更新指南
### 1. 做好数据库备份
### 2. 更新镜像
- 更新 FastGPT 镜像 tag: v4.9.3
- 更新 FastGPT 商业版镜像 tag: v4.9.3
- Sandbox 镜像tag: v4.9.3
- AIProxy 镜像tag: v0.1.5
## 🚀 新增内容
1. 工作流 debug 模式支持交互节点。
2. 代码运行支持 Python3 代码。
## 🐛 修复
1. 工作流格式转化异常。

View File

@@ -1,66 +0,0 @@
---
title: 'V4.9.4(进行中)'
description: 'FastGPT V4.9.4 更新说明'
icon: 'upgrade'
draft: false
toc: true
weight: 796
---
## 升级指南
### 1. 做好数据备份
### 1. 安装 Redis
* docker 部署的用户,参考最新的 `docker-compose.yml` 文件增加 Redis 配置。增加一个 redis 容器,并配置`fastgpt`,`fastgpt-pro`的环境变量,增加 `REDIS_URL` 环境变量。
* Sealos 部署的用户,在数据库里新建一个`redis`数据库,并复制`内网地址的 connection` 作为 `redis` 的链接串。然后配置`fastgpt`,`fastgpt-pro`的环境变量,增加 `REDIS_URL` 环境变量。
| | | |
| --- | --- | --- |
| ![](/imgs/sealos-redis1.png) | ![](/imgs/sealos-redis2.png) | ![](/imgs/sealos-redis3.png) |
### 2. 更新镜像 tag
- 更新 FastGPT 镜像 tag: v4.9.4-alpha
- 更新 FastGPT 商业版镜像 tag: v4.9.4-alpha
- Sandbox 无需更新
- AIProxy 无需更新
### 3. 执行升级脚本
该脚本仅需商业版用户执行。
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`{{host}} 替换成**FastGPT 域名**。
```bash
curl --location --request POST 'https://{{host}}/api/admin/initv494' \
--header 'rootkey: {{rootkey}}' \
--header 'Content-Type: application/json'
```
**脚本功能**
1. 更新站点同步定时器
## 🚀 新增内容
1. 集合数据训练状态展示
2. SMTP 发送邮件插件
3. BullMQ 消息队列。
4. 利用 redis 进行部分数据缓存。
5. 站点同步支持配置训练参数。
6. AI 对话/工具调用,增加返回模型 finish_reason 字段。
7. 移动端语音输入交互调整
## ⚙️ 优化
1. Admin 模板渲染调整。
2. 支持环境变量配置对话文件过期时间。
3. MongoDB log 库可独立部署。
## 🐛 修复
1. 搜索应用/知识库时,无法点击目录进入下一层。
2. 重新训练时,参数未成功初始化。
3. package/service 部分请求在多 app 中不一致。

View File

@@ -1,88 +0,0 @@
---
title: '知识库引用分块阅读器'
description: 'FastGPT 分块阅读器功能介绍'
icon: 'description'
draft: false
toc: true
weight: 480
---
在企业 AI 应用落地过程中文档知识引用的精确性和透明度一直是用户关注的焦点。FastGPT 4.9.1 版本带来的知识库分块阅读器,巧妙解决了这一痛点,让 AI 引用不再是"黑盒"。
# 为什么需要分块阅读器?
传统的 AI 对话中,当模型引用企业知识库内容时,用户往往只能看到被引用的片段,无法获取完整语境,这给内容验证和深入理解带来了挑战。分块阅读器的出现,让用户可以在对话中直接查看引用内容的完整文档,并精确定位到引用位置,实现了引用的"可解释性"。
## 传统引用体验的局限
以往在知识库中上传文稿后,当我们在工作流中输入问题时,传统的引用方式只会展示引用到的分块,无法确认分块在文章中的上下文:
| 问题 | 引用 |
| --- | --- |
| ![](/imgs/chunkReader1.png) | ![](/imgs/chunkReader2.jpg) |
## FastGPT 分块阅读器:精准定位,无缝阅读
而在 FastGPT 全新的分块式阅读器中,同样的知识库内容和问题,呈现方式发生了质的飞跃
![](/imgs/chunkReader4.jpg)
当 AI 引用知识库内容时,用户只需点击引用链接,即可打开一个浮窗,呈现完整的原文内容,并通过醒目的高亮标记精确显示引用的文本片段。这既保证了回答的可溯源性,又提供了便捷的原文查阅体验。
# 核心功能
## 全文展示与定位
"分块阅读器" 让用户能直观查看AI回答引用的知识来源。
在对话界面中,当 AI 引用了知识库内容,系统会在回复下方展示出处信息。用户只需点击这些引用链接,即可打开一个优雅的浮窗,呈现完整的原文内容,并通过醒目的高亮标记精确显示 AI 引用的文本片段。
这一设计既保证了回答的可溯源性又提供了便捷的原文查阅体验让用户能轻松验证AI回答的准确性和相关上下文。
![](/imgs/chunkReader3.webp)
## 便捷引用导航
分块阅读器右上角设计了简洁实用的导航控制,用户可以通过这对按钮轻松在多个引用间切换浏览。导航区还直观显示当前查看的引用序号及总引用数量(如 "7/10"),帮助用户随时了解浏览进度和引用内容的整体规模。
![](imgs/chunkReader5.jpg)
## 引用质量评分
每条引用内容旁边都配有智能评分标签直观展示该引用在所有知识片段中的相关性排名。用户只需将鼠标悬停在评分标签上即可查看完整的评分详情了解这段引用内容为何被AI选中以及其相关性的具体构成。
![](imgs/chunkReader6.png)
## 文档内容一键导出
分块阅读器贴心配备了内容导出功能,让有效信息不再流失。只要用户拥有相应知识库的阅读权限,便可通过简单点击将引用涉及的全文直接保存到本地设备。
![](imgs/chunkReader7.jpg)
# 进阶特性
## 灵活的可见度控制
FastGPT提供灵活的引用可见度设置让知识共享既开放又安全。以免登录链接为例管理员可精确控制外部访问者能看到的信息范围。
当设置为"仅引用内容可见"时,外部用户点击引用链接将只能查看 AI 引用的特定文本片段,而非完整原文档。如图所示,分块阅读器此时智能调整显示模式,仅呈现相关引用内容。
| | |
| --- | --- |
| ![](/imgs/chunkReader8.png) | ![](/imgs/chunkReader9.jpg) |
## 即时标注优化
在浏览过程中,授权用户可以直接对引用内容进行即时标注和修正,系统会智能处理这些更新而不打断当前的对话体验。所有修改过的内容会通过醒目的"已更新"标签清晰标识,既保证了引用的准确性,又维持了对话历史的完整性。
这一无缝的知识优化流程特别适合团队协作场景让知识库能在实际使用过程中持续进化确保AI回答始终基于最新、最准确的信息源。
## 智能文档性能优化
面对现实业务中可能包含成千上万分块的超长文档FastGPT采用了先进的性能优化策略确保分块阅读器始终保持流畅响应。
系统根据引用相关性排序和数据库索引进行智能加载管理,实现了"按需渲染"机制——根据索引排序和数据库 id只有当用户实际需要查看的内容才会被加载到内存中。这意味着无论是快速跳转到特定引用还是自然滚动浏览文档都能获得丝滑的用户体验不会因为文档体积庞大而出现卡顿或延迟。
这一技术优化使FastGPT能够轻松应对企业级的大规模知识库场景让即使是包含海量信息的专业文档也能高效展示和查阅。

View File

@@ -1,581 +0,0 @@
---
title: 'SSO & 外部成员同步'
description: 'FastGPT 外部成员系统接入设计与配置'
icon: ''
draft: false
toc: true
weight: 707
---
如果你不需要用到 SSO/成员同步功能,或者是只需要用 Github、google、microsoft、公众号的快速登录可以跳过本章节。本章适合需要接入自己的成员系统或主流 办公IM 的用户。
## 介绍
为了方便地接入**外部成员系统**FastGPT 提供一套接入外部系统的**标准接口**,以及一个 FastGPT-SSO-Service 镜像作为**适配器**。
通过这套标注接口,你可以可以实现:
1. SSO 登录。从外部系统回调后,在 FastGPT 中创建一个用户。
2. 成员和组织架构同步(下面都简称成员同步)。
**原理**
FastGPT-pro 中有一套标准的SSO 和成员同步接口,系统会根据这套接口进行 SSO 和成员同步操作。
FastGPT-SSO-Service 是为了聚合不同来源的 SSO 和成员同步接口,将他们转成 fastgpt-pro 可识别的接口。
![](/imgs/sso2.png)
## 系统配置教程
### 1. 部署 SSO-service 镜像
使用 docker-compose 部署:
```yaml
fastgpt-sso:
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sso-service:v4.9.0
container_name: fastgpt-sso
restart: always
networks:
- fastgpt
environment:
- SSO_PROVIDER=example
- AUTH_TOKEN=xxxxx # 鉴权信息fastgpt-pro 会用到。
# 具体对接提供商的环境变量。
```
根据不同的提供商,你需要配置不同的环境变量,下面是内置的通用协议/IM
{{< table "table-hover table-striped-columns" >}}
| 协议/功能 | SSO | 成员同步支持 |
|----------------|----------|--------------|
| 飞书 | 是 | 是 |
| 企业微信 | 是 | 是 |
| 钉钉 | 是 | 否 |
| Saml2.0 | 是 | 否 |
| Oauth2.0 | 是 | 否 |
{{< /table >}}
### 2. 配置 fastgpt-pro
#### 1. 配置环境变量
环境变量中的 `EXTERNAL_USER_SYSTEM_BASE_URL` 为内网地址,例如上述例子中的配置,环境变量应该设置为
```yaml
env:
- EXTERNAL_USER_SYSTEM_BASE_URL=http://fastgpt-sso:3000
- EXTERNAL_USER_SYSTEM_AUTH_TOKEN=xxxxx
```
#### 2. 在商业版后台配置按钮文字,图标等。
{{< table "table-hover table-striped-columns" >}}
| <div style="text-align:center">企业微信</div> | <div style="text-align:center">钉钉</div> | <div style="text-align:center">飞书</div> |
|-----------|-----------------|--------------|
| ![企业微信](/imgs/sso15.png) | ![钉钉](/imgs/sso16.png) | ![飞书](/imgs/sso17.png) |
{{< /table >}}
#### 3. 开启成员同步(可选)
如果需要同步外部系统的成员,可以选择开启成员同步。团队模式具体可参考:[团队模式说明文档](/docs/guide/admin/teamMode)
![](/imgs/sso1.png)
#### 4. 可选配置
1. 自动定时成员同步
设置 fastgpt-pro 环境变量则可开启自动成员同步
```bash
env:
- "SYNC_MEMBER_CRON=0 0 * * *" # Cron 表达式,每天 0 点执行
```
## 内置的通用协议/IM 配置示例
### 飞书
#### 1. 参数获取
App ID和App Secret
进入开发者后台,点击企业自建应用,在凭证与基础信息页面查看应用凭证。
![](/imgs/sso3.png)
#### 2. 权限配置
进入开发者后台,点击企业自建应用,在开发配置的权限管理页面开通权限。
![](/imgs/sso4.png)
对于开通用户SSO登录而言开启用户身份权限的以下内容
1. ***获取通讯录基本信息***
2. ***获取用户基本信息***
3. ***获取用户邮箱信息***
4. ***获取用户 user ID***
对于开启企业同步相关内容而言,开启身份权限的内容与上面一致,但要注意是开启应用权限
#### 3. 重定向URL
进入开发者后台点击企业自建应用在开发配置的安全设置中设置重定向URL
![](/imgs/sso5.png)
#### 4. yml 配置示例
```bash
fastgpt-sso:
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sso-service:v4.9.0
container_name: fastgpt-sso
restart: always
networks:
- fastgpt
environment:
- SSO_PROVIDER=example
- AUTH_TOKEN=xxxxx
# 飞书 - feishu -如果是私有化部署,这里的配置前缀可能会有变化
- SSO_PROVIDER=feishu
# oauth 接口(公开的飞书不用改)
- SSO_TARGET_URL=https://accounts.feishu.cn/open-apis/authen/v1/authorize
# 获取token 接口(公开的飞书不用改)
- FEISHU_TOKEN_URL=https://open.feishu.cn/open-apis/authen/v2/oauth/token
# 获取用户信息接口(公开的飞书不用改)
- FEISHU_GET_USER_INFO_URL=https://open.feishu.cn/open-apis/authen/v1/user_info
# 重定向地址,因为飞书获取用户信息要校验所以需要填
- FEISHU_REDIRECT_URI=xxx
#飞书APP的应用ID一般以cli开头
- FEISHU_APP_ID=xxx
#飞书APP的应用密钥
- FEISHU_APP_SECRET=xxx
```
### 钉钉
#### 1. 参数获取
CLIENT_ID 与 CLIENT_SECRET
进入钉钉开放平台点击应用开发选择自己的应用进入记录在凭证与基础信息页面下的Client ID与Client secret。
![](/imgs/sso6.png)
#### 2. 权限配置
进入钉钉开放平台,点击应用开发,选择自己的应用进入,在开发配置的权限管理页面操作,需要开通的权限包括:
1. ***个人手机号信息***
2. ***通讯录个人信息读权限***
3. ***获取钉钉开放接口用户访问凭证的基础权限***
#### 3. 重定向URL
进入钉钉开放平台,点击应用开发,选择自己的应用进入,在开发配置的安全设置页面操作
需要填写的内容有两个:
1. 服务器出口IP 调用钉钉服务端API的服务器IP列表
2. 重定向URL回调域名
#### 4. yml 配置示例
```bash
fastgpt-sso:
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sso-service:v4.9.0
container_name: fastgpt-sso
restart: always
networks:
- fastgpt
environment:
- SSO_PROVIDER=dingtalk
- AUTH_TOKEN=xxxxx
#oauth 接口
- SSO_TARGET_URL=https://login.dingtalk.com/oauth2/auth
#获取token 接口
- DINGTALK_TOKEN_URL=https://api.dingtalk.com/v1.0/oauth2/userAccessToken
#获取用户信息接口
- DINGTALK_GET_USER_INFO_URL=https://oapi.dingtalk.com/v1.0/contact/users/me
#钉钉APP的应用ID
- DINGTALK_CLIENT_ID=xxx
#钉钉APP的应用密钥
- DINGTALK_CLIENT_SECRET=xxx
```
### 企业微信
#### 1. 参数获取
1. 企业的 CorpID
a. 使用管理员账号登陆企业微信管理后台 `https://work.weixin.qq.com/wework_admin/loginpage_wx`
b. 点击 【我的企业】 页面,查看企业的 **企业ID**
![](/imgs/sso7.png)
2. 创建一个供 FastGPT 使用的内部应用:
a. 获取应用的 AgentID 和 Secret
b. 保证这个应用的可见范围为全部(也就是根部门)
![](/imgs/sso8.png)
![](/imgs/sso9.png)
3. 一个域名。并且要求:
a. 解析到可公网访问的服务器上
b. 可以在该服务的根目录地址上挂载静态文件(以便进行域名归属认证 ,按照配置处的提示进行操作,只需要挂载一个静态文件,认证后可以删除)
c. 配置网页授权JS-SDK以及企业微信授权登陆
d. 可以在【企业微信授权登陆】页面下方设置“在工作台隐藏应用”
![](/imgs/sso10.png)
![](/imgs/sso11.png)
![](/imgs/sso12.png)
4. 获取 “通讯录同步助手” secret
获取通讯录,组织成员 ID 需要使用 “通讯录同步助手” secret
【安全与管理】-- 【管理工具】 -- 【通讯录同步】
![](/imgs/sso13.png)
5. 开启接口同步
6. 获取 Secret
7. 配置企业可信 IP
![](/imgs/sso14.png)
#### 2. yml 配置示例
```bash
fastgpt-sso:
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sso-service:v4.9.0
container_name: fastgpt-sso
restart: always
networks:
- fastgpt
environment:
- AUTH_TOKEN=xxxxx
- SSO_PROVIDER=wecom
# oauth 接口,在企微终端使用
- WECOM_TARGET_URL_OAUTH=https://open.weixin.qq.com/connect/oauth2/authorize
# sso 接口,扫码
- WECOM_TARGET_URL_SSO=https://login.work.weixin.qq.com/wwlogin/sso/login
# 获取用户id只能拿id)
- WECOM_GET_USER_ID_URL=https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo
# 获取用户详细信息(除了名字都有)
- WECOM_GET_USER_INFO_URL=https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail
# 获取用户信息(有名字,没其他信息)
- WECOM_GET_USER_NAME_URL=https://qyapi.weixin.qq.com/cgi-bin/user/get
# 获取组织 id 列表
- WECOM_GET_DEPARTMENT_LIST_URL=https://qyapi.weixin.qq.com/cgi-bin/department/list
# 获取用户 id 列表
- WECOM_GET_USER_LIST_URL=https://qyapi.weixin.qq.com/cgi-bin/user/list_id
# 企微 CorpId
- WECOM_CORPID=
# 企微 App 的 AgentId 一般是 1000xxx
- WECOM_AGENTID=
# 企微 App 的 Secret
- WECOM_APP_SECRET=
# 通讯录同步助手的 Secret
- WECOM_SYNC_SECRET=
```
### 标准 OAuth2.0
#### 参数需求
我们提供一套标准的 OAuth2.0 接入流程。需要三个地址:
1. 登陆鉴权地址(登陆后将 code 传入 redirect_uri
- 需要将地址完整写好,除了 redirect_uri 以外(会自动补全)
2. 获取 access_token 的地址,请求为 GET 方法,参数 code
```bash
http://example.com/oauth/access_token?code=xxxx
```
3. 获取用户信息的地址
```bash
http://example.com/oauth/user_info
```
#### 配置示例
```bash
fastgpt-sso:
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sso-service:v4.9.0
container_name: fastgpt-sso
restart: always
networks:
- fastgpt
environment:
# OAuth2.0
- AUTH_TOKEN=xxxxx
- SSO_PROVIDER=oauth2
# OAuth2 重定向地址
- OAUTH2_AUTHORIZE_URL=
# OAuth2 获取 AccessToken 地址
- OAUTH2_TOKEN_URL=
# OAuth2 获取用户信息地址
- OAUTH2_USER_INFO_URL=
# OAuth2 用户名字段映射(必填)
- OAUTH2_USERNAME_MAP=
# OAuth2 头像字段映射(选填)
- OAUTH2_AVATAR_MAP=
# OAuth2 成员名字段映射(选填)
- OAUTH2_MEMBER_NAME_MAP=
# OAuth2 联系方式字段映射(选填)
- OAUTH2_CONTACT_MAP=
```
## 标准接口文档
以下是 FastGPT-pro 中SSO 和成员同步的标准接口文档,如果需要对接非标准系统,可以参考该章节进行开发。
![](/imgs/sso18.png)
FastGPT 提供如下标准接口支持:
1. https://example.com/login/oauth/getAuthURL 获取鉴权重定向地址
2. https://example.com/login/oauth/getUserInfo?code=xxxxx 消费 code换取用户信息
3. https://example.com/org/list 获取组织列表
4. https://example.com/user/list 获取成员列表
### 获取 SSO 登录重定向地址
返回一个重定向登录地址fastgpt 会自动重定向到该地址。redirect_uri 会自动拼接到该地址的 query中。
{{< tabs tabTotal="2" >}}
{{< tab tabName="请求示例" >}}
{{< markdownify >}}
```bash
curl -X GET "https://redict.example/login/oauth/getAuthURL?redirect_uri=xxx&state=xxxx" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json"
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="响应示例" >}}
{{< markdownify >}}
成功:
```JSON
{
"success": true,
"message": "",
"authURL": "https://example.com/somepath/login/oauth?redirect_uri=https%3A%2F%2Ffastgpt.cn%2Flogin%2Fprovider%0A"
}
```
失败:
```JSON
{
"success": false,
"message": "错误信息",
"authURL": ""
}
```
{{< /markdownify >}}
{{< /tab >}}
{{< /tabs >}}
### SSO 获取用户信息
该接口接受一个 code 参数作为鉴权,消费 code 返回用户信息。
{{< tabs tabTotal="2" >}}
{{< tab tabName="请求示例" >}}
{{< markdownify >}}
```bash
curl -X GET "https://oauth.example/login/oauth/getUserInfo?code=xxxxxx" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json"
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="响应示例" >}}
{{< markdownify >}}
成功:
```JSON
{
"success": true,
"message": "",
"username": "fastgpt-123456789",
"avatar": "https://example.webp",
"contact": "+861234567890",
"memberName": "成员名(非必填)",
}
```
失败:
```JSON
{
"success": false,
"message": "错误信息",
"username": "",
"avatar": "",
"contact": ""
}
```
{{< /markdownify >}}
{{< /tab >}}
{{< /tabs >}}
### 获取组织
{{< tabs tabTotal="2" >}}
{{< tab tabName="请求示例" >}}
{{< markdownify >}}
```bash
curl -X GET "https://example.com/org/list" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json"
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="响应示例" >}}
{{< markdownify >}}
⚠️注意:只能存在一个根部门。如果你的系统中存在多个根部门,需要先进行处理,加一个虚拟的根部门。返回值类型:
```ts
type OrgListResponseType = {
message?: string; // 报错信息
success: boolean;
orgList: {
id: string; // 部门的唯一 id
name: string; // 名字
parentId: string; // parentId如果为根部门传空字符串。
}[];
}
```
```JSON
{
"success": true,
"message": "",
"orgList": [
{
"id": "od-125151515",
"name": "根部门",
"parentId": ""
},
{
"id": "od-51516152",
"name": "子部门",
"parentId": "od-125151515"
}
]
}
```
{{< /markdownify >}}
{{< /tab >}}
{{< /tabs >}}
### 获取成员
{{< tabs tabTotal="2" >}}
{{< tab tabName="请求示例" >}}
{{< markdownify >}}
```bash
curl -X GET "https://example.com/user/list" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json"
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="响应示例" >}}
{{< markdownify >}}
返回值类型:
```typescript
type UserListResponseListType = {
message?: string; // 报错信息
success: boolean;
userList: {
username: string; // 唯一 id username 必须与 SSO 接口返回的用户 username 相同。并且必须携带一个前缀,例如: sync-aaaaa和 sso 接口返回的前缀一致
memberName?: string; // 名字,作为 tmbname
avatar?: string;
contact?: string; // email or phone number
orgs?: string[]; // 人员所在组织的 ID。没有组织传 []
}[];
}
```
curl示例
```JSON
{
"success": true,
"message": "",
"userList": [
{
"username": "fastgpt-123456789",
"memberName": "张三",
"avatar": "https://example.webp",
"contact": "+861234567890",
"orgs": ["od-125151515", "od-51516152"]
},
{
"username": "fastgpt-12345678999",
"memberName": "李四",
"avatar": "",
"contact": "",
"orgs": ["od-125151515"]
}
]
}
```
{{< /markdownify >}}
{{< /tab >}}
{{< /tabs >}}
## 如何对接非标准系统
1. 客户自己开发:按 fastgpt 提供的标准接口进行开发,并将部署后的服务地址填入 fastgpt-pro
可以参考该模版库:[fastgpt-sso-template](https://github.com/labring/fastgpt-sso-template) 进行开发
2. 由 fastgpt 团队定制开发:
a. 提供系统的 SSO 文档、获取成员和组织的文档、以及外网测试地址。
b. 在 fastgpt-sso-service 中,增加对应的 provider 和环境变量,并编写代码来对接。

View File

@@ -0,0 +1,44 @@
---
weight: 490
title: '钉钉 SSO 配置'
description: '钉钉 SSO 登录'
icon: 'chat_bubble'
draft: false
images: []
---
## 1. 注册钉钉应用
登录 [钉钉开放平台](https://open-dev.dingtalk.com/fe/app?hash=%23%2Fcorp%2Fapp#/corp/app),创建一个应用。
![alt text](/imgs/image-25.png)
## 2. 配置钉钉应用安全设置
点击进入创建好的应用后,点开`安全设置`,配置出口 IP服务器 IP和重定向 URL。重定向 URL 填写逻辑:
`{{fastgpt 域名}}/login/provider`
![alt text](/imgs/image-26.png)
## 3. 设置钉钉应用权限
点击进入创建好的应用后,点开`权限设置`,开放两个权限: `个人手机号信息``通讯录个人信息读权限`
![alt text](/imgs/image-27.png)
## 4. 发布应用
点击进入创建好的应用后,点开`版本管理与发布`,随便创建一个新版本即可。
## 5. 在 FastGPT Admin 配置钉钉应用 id
名字都是对应上,直接填写即可。
| | |
| --- | --- |
| ![alt text](/imgs/image-28.png)| ![alt text](/imgs/image-29.png) |
## 6. 测试
![alt text](/imgs/image-30.png)

View File

@@ -1,81 +0,0 @@
---
title: '团队模式说明文档'
description: 'FastGPT 团队模式说明文档'
icon: ''
draft: false
toc: true
weight: 707
---
## 介绍
目前支持的团队模式:
1. 多团队模式(默认模式)
2. 单团队模式(全局只有一个团队)
3. 成员同步模式(所有成员自外部同步)
<table class="table-hover table-striped-columns" style="text-align: center;">
<tr>
<th rowspan="2">团队模式</th>
<th colspan="2">短信/邮箱 注册</th>
<th colspan="2">管理员直接添加</th>
<th colspan="2">SSO 注册</th>
</tr>
<tr>
<th>是否创建默认团队</th>
<th>是否加入 Root 团队</th>
<th>是否创建默认团队</th>
<th>是否加入 Root 团队</th>
<th>是否创建默认团队</th>
<th>是否加入 Root 团队</th>
</tr>
<tr>
<td>单团队模式</td>
<td>❌</td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td>多团队模式</td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td>同步模式</td>
<td>❌</td>
<td>❌</td>
<td>❌</td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
</tr>
</table>
### 多团队模式(默认模式)
多团队模式下,每个用户创建时默认创建以自己为所有者的默认团队。
### 单团队模式
单团队模式是 v4.9 推出的新功能。为了简化企业进行人员和资源的管理,开启单团队模式后,所有新增的用户都不再创建自己的默认团队,而是加入 root 用户所在的团队。
### 同步模式
在完成系统配置,开启同步模式的情况下,外部成员系统的成员会自动同步到 FastGPT 中。
具体的同步方式和规则请参考 [SSO & 外部成员同步](/docs/guide/admin/sso.md)。
## 配置
`fastgpt-pro``系统配置-成员配置`中,可以配置团队模式。
![](/imgs/teammode.png)

View File

@@ -7,7 +7,7 @@ toc: true
weight: -10
---
FastGPT 是一个AI Agent 构建平台,提供开箱即用的数据处理、模型调用等能力同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的应用场景!
FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的问答场景!
{{% alert icon="🤖 " context="success" %}}
FastGPT 在线使用:[https://tryfastgpt.ai](https://tryfastgpt.ai)

40
env.d.ts vendored
View File

@@ -1,40 +0,0 @@
declare global {
namespace NodeJS {
interface ProcessEnv {
LOG_DEPTH: string;
DEFAULT_ROOT_PSW: string;
DB_MAX_LINK: string;
TOKEN_KEY: string;
FILE_TOKEN_KEY: string;
ROOT_KEY: string;
OPENAI_BASE_URL: string;
CHAT_API_KEY: string;
AIPROXY_API_ENDPOINT: string;
AIPROXY_API_TOKEN: string;
MULTIPLE_DATA_TO_BASE64: string;
MONGODB_URI: string;
MONGODB_LOG_URI?: string;
PG_URL: string;
OCEANBASE_URL: string;
MILVUS_ADDRESS: string;
MILVUS_TOKEN: string;
SANDBOX_URL: string;
PRO_URL: string;
FE_DOMAIN: string;
FILE_DOMAIN: string;
NEXT_PUBLIC_BASE_URL: string;
LOG_LEVEL: string;
STORE_LOG_LEVEL: string;
USE_IP_LIMIT: string;
WORKFLOW_MAX_RUN_TIMES: string;
WORKFLOW_MAX_LOOP_TIMES: string;
CHECK_INTERNAL_IP: string;
CHAT_LOG_URL: string;
CHAT_LOG_INTERVAL: string;
CHAT_LOG_SOURCE_ID_PREFIX: string;
ALLOWED_ORIGINS: string;
}
}
}
export {};

View File

@@ -112,18 +112,17 @@ export type SystemEnvType = {
vectorMaxProcess: number;
qaMaxProcess: number;
vlmMaxProcess: number;
hnswEfSearch: number;
pgHNSWEfSearch: number;
tokenWorkers: number; // token count max worker
oneapiUrl?: string;
chatApiKey?: string;
customPdfParse?: customPdfParseType;
};
customPdfParse?: {
url?: string;
key?: string;
export type customPdfParseType = {
url?: string;
key?: string;
doc2xKey?: string;
price?: number;
doc2xKey?: string;
price?: number; // n points/1 page
};
};

View File

@@ -1,5 +1,3 @@
import { i18nT } from '../../../web/i18n/utils';
export enum ChatCompletionRequestMessageRoleEnum {
'System' = 'system',
'User' = 'user',
@@ -30,13 +28,3 @@ export enum EmbeddingTypeEnm {
query = 'query',
db = 'db'
}
export const completionFinishReasonMap = {
close: i18nT('chat:completion_finish_close'),
stop: i18nT('chat:completion_finish_stop'),
length: i18nT('chat:completion_finish_length'),
tool_calls: i18nT('chat:completion_finish_tool_calls'),
content_filter: i18nT('chat:completion_finish_content_filter'),
function_call: i18nT('chat:completion_finish_function_call'),
null: i18nT('chat:completion_finish_null')
};

View File

@@ -73,15 +73,6 @@ export type ChatCompletionMessageFunctionCall =
export type StreamChatType = Stream<openai.Chat.Completions.ChatCompletionChunk>;
export type UnStreamChatType = openai.Chat.Completions.ChatCompletion;
export type CompletionFinishReason =
| 'close'
| 'stop'
| 'length'
| 'tool_calls'
| 'content_filter'
| 'function_call'
| null;
export default openai;
export * from 'openai';

View File

@@ -15,6 +15,7 @@ export type DatasetUpdateBody = {
name?: string;
avatar?: string;
intro?: string;
status?: DatasetSchemaType['status'];
agentModel?: string;
vlmModel?: string;
@@ -25,7 +26,6 @@ export type DatasetUpdateBody = {
apiServer?: DatasetSchemaType['apiServer'];
yuqueServer?: DatasetSchemaType['yuqueServer'];
feishuServer?: DatasetSchemaType['feishuServer'];
chunkSettings?: DatasetSchemaType['chunkSettings'];
// sync schedule
autoSync?: boolean;
@@ -141,6 +141,7 @@ export type PushDatasetDataChunkProps = {
export type PostWebsiteSyncParams = {
datasetId: string;
billId: string;
};
export type PushDatasetDataProps = {

View File

@@ -50,9 +50,7 @@ export const DatasetTypeMap = {
export enum DatasetStatusEnum {
active = 'active',
syncing = 'syncing',
waiting = 'waiting',
error = 'error'
syncing = 'syncing'
}
export const DatasetStatusMap = {
[DatasetStatusEnum.active]: {
@@ -60,12 +58,6 @@ export const DatasetStatusMap = {
},
[DatasetStatusEnum.syncing]: {
label: i18nT('common:core.dataset.status.syncing')
},
[DatasetStatusEnum.waiting]: {
label: i18nT('common:core.dataset.status.waiting')
},
[DatasetStatusEnum.error]: {
label: i18nT('dataset:status_error')
}
};

View File

@@ -17,20 +17,6 @@ import { SourceMemberType } from 'support/user/type';
import { DatasetDataIndexTypeEnum } from './data/constants';
import { ChunkSettingModeEnum } from './constants';
export type ChunkSettingsType = {
trainingType: DatasetCollectionDataProcessModeEnum;
autoIndexes?: boolean;
imageIndex?: boolean;
chunkSettingMode?: ChunkSettingModeEnum;
chunkSplitMode?: DataChunkSplitModeEnum;
chunkSize?: number;
indexSize?: number;
chunkSplitter?: string;
qaPrompt?: string;
};
export type DatasetSchemaType = {
_id: string;
parentId?: string;
@@ -43,6 +29,7 @@ export type DatasetSchemaType = {
name: string;
intro: string;
type: `${DatasetTypeEnum}`;
status: `${DatasetStatusEnum}`;
vectorModel: string;
agentModel: string;
@@ -52,16 +39,14 @@ export type DatasetSchemaType = {
url: string;
selector: string;
};
chunkSettings?: ChunkSettingsType;
inheritPermission: boolean;
apiServer?: APIFileServer;
feishuServer?: FeishuServer;
yuqueServer?: YuqueServer;
// abandon
autoSync?: boolean;
// abandon
externalReadUrl?: string;
defaultPermission?: number;
};
@@ -178,7 +163,6 @@ export type DatasetTrainingSchemaType = {
weight: number;
indexes: Omit<DatasetDataIndexItemType, 'dataId'>[];
retryCount: number;
errorMsg?: string;
};
export type CollectionWithDatasetType = DatasetCollectionSchemaType & {
@@ -208,8 +192,6 @@ export type DatasetListItemType = {
};
export type DatasetItemType = Omit<DatasetSchemaType, 'vectorModel' | 'agentModel' | 'vlmModel'> & {
status: `${DatasetStatusEnum}`;
errorMsg?: string;
vectorModel: EmbeddingModelItemType;
agentModel: LLMModelItemType;
vlmModel?: LLMModelItemType;
@@ -234,7 +216,6 @@ export type DatasetCollectionItemType = CollectionWithDatasetType & {
file?: DatasetFileSchema;
permission: DatasetPermission;
indexAmount: number;
errorCount?: number;
};
/* ================= data ===================== */

View File

@@ -5,7 +5,6 @@ export enum SseResponseEventEnum {
answer = 'answer', // animation stream
fastAnswer = 'fastAnswer', // direct answer text, not animation
flowNodeStatus = 'flowNodeStatus', // update node status
flowNodeResponse = 'flowNodeResponse', // node response
toolCall = 'toolCall', // tool start
toolParams = 'toolParams', // tool params return

View File

@@ -22,7 +22,6 @@ import { UserSelectOptionType } from '../template/system/userSelect/type';
import { WorkflowResponseType } from '../../../../service/core/workflow/dispatch/type';
import { AiChatQuoteRoleType } from '../template/system/aiChat/type';
import { LafAccountType, OpenaiAccountType } from '../../../support/user/team/type';
import { CompletionFinishReason } from '../../ai/type';
export type ExternalProviderType = {
openaiAccount?: OpenaiAccountType;
@@ -41,7 +40,6 @@ export type ChatDispatchProps = {
id: string; // May be the id of the system plug-in (cannot be used directly to look up the table)
teamId: string;
tmbId: string; // App tmbId
isChildApp?: boolean;
};
runningUserInfo: {
teamId: string;
@@ -60,7 +58,6 @@ export type ChatDispatchProps = {
isToolCall?: boolean;
workflowStreamResponse?: WorkflowResponseType;
workflowDispatchDeep?: number;
version?: 'v1' | 'v2';
};
export type ModuleDispatchProps<T> = ChatDispatchProps & {
@@ -131,7 +128,6 @@ export type DispatchNodeResponseType = {
obj: `${ChatRoleEnum}`;
value: string;
}[]; // completion context array. history will slice
finishReason?: CompletionFinishReason;
// dataset search
similarity?: number;

View File

@@ -10,6 +10,7 @@ import { FlowNodeOutputItemType, ReferenceValueType } from '../type/io';
import { ChatItemType, NodeOutputItemType } from '../../../core/chat/type';
import { ChatItemValueTypeEnum, ChatRoleEnum } from '../../../core/chat/constants';
import { replaceVariable, valToStr } from '../../../common/string/tools';
import { ChatCompletionChunk } from 'openai/resources';
export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number => {
let limit = 10;
@@ -66,7 +67,7 @@ export const getLastInteractiveValue = (histories: ChatItemType[]) => {
};
export const initWorkflowEdgeStatus = (
edges: StoreEdgeItemType[] | RuntimeEdgeItemType[],
edges: StoreEdgeItemType[],
histories?: ChatItemType[]
): RuntimeEdgeItemType[] => {
// If there is a history, use the last interactive value

View File

@@ -5,36 +5,10 @@ import { FlowNodeInputTypeEnum } from 'core/workflow/node/constant';
import { WorkflowIOValueTypeEnum } from 'core/workflow/constants';
import type { ChatCompletionMessageParam } from '../../../../ai/type';
type InteractiveBasicType = {
entryNodeIds: string[];
memoryEdges: RuntimeEdgeItemType[];
nodeOutputs: NodeOutputItemType[];
toolParams?: {
entryNodeIds: string[]; // 记录工具中,交互节点的 Id而不是起始工作流的入口
memoryMessages: ChatCompletionMessageParam[]; // 这轮工具中,产生的新的 messages
toolCallId: string; // 记录对应 tool 的id用于后续交互节点可以替换掉 tool 的 response
};
};
type InteractiveNodeType = {
entryNodeIds?: string[];
memoryEdges?: RuntimeEdgeItemType[];
nodeOutputs?: NodeOutputItemType[];
};
export type UserSelectOptionItemType = {
key: string;
value: string;
};
type UserSelectInteractive = InteractiveNodeType & {
type: 'userSelect';
params: {
description: string;
userSelectOptions: UserSelectOptionItemType[];
userSelectedVal?: string;
};
};
export type UserInputFormItemType = {
type: FlowNodeInputTypeEnum;
@@ -54,7 +28,29 @@ export type UserInputFormItemType = {
// select
list?: { label: string; value: string }[];
};
type UserInputInteractive = InteractiveNodeType & {
type InteractiveBasicType = {
entryNodeIds: string[];
memoryEdges: RuntimeEdgeItemType[];
nodeOutputs: NodeOutputItemType[];
toolParams?: {
entryNodeIds: string[]; // 记录工具中,交互节点的 Id而不是起始工作流的入口
memoryMessages: ChatCompletionMessageParam[]; // 这轮工具中,产生的新的 messages
toolCallId: string; // 记录对应 tool 的id用于后续交互节点可以替换掉 tool 的 response
};
};
type UserSelectInteractive = {
type: 'userSelect';
params: {
description: string;
userSelectOptions: UserSelectOptionItemType[];
userSelectedVal?: string;
};
};
type UserInputInteractive = {
type: 'userInput';
params: {
description: string;
@@ -62,5 +58,6 @@ type UserInputInteractive = InteractiveNodeType & {
submitted?: boolean;
};
};
export type InteractiveNodeResponseType = UserSelectInteractive | UserInputInteractive;
export type WorkflowInteractiveResponseType = InteractiveBasicType & InteractiveNodeResponseType;

View File

@@ -1,23 +1,7 @@
export const JS_TEMPLATE = `function main({data1, data2}){
return {
result: data1,
data2
}
}`;
export const PY_TEMPLATE = `def main(data1, data2):
return {
"result": data1,
"data2": data2
result: data1,
data2
}
`;
export enum SandboxCodeTypeEnum {
js = 'js',
py = 'py'
}
export const SNADBOX_CODE_TEMPLATE = {
[SandboxCodeTypeEnum.js]: JS_TEMPLATE,
[SandboxCodeTypeEnum.py]: PY_TEMPLATE
};
}`;

View File

@@ -68,14 +68,12 @@ export const CodeNode: FlowNodeTemplateType = {
key: NodeInputKeyEnum.codeType,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
valueType: WorkflowIOValueTypeEnum.string,
value: 'js'
},
{
key: NodeInputKeyEnum.code,
renderTypeList: [FlowNodeInputTypeEnum.custom],
label: '',
valueType: WorkflowIOValueTypeEnum.string,
value: JS_TEMPLATE
}
],

View File

@@ -23,7 +23,6 @@ import { NextApiResponse } from 'next';
import { AppDetailType, AppSchema } from '../../app/type';
import { ParentIdType } from 'common/parentFolder/type';
import { AppTypeEnum } from 'core/app/constants';
import { WorkflowInteractiveResponseType } from '../template/system/interactive/type';
export type FlowNodeCommonType = {
parentNodeId?: string;
@@ -121,7 +120,6 @@ export type FlowNodeItemType = FlowNodeTemplateType & {
showResult?: boolean; // show and hide result modal
response?: ChatHistoryItemResType;
isExpired?: boolean;
workflowInteractiveResponse?: WorkflowInteractiveResponseType;
};
isFolded?: boolean;
};

View File

@@ -10,7 +10,7 @@
"js-yaml": "^4.1.0",
"jschardet": "3.1.1",
"nanoid": "^5.1.3",
"next": "14.2.26",
"next": "14.2.25",
"openai": "4.61.0",
"openapi-types": "^12.1.3",
"json5": "^2.2.3",

View File

@@ -24,6 +24,5 @@ export enum SendInformTemplateCodeEnum {
RESET_PASSWORD = 'RESET_PASSWORD',
BIND_NOTIFICATION = 'BIND_NOTIFICATION',
LACK_OF_POINTS = 'LACK_OF_POINTS',
CUSTOM = 'CUSTOM',
MANAGE_RENAME = 'MANAGE_RENAME'
CUSTOM = 'CUSTOM'
}

View File

@@ -19,19 +19,6 @@ export type SendInform2User = SendInformProps & {
export type UserInformSchema = {
_id: string;
userId: string;
teamId?: string;
time: Date;
level: `${InformLevelEnum}`;
title: string;
content: string;
read: boolean;
};
export type UserInformType = {
_id: string;
userId: string;
teamId?: string;
teamName?: string;
time: Date;
level: `${InformLevelEnum}`;
title: string;

View File

@@ -5,7 +5,6 @@
"dependencies": {
"cheerio": "1.0.0-rc.12",
"@types/pg": "^8.6.6",
"@types/nodemailer": "^6.4.17",
"axios": "^1.8.2",
"duck-duck-scrape": "^2.2.5",
"echarts": "5.4.1",
@@ -14,7 +13,6 @@
"mssql": "^11.0.1",
"mysql2": "^3.11.3",
"json5": "^2.2.3",
"nodemailer": "^6.10.0",
"pg": "^8.10.0",
"wikijs": "^6.4.1"
},

View File

@@ -29,8 +29,7 @@ const packagePluginList = [
'databaseConnection',
'Doc2X',
'Doc2X/PDF2text',
'searchXNG',
'smtpEmail'
'searchXNG'
];
export const list = [...staticPluginList, ...packagePluginList];

View File

@@ -34,8 +34,7 @@ const main = async ({
port: parseInt(port, 10),
database: databaseName,
user,
password,
connectionTimeoutMillis: 30000
password
});
await client.connect();
@@ -48,8 +47,7 @@ const main = async ({
port: parseInt(port, 10),
database: databaseName,
user,
password,
connectTimeout: 30000
password
});
const [rows] = await connection.execute(sql);

View File

@@ -1,122 +0,0 @@
import { getErrText } from '@fastgpt/global/common/error/utils';
import nodemailer from 'nodemailer';
interface Props {
// SMTP配置
smtpHost: string;
smtpPort: string;
SSL: boolean;
smtpUser: string;
smtpPass: string;
fromName?: string;
// 邮件参数
to: string;
subject: string;
content: string;
cc?: string;
bcc?: string;
attachments?: string;
}
interface Response {
success: boolean;
messageId?: string;
error?: string;
}
const validateEmail = (email: string) => {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
};
const validateEmails = (emails: string) => {
return emails.split(',').every((email) => validateEmail(email.trim()));
};
const main = async ({
smtpHost,
smtpPort,
SSL,
smtpUser,
smtpPass,
fromName,
to,
subject,
content,
cc,
bcc,
attachments
}: Props): Promise<Response> => {
try {
// 验证SMTP配置
if (!smtpHost || !smtpPort || !smtpUser || !smtpPass) {
throw new Error('Incomplete SMTP configuration');
}
// 验证必填参数
if (!to || !subject || !content) {
throw new Error('Recipient, subject, and content are required');
}
// 验证邮箱格式
if (!validateEmails(to)) {
throw new Error('Invalid recipient email format');
}
if (cc && !validateEmails(cc)) {
throw new Error('Invalid CC email format');
}
if (bcc && !validateEmails(bcc)) {
throw new Error('Invalid BCC email format');
}
// 创建SMTP传输对象
const transporter = nodemailer.createTransport({
host: smtpHost,
port: Number(smtpPort),
secure: SSL === true,
auth: {
user: smtpUser,
pass: smtpPass
}
});
let attachmentsArray = [];
try {
attachmentsArray = JSON.parse(attachments || '[]');
} catch (error) {
throw new Error('Attachment format parsing error, please check attachment configuration');
}
// 发送邮件
const info = await transporter.sendMail({
from: `"${fromName || 'FastGPT'}" <${smtpUser}>`,
to: to
.split(',')
.map((email) => email.trim())
.join(','),
cc: cc
?.split(',')
.map((email) => email.trim())
.join(','),
bcc: bcc
?.split(',')
.map((email) => email.trim())
.join(','),
subject,
html: content,
attachments: attachmentsArray || []
});
return {
success: true,
messageId: info.messageId
};
} catch (error: any) {
return {
success: false,
error: getErrText(error)
};
}
};
export default main;

View File

@@ -1,651 +0,0 @@
{
"author": "cloudpense",
"version": "1.0.0",
"name": "Email 邮件发送",
"avatar": "plugins/email",
"intro": "通过SMTP协议发送电子邮件(nodemailer)",
"showStatus": true,
"weight": 10,
"isTool": true,
"templateType": "tools",
"workflow": {
"nodes": [
{
"nodeId": "pluginInput",
"name": "workflow:template.plugin_start",
"intro": "workflow:intro_plugin_input",
"avatar": "core/workflow/template/workflowStart",
"flowNodeType": "pluginInput",
"showStatus": false,
"position": {
"x": 595.3456736313964,
"y": -323.02524442647456
},
"version": "481",
"inputs": [
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "smtpHost",
"label": "smtpHost",
"description": "",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true,
"customInputConfig": {
"selectValueTypeList": ["string"]
}
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "smtpPort",
"label": "smtpPort",
"description": "SMTP端口",
"defaultValue": "465",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true
},
{
"renderTypeList": ["select", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "SSL",
"label": "SSL",
"description": "SSL",
"defaultValue": "true",
"list": [
{
"label": "true",
"value": "true"
},
{
"label": "false",
"value": "false"
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "smtpUser",
"label": "smtpUser",
"description": "SMTP用户名, 邮箱账号",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "smtpPass",
"label": "smtpPass",
"description": "邮箱密码或授权码",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "fromName",
"label": "fromName",
"description": "显示的发件人名称",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "to",
"label": "to",
"description": "请输入收件人邮箱,多个邮箱用逗号分隔",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true,
"toolDescription": "请输入收件人邮箱,多个邮箱用逗号分隔"
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "subject",
"label": "subject",
"description": "请输入邮件主题",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true,
"toolDescription": "请输入邮件主题"
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "content",
"label": "content",
"description": "请输入邮件内容支持HTML格式",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true,
"toolDescription": "请输入邮件内容支持HTML格式"
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "cc",
"label": "cc",
"description": "请输入抄送邮箱,多个邮箱用逗号分隔",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": false,
"toolDescription": "请输入抄送邮箱,多个邮箱用逗号分隔"
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "bcc",
"label": "bcc",
"description": "请输入密送邮箱,多个邮箱用逗号分隔",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": false,
"toolDescription": "请输入密送邮箱,多个邮箱用逗号分隔"
},
{
"renderTypeList": ["JSONEditor", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "attachments",
"label": "attachments",
"description": "必须是json数组格式\n[{\"filename\":\"附件名\",\"path\":\"附件url\"}]",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": false,
"customInputConfig": {
"selectValueTypeList": ["arrayObject"]
},
"toolDescription": "必须是json数组格式\n[{\"filename\":\"附件名\",\"path\":\"附件url\"}]",
"maxLength": 0
}
],
"outputs": [
{
"id": "smtpHost",
"valueType": "string",
"key": "smtpHost",
"label": "smtpHost",
"type": "hidden"
},
{
"id": "smtpPort",
"valueType": "string",
"key": "smtpPort",
"label": "smtpPort",
"type": "hidden"
},
{
"id": "SSL",
"valueType": "string",
"key": "SSL",
"label": "SSL",
"type": "hidden"
},
{
"id": "smtpUser",
"valueType": "string",
"key": "smtpUser",
"label": "smtpUser",
"type": "hidden"
},
{
"id": "smtpPass",
"valueType": "string",
"key": "smtpPass",
"label": "smtpPass",
"type": "hidden"
},
{
"id": "fromName",
"valueType": "string",
"key": "fromName",
"label": "fromName",
"type": "hidden"
},
{
"id": "to",
"valueType": "string",
"key": "to",
"label": "to",
"type": "hidden"
},
{
"id": "subject",
"valueType": "string",
"key": "subject",
"label": "subject",
"type": "hidden"
},
{
"id": "content",
"valueType": "string",
"key": "content",
"label": "content",
"type": "hidden"
},
{
"id": "cc",
"valueType": "string",
"key": "cc",
"label": "cc",
"type": "hidden"
},
{
"id": "bcc",
"valueType": "string",
"key": "bcc",
"label": "bcc",
"type": "hidden"
},
{
"id": "attachments",
"valueType": "string",
"key": "attachments",
"label": "attachments",
"type": "hidden"
}
]
},
{
"nodeId": "pluginOutput",
"name": "common:core.module.template.self_output",
"intro": "workflow:intro_custom_plugin_output",
"avatar": "core/workflow/template/pluginOutput",
"flowNodeType": "pluginOutput",
"showStatus": false,
"position": {
"x": 2135.4991928806685,
"y": -98.02524442647456
},
"version": "481",
"inputs": [
{
"renderTypeList": ["reference"],
"valueType": "string",
"canEdit": true,
"key": "发送结果",
"label": "发送结果",
"isToolOutput": true,
"description": "",
"required": true,
"value": ["uOX6ITvPWm9O", "httpRawResponse"]
}
],
"outputs": []
},
{
"nodeId": "pluginConfig",
"name": "common:core.module.template.system_config",
"intro": "",
"avatar": "core/workflow/template/systemConfig",
"flowNodeType": "pluginConfig",
"position": {
"x": 184.66337662472682,
"y": -216.05298493910115
},
"version": "4811",
"inputs": [],
"outputs": []
},
{
"nodeId": "uOX6ITvPWm9O",
"name": "HTTP 请求",
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
"avatar": "core/workflow/template/httpRequest",
"flowNodeType": "httpRequest468",
"showStatus": true,
"position": {
"x": 1340.0519095857342,
"y": -393.02524442647456
},
"version": "481",
"inputs": [
{
"key": "system_addInputParam",
"renderTypeList": ["addInputParam"],
"valueType": "dynamic",
"label": "",
"required": false,
"description": "common:core.module.input.description.HTTP Dynamic Input",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectDataset",
"selectApp"
],
"showDescription": false,
"showDefaultValue": true
},
"valueDesc": "",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpMethod",
"renderTypeList": ["custom"],
"valueType": "string",
"label": "",
"value": "POST",
"required": true,
"valueDesc": "",
"description": "",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpTimeout",
"renderTypeList": ["custom"],
"valueType": "number",
"label": "",
"value": 30,
"min": 5,
"max": 600,
"required": true,
"valueDesc": "",
"description": "",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpReqUrl",
"renderTypeList": ["hidden"],
"valueType": "string",
"label": "",
"description": "common:core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"value": "smtpEmail",
"valueDesc": "",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpHeader",
"renderTypeList": ["custom"],
"valueType": "any",
"value": [],
"label": "",
"description": "common:core.module.input.description.Http Request Header",
"placeholder": "common:core.module.input.description.Http Request Header",
"required": false,
"valueDesc": "",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpParams",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": [],
"label": "",
"required": false,
"valueDesc": "",
"description": "",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpJsonBody",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": "{\n\"smtpHost\": \"{{$pluginInput.smtpHost$}}\",\n\"smtpPort\": \"{{$pluginInput.smtpPort$}}\",\n\"SSL\": {{$pluginInput.SSL$}},\n\"smtpUser\": \"{{$pluginInput.smtpUser$}}\",\n\"smtpPass\": \"{{$pluginInput.smtpPass$}}\",\n\"fromName\": \"{{$pluginInput.fromName$}}\",\n\"to\": \"{{$pluginInput.to$}}\",\n\"subject\": \"{{$pluginInput.subject$}}\",\n\"content\": \"{{$pluginInput.content$}}\",\n\"cc\": \"{{$pluginInput.cc$}}\",\n\"bcc\": \"{{$pluginInput.bcc$}}\",\n\"attachments\":'{{$pluginInput.attachments$}}'\n}",
"label": "",
"required": false,
"valueDesc": "",
"description": "",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpFormBody",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": [],
"label": "",
"required": false,
"valueDesc": "",
"description": "",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpContentType",
"renderTypeList": ["hidden"],
"valueType": "string",
"value": "json",
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
}
],
"outputs": [
{
"id": "error",
"key": "error",
"label": "workflow:request_error",
"description": "HTTP请求错误信息成功时返回空",
"valueType": "object",
"type": "static"
},
{
"id": "httpRawResponse",
"key": "httpRawResponse",
"required": true,
"label": "workflow:raw_response",
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
"valueType": "any",
"type": "static"
},
{
"id": "system_addOutputParam",
"key": "system_addOutputParam",
"type": "dynamic",
"valueType": "dynamic",
"label": "输出字段提取",
"customFieldConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": false
},
"description": "可以通过 JSONPath 语法来提取响应值中的指定字段",
"valueDesc": ""
}
]
}
],
"edges": [
{
"source": "uOX6ITvPWm9O",
"target": "pluginOutput",
"sourceHandle": "uOX6ITvPWm9O-source-right",
"targetHandle": "pluginOutput-target-left"
},
{
"source": "pluginInput",
"target": "uOX6ITvPWm9O",
"sourceHandle": "pluginInput-source-right",
"targetHandle": "uOX6ITvPWm9O-target-left"
}
],
"chatConfig": {
"welcomeText": "",
"variables": [],
"questionGuide": {
"open": false,
"model": "gpt-4o-mini",
"customPrompt": ""
},
"ttsConfig": {
"type": "web"
},
"whisperConfig": {
"open": false,
"autoSend": false,
"autoTTSResponse": false
},
"chatInputGuide": {
"open": false,
"textList": [],
"customUrl": ""
},
"instruction": "通过SMTP协议发送电子邮件",
"autoExecute": {
"open": false,
"defaultPrompt": ""
},
"_id": "67ad649ea4b6b8eefa9d3d0d"
}
}
}

View File

@@ -1,6 +1,7 @@
import { POST } from './plusRequest';
export const postTextCensor = (data: { text: string }) =>
global
.textCensorHandler(data)
POST<{ code?: number; message: string }>('/common/censor/check', data)
.then((res) => {
if (res?.code === 5000) {
return Promise.reject(res);

View File

@@ -1,29 +0,0 @@
import { FeishuServer, YuqueServer } from '@fastgpt/global/core/dataset/apiDataset';
import {
DeepRagSearchProps,
SearchDatasetDataResponse
} from '../../core/dataset/search/controller';
import { AuthOpenApiLimitProps } from '../../support/openapi/auth';
import { CreateUsageProps, ConcatUsageProps } from '@fastgpt/global/support/wallet/usage/api';
import {
GetProApiDatasetFileContentParams,
GetProApiDatasetFileListParams,
GetProApiDatasetFilePreviewUrlParams
} from '../../core/dataset/apiDataset/proApi';
declare global {
var textCensorHandler: (params: { text: string }) => Promise<{ code: number; message?: string }>;
var deepRagHandler: (data: DeepRagSearchProps) => Promise<SearchDatasetDataResponse>;
var authOpenApiHandler: (data: AuthOpenApiLimitProps) => Promise<any>;
var createUsageHandler: (data: CreateUsageProps) => Promise<void>;
var concatUsageHandler: (data: ConcatUsageProps) => Promise<void>;
// API dataset
var getProApiDatasetFileList: (data: GetProApiDatasetFileListParams) => Promise<APIFileItem[]>;
var getProApiDatasetFileContent: (
data: GetProApiDatasetFileContentParams
) => Promise<ApiFileReadContentResponse>;
var getProApiDatasetFilePreviewUrl: (
data: GetProApiDatasetFilePreviewUrlParams
) => Promise<string>;
}

View File

@@ -1,4 +1,5 @@
import { getMongoModel, Schema } from '../../mongo';
import { connectionMongo, getMongoModel } from '../../mongo';
const { Schema } = connectionMongo;
import { RawTextBufferSchemaType } from './type';
export const collectionName = 'buffer_rawtexts';

View File

@@ -1,4 +1,5 @@
import { Schema, getMongoModel } from '../../../common/mongo';
import { connectionMongo, getMongoModel, type Model } from '../../../common/mongo';
const { Schema, model, models } = connectionMongo;
import { TTSBufferSchemaType } from './type.d';
export const collectionName = 'buffer_tts';

View File

@@ -1,79 +0,0 @@
import { ConnectionOptions, Processor, Queue, QueueOptions, Worker, WorkerOptions } from 'bullmq';
import { addLog } from '../system/log';
import { newQueueRedisConnection, newWorkerRedisConnection } from '../redis';
const defaultWorkerOpts: Omit<ConnectionOptions, 'connection'> = {
removeOnComplete: {
count: 0 // Delete jobs immediately on completion
},
removeOnFail: {
count: 0 // Delete jobs immediately on failure
}
};
export enum QueueNames {
websiteSync = 'websiteSync'
}
export const queues = (() => {
if (!global.queues) {
global.queues = new Map<QueueNames, Queue>();
}
return global.queues;
})();
export const workers = (() => {
if (!global.workers) {
global.workers = new Map<QueueNames, Worker>();
}
return global.workers;
})();
export function getQueue<DataType, ReturnType = void>(
name: QueueNames,
opts?: Omit<QueueOptions, 'connection'>
): Queue<DataType, ReturnType> {
// check if global.queues has the queue
const queue = queues.get(name);
if (queue) {
return queue as Queue<DataType, ReturnType>;
}
const newQueue = new Queue<DataType, ReturnType>(name.toString(), {
connection: newQueueRedisConnection(),
...opts
});
// default error handler, to avoid unhandled exceptions
newQueue.on('error', (error) => {
addLog.error(`MQ Queue [${name}]: ${error.message}`, error);
});
queues.set(name, newQueue);
return newQueue;
}
export function getWorker<DataType, ReturnType = void>(
name: QueueNames,
processor: Processor<DataType, ReturnType>,
opts?: Omit<WorkerOptions, 'connection'>
): Worker<DataType, ReturnType> {
const worker = workers.get(name);
if (worker) {
return worker as Worker<DataType, ReturnType>;
}
const newWorker = new Worker<DataType, ReturnType>(name.toString(), processor, {
connection: newWorkerRedisConnection(),
...defaultWorkerOpts,
...opts
});
// default error handler, to avoid unhandled exceptions
newWorker.on('error', (error) => {
addLog.error(`MQ Worker [${name}]: ${error.message}`, error);
});
newWorker.on('failed', (jobId, error) => {
addLog.error(`MQ Worker [${name}]: ${error.message}`, error);
});
workers.set(name, newWorker);
return newWorker;
}
export * from 'bullmq';

View File

@@ -1,7 +0,0 @@
import { Queue, Worker } from 'bullmq';
import { QueueNames } from './index';
declare global {
var queues: Map<QueueNames, Queue> | undefined;
var workers: Map<QueueNames, Worker> | undefined;
}

View File

@@ -1,4 +1,5 @@
import { Schema, getMongoModel } from '../../mongo';
import { connectionMongo, getMongoModel, type Model } from '../../mongo';
const { Schema } = connectionMongo;
const DatasetFileSchema = new Schema({});
const ChatFileSchema = new Schema({});

View File

@@ -1,6 +1,7 @@
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
import { Schema, getMongoModel } from '../../mongo';
import { connectionMongo, getMongoModel } from '../../mongo';
import { MongoImageSchemaType } from '@fastgpt/global/common/file/image/type.d';
const { Schema } = connectionMongo;
const ImageSchema = new Schema({
teamId: {

View File

@@ -1,24 +1,15 @@
import { addLog } from '../../common/system/log';
import mongoose, { Model, Mongoose } from 'mongoose';
import mongoose, { Model } from 'mongoose';
export default mongoose;
export * from 'mongoose';
export const MONGO_URL = process.env.MONGODB_URI as string;
export const MONGO_LOG_URL = (process.env.MONGODB_LOG_URI ?? process.env.MONGODB_URI) as string;
export const connectionMongo = (() => {
if (!global.mongodb) {
global.mongodb = new Mongoose();
global.mongodb = mongoose;
}
return global.mongodb;
})();
export const connectionLogMongo = (() => {
if (!global.mongodbLog) {
global.mongodbLog = new Mongoose();
}
return global.mongodbLog;
return global.mongodb;
})();
const addCommonMiddleware = (schema: mongoose.Schema) => {
@@ -80,19 +71,6 @@ export const getMongoModel = <T>(name: string, schema: mongoose.Schema) => {
return model;
};
export const getMongoLogModel = <T>(name: string, schema: mongoose.Schema) => {
if (connectionLogMongo.models[name]) return connectionLogMongo.models[name] as Model<T>;
console.log('Load model======', name);
addCommonMiddleware(schema);
const model = connectionLogMongo.model<T>(name, schema);
// Sync index
syncMongoIndex(model);
return model;
};
const syncMongoIndex = async (model: Model<any>) => {
if (process.env.SYNC_INDEX !== '0' && process.env.NODE_ENV !== 'test') {
try {

View File

@@ -1,5 +1,6 @@
import { delay } from '@fastgpt/global/common/system/utils';
import { addLog } from '../system/log';
import { connectionMongo } from './index';
import type { Mongoose } from 'mongoose';
const maxConnecting = Math.max(30, Number(process.env.DB_MAX_LINK || 20));
@@ -7,41 +8,41 @@ const maxConnecting = Math.max(30, Number(process.env.DB_MAX_LINK || 20));
/**
* connect MongoDB and init data
*/
export async function connectMongo(db: Mongoose, url: string): Promise<Mongoose> {
export async function connectMongo(): Promise<Mongoose> {
/* Connecting, connected will return */
if (db.connection.readyState !== 0) {
return db;
if (connectionMongo.connection.readyState !== 0) {
return connectionMongo;
}
console.log('MongoDB start connect');
console.log('mongo start connect');
try {
// Remove existing listeners to prevent duplicates
db.connection.removeAllListeners('error');
db.connection.removeAllListeners('disconnected');
db.set('strictQuery', 'throw');
connectionMongo.connection.removeAllListeners('error');
connectionMongo.connection.removeAllListeners('disconnected');
connectionMongo.set('strictQuery', 'throw');
db.connection.on('error', async (error) => {
connectionMongo.connection.on('error', async (error) => {
console.log('mongo error', error);
try {
if (db.connection.readyState !== 0) {
await db.disconnect();
if (connectionMongo.connection.readyState !== 0) {
await connectionMongo.disconnect();
await delay(1000);
await connectMongo(db, url);
await connectMongo();
}
} catch (error) {}
});
db.connection.on('disconnected', async () => {
connectionMongo.connection.on('disconnected', async () => {
console.log('mongo disconnected');
try {
if (db.connection.readyState !== 0) {
await db.disconnect();
if (connectionMongo.connection.readyState !== 0) {
await connectionMongo.disconnect();
await delay(1000);
await connectMongo(db, url);
await connectMongo();
}
} catch (error) {}
});
const options = {
await connectionMongo.connect(process.env.MONGODB_URI as string, {
bufferCommands: true,
maxConnecting: maxConnecting,
maxPoolSize: maxConnecting,
@@ -52,18 +53,18 @@ export async function connectMongo(db: Mongoose, url: string): Promise<Mongoose>
maxIdleTimeMS: 300000,
retryWrites: true,
retryReads: true
};
db.connect(url, options);
// readPreference: 'secondaryPreferred',
// readConcern: { level: 'local' },
// writeConcern: { w: 'majority', j: true }
});
console.log('mongo connected');
return db;
return connectionMongo;
} catch (error) {
addLog.error('Mongo connect error', error);
await db.disconnect();
addLog.error('mongo connect error', error);
await connectionMongo.disconnect();
await delay(1000);
return connectMongo(db, url);
return connectMongo();
}
}

View File

@@ -3,5 +3,4 @@ import type { Logger } from 'winston';
declare global {
var mongodb: Mongoose | undefined;
var mongodbLog: Mongoose | undefined;
}

View File

@@ -1,38 +0,0 @@
import { getGlobalRedisCacheConnection } from './index';
import { addLog } from '../system/log';
import { retryFn } from '@fastgpt/global/common/system/utils';
export enum CacheKeyEnum {
team_vector_count = 'team_vector_count'
}
export const setRedisCache = async (
key: string,
data: string | Buffer | number,
expireSeconds?: number
) => {
return await retryFn(async () => {
try {
const redis = getGlobalRedisCacheConnection();
if (expireSeconds) {
await redis.set(key, data, 'EX', expireSeconds);
} else {
await redis.set(key, data);
}
} catch (error) {
addLog.error('Set cache error:', error);
return Promise.reject(error);
}
});
};
export const getRedisCache = async (key: string) => {
const redis = getGlobalRedisCacheConnection();
return await retryFn(() => redis.get(key));
};
export const delRedisCache = async (key: string) => {
const redis = getGlobalRedisCacheConnection();
await retryFn(() => redis.del(key));
};

View File

@@ -1,43 +0,0 @@
import { addLog } from '../system/log';
import Redis from 'ioredis';
const REDIS_URL = process.env.REDIS_URL ?? 'redis://localhost:6379';
export const newQueueRedisConnection = () => {
const redis = new Redis(REDIS_URL);
redis.on('connect', () => {
console.log('Redis connected');
});
redis.on('error', (error) => {
console.error('Redis connection error', error);
});
return redis;
};
export const newWorkerRedisConnection = () => {
const redis = new Redis(REDIS_URL, {
maxRetriesPerRequest: null
});
redis.on('connect', () => {
console.log('Redis connected');
});
redis.on('error', (error) => {
console.error('Redis connection error', error);
});
return redis;
};
export const getGlobalRedisCacheConnection = () => {
if (global.redisCache) return global.redisCache;
global.redisCache = new Redis(REDIS_URL, { keyPrefix: 'fastgpt:cache:' });
global.redisCache.on('connect', () => {
addLog.info('Redis connected');
});
global.redisCache.on('error', (error) => {
addLog.error('Redis connection error', error);
});
return global.redisCache;
};

View File

@@ -1,5 +0,0 @@
import Redis from 'ioredis';
declare global {
var redisCache: Redis | null;
}

View File

@@ -1,3 +1,4 @@
export const FastGPTProUrl = process.env.PRO_URL ? `${process.env.PRO_URL}/api` : '';
export const isFastGPTMainService = !!process.env.PRO_URL;
// @ts-ignore
export const isFastGPTProService = () => !!global.systemConfig;

Some files were not shown because too many files have changed in this diff Show More