mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-14 11:40:07 +00:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 805783d65b | |||
| 9fdebe3eac | |||
| da87df9533 | |||
| 710d92d9f6 | |||
| 5e203b868c | |||
| 6e4ad89c82 | |||
| 73daa2513f | |||
| 2302940079 | |||
| 9c653e0053 | |||
| 53c9cda9e8 | |||
| 6f9e01047b | |||
| a76a630f28 | |||
| 338df4baf9 | |||
| 1a590a065c | |||
| 4a87b31246 | |||
| 83842b45b3 | |||
| 87e3dad58a | |||
| f3210a3f57 | |||
| 8b8159eb01 | |||
| 5086a126a7 | |||
| a82a4bda34 | |||
| 71b2ecd94b | |||
| ffd9fff091 | |||
| 67c4bafd3f | |||
| 7496511917 | |||
| 15e89f2eee | |||
| 1421e991d8 | |||
| f17acd7f7e | |||
| e46df98907 | |||
| 2c791d749d | |||
| 4e982cf89f | |||
| 104a19a8a4 | |||
| c5a1791e32 | |||
| 9a1a81680f | |||
| 4bd82c397a | |||
| 891837b792 | |||
| a4c1d4b687 | |||
| 0bda4d9845 | |||
| 7abc5142e0 | |||
| 1b9caa92a5 | |||
| b8ef02e647 |
+4
-6
@@ -1,6 +1,3 @@
|
||||
# add a access code to lock your lobe-chat application, you can set a long password to avoid leaking. If this value contains a comma, it is a password array.
|
||||
# ACCESS_CODE=lobe66
|
||||
|
||||
# Specify your API Key selection method, currently supporting `random` and `turn`.
|
||||
# API_KEY_SELECT_MODE=random
|
||||
|
||||
@@ -265,9 +262,6 @@ OPENAI_API_KEY=sk-xxxxxxxxx
|
||||
# Bucket request endpoint
|
||||
# S3_ENDPOINT=https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxx.r2.cloudflarestorage.com
|
||||
|
||||
# Public access domain for the bucket
|
||||
# S3_PUBLIC_DOMAIN=https://s3-for-lobechat.your-domain.com
|
||||
|
||||
# Bucket region, such as us-west-1, generally not needed to add
|
||||
# but some service providers may require configuration
|
||||
# S3_REGION=us-west-1
|
||||
@@ -295,6 +289,10 @@ OPENAI_API_KEY=sk-xxxxxxxxx
|
||||
# Leave empty to allow all emails
|
||||
# AUTH_ALLOWED_EMAILS=example.com,admin@other.com
|
||||
|
||||
# Disable email/password authentication (SSO-only mode)
|
||||
# Set to '1' to disable email/password sign-in and registration, only allowing SSO login
|
||||
# AUTH_DISABLE_EMAIL_PASSWORD=0
|
||||
|
||||
# Google OAuth Configuration (for Better-Auth)
|
||||
# Get credentials from: https://console.cloud.google.com/apis/credentials
|
||||
# Authorized redirect URIs:
|
||||
|
||||
@@ -85,9 +85,6 @@ S3_ENDPOINT=http://localhost:${MINIO_PORT}
|
||||
# S3 bucket name for storing files
|
||||
S3_BUCKET=${MINIO_LOBE_BUCKET}
|
||||
|
||||
# Public domain for S3 file access
|
||||
S3_PUBLIC_DOMAIN=http://localhost:${MINIO_PORT}
|
||||
|
||||
# Enable path-style S3 requests (required for MinIO)
|
||||
S3_ENABLE_PATH_STYLE=1
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ jobs:
|
||||
# 使用 GitHub Hosted Runner
|
||||
if [[ "${{ github.event_name }}" != "workflow_dispatch" ]] || [[ "${{ inputs.build_mac }}" == "true" ]]; then
|
||||
echo "Using GitHub-Hosted Runner for macOS ARM64"
|
||||
arm_entry='{"os": "macos-14", "name": "macos-arm64"}'
|
||||
arm_entry='{"os": "macos-15", "name": "macos-arm64"}'
|
||||
static_matrix=$(echo "$static_matrix" | jq -c --argjson entry "$arm_entry" '. + [$entry]')
|
||||
fi
|
||||
|
||||
|
||||
+259
@@ -2,6 +2,265 @@
|
||||
|
||||
# Changelog
|
||||
|
||||
### [Version 2.1.6](https://github.com/lobehub/lobe-chat/compare/v2.1.5...v2.1.6)
|
||||
|
||||
<sup>Released on **2026-02-01**</sup>
|
||||
|
||||
#### 💄 Styles
|
||||
|
||||
- **misc**: Improve local-system tool implement.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### Styles
|
||||
|
||||
- **misc**: Improve local-system tool implement, closes [#12022](https://github.com/lobehub/lobe-chat/issues/12022) ([5e203b8](https://github.com/lobehub/lobe-chat/commit/5e203b8))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.5](https://github.com/lobehub/lobe-chat/compare/v2.1.4...v2.1.5)
|
||||
|
||||
<sup>Released on **2026-01-31**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **misc**: Slove the group member agents cant set skills problem.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **misc**: Slove the group member agents cant set skills problem, closes [#12021](https://github.com/lobehub/lobe-chat/issues/12021) ([2302940](https://github.com/lobehub/lobe-chat/commit/2302940))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.4](https://github.com/lobehub/lobe-chat/compare/v2.1.3...v2.1.4)
|
||||
|
||||
<sup>Released on **2026-01-31**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **stream**: Update event handling to use 'text' instead of 'content_part' in gemini 2.5 models.
|
||||
|
||||
#### 💄 Styles
|
||||
|
||||
- **misc**: Update i18n, Update Kimi K2.5 & Qwen3 Max Thinking models.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **stream**: Update event handling to use 'text' instead of 'content_part' in gemini 2.5 models, closes [#11235](https://github.com/lobehub/lobe-chat/issues/11235) ([a76a630](https://github.com/lobehub/lobe-chat/commit/a76a630))
|
||||
|
||||
#### Styles
|
||||
|
||||
- **misc**: Update i18n, closes [#11920](https://github.com/lobehub/lobe-chat/issues/11920) ([1a590a0](https://github.com/lobehub/lobe-chat/commit/1a590a0))
|
||||
- **misc**: Update Kimi K2.5 & Qwen3 Max Thinking models, closes [#11925](https://github.com/lobehub/lobe-chat/issues/11925) ([6f9e010](https://github.com/lobehub/lobe-chat/commit/6f9e010))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.3](https://github.com/lobehub/lobe-chat/compare/v2.1.2...v2.1.3)
|
||||
|
||||
<sup>Released on **2026-01-31**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **auth**: Add AUTH_DISABLE_EMAIL_PASSWORD env to enable SSO-only mode.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **auth**: Add AUTH_DISABLE_EMAIL_PASSWORD env to enable SSO-only mode, closes [#12009](https://github.com/lobehub/lobe-chat/issues/12009) ([f3210a3](https://github.com/lobehub/lobe-chat/commit/f3210a3))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.2](https://github.com/lobehub/lobe-chat/compare/v2.1.1...v2.1.2)
|
||||
|
||||
<sup>Released on **2026-01-30**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **misc**: Fix feishu sso provider.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **misc**: Fix feishu sso provider, closes [#11970](https://github.com/lobehub/lobe-chat/issues/11970) ([ffd9fff](https://github.com/lobehub/lobe-chat/commit/ffd9fff))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.1](https://github.com/lobehub/lobe-chat/compare/v2.1.0...v2.1.1)
|
||||
|
||||
<sup>Released on **2026-01-30**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **misc**: Correct desktop download URL path.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **misc**: Correct desktop download URL path, closes [#11990](https://github.com/lobehub/lobe-chat/issues/11990) ([e46df98](https://github.com/lobehub/lobe-chat/commit/e46df98))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
## [Version 2.1.0](https://github.com/lobehub/lobe-chat/compare/v2.0.13...v2.1.0)
|
||||
|
||||
<sup>Released on **2026-01-30**</sup>
|
||||
|
||||
#### ✨ Features
|
||||
|
||||
- **misc**: Refactor cron job UI and use runtime enableBusinessFeatures flag.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's improved
|
||||
|
||||
- **misc**: Refactor cron job UI and use runtime enableBusinessFeatures flag, closes [#11975](https://github.com/lobehub/lobe-chat/issues/11975) ([104a19a](https://github.com/lobehub/lobe-chat/commit/104a19a))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.0.13](https://github.com/lobehub/lobe-chat/compare/v2.0.12...v2.0.13)
|
||||
|
||||
<sup>Released on **2026-01-29**</sup>
|
||||
|
||||
#### 💄 Styles
|
||||
|
||||
- **misc**: Fix usage table display issues.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### Styles
|
||||
|
||||
- **misc**: Fix usage table display issues, closes [#10108](https://github.com/lobehub/lobe-chat/issues/10108) ([4bd82c3](https://github.com/lobehub/lobe-chat/commit/4bd82c3))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.0.12](https://github.com/lobehub/lobe-chat/compare/v2.0.11...v2.0.12)
|
||||
|
||||
<sup>Released on **2026-01-29**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **misc**: Group publish to market should set local group market identifer.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **misc**: Group publish to market should set local group market identifer, closes [#11965](https://github.com/lobehub/lobe-chat/issues/11965) ([0bda4d9](https://github.com/lobehub/lobe-chat/commit/0bda4d9))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.0.11](https://github.com/lobehub/lobe-chat/compare/v2.0.10...v2.0.11)
|
||||
|
||||
<sup>Released on **2026-01-29**</sup>
|
||||
|
||||
#### 💄 Styles
|
||||
|
||||
- **misc**: Fix group task render.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### Styles
|
||||
|
||||
- **misc**: Fix group task render, closes [#11952](https://github.com/lobehub/lobe-chat/issues/11952) ([b8ef02e](https://github.com/lobehub/lobe-chat/commit/b8ef02e))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.0.10](https://github.com/lobehub/lobe-chat/compare/v2.0.9...v2.0.10)
|
||||
|
||||
<sup>Released on **2026-01-29**</sup>
|
||||
|
||||
+50
-56
@@ -8,24 +8,22 @@ ARG USE_CN_MIRROR
|
||||
|
||||
ENV DEBIAN_FRONTEND="noninteractive"
|
||||
|
||||
RUN <<'EOF'
|
||||
set -e
|
||||
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then
|
||||
sed -i "s/deb.debian.org/mirrors.ustc.edu.cn/g" "/etc/apt/sources.list.d/debian.sources"
|
||||
fi
|
||||
apt update
|
||||
apt install ca-certificates proxychains-ng -qy
|
||||
mkdir -p /distroless/bin /distroless/etc /distroless/etc/ssl/certs /distroless/lib
|
||||
cp /usr/lib/$(arch)-linux-gnu/libproxychains.so.4 /distroless/lib/libproxychains.so.4
|
||||
cp /usr/lib/$(arch)-linux-gnu/libdl.so.2 /distroless/lib/libdl.so.2
|
||||
cp /usr/bin/proxychains4 /distroless/bin/proxychains
|
||||
cp /etc/proxychains4.conf /distroless/etc/proxychains4.conf
|
||||
cp /usr/lib/$(arch)-linux-gnu/libstdc++.so.6 /distroless/lib/libstdc++.so.6
|
||||
cp /usr/lib/$(arch)-linux-gnu/libgcc_s.so.1 /distroless/lib/libgcc_s.so.1
|
||||
cp /usr/local/bin/node /distroless/bin/node
|
||||
cp /etc/ssl/certs/ca-certificates.crt /distroless/etc/ssl/certs/ca-certificates.crt
|
||||
rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/*
|
||||
EOF
|
||||
RUN set -e && \
|
||||
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then \
|
||||
sed -i "s/deb.debian.org/mirrors.ustc.edu.cn/g" "/etc/apt/sources.list.d/debian.sources"; \
|
||||
fi && \
|
||||
apt update && \
|
||||
apt install ca-certificates proxychains-ng -qy && \
|
||||
mkdir -p /distroless/bin /distroless/etc /distroless/etc/ssl/certs /distroless/lib && \
|
||||
cp /usr/lib/$(arch)-linux-gnu/libproxychains.so.4 /distroless/lib/libproxychains.so.4 && \
|
||||
cp /usr/lib/$(arch)-linux-gnu/libdl.so.2 /distroless/lib/libdl.so.2 && \
|
||||
cp /usr/bin/proxychains4 /distroless/bin/proxychains && \
|
||||
cp /etc/proxychains4.conf /distroless/etc/proxychains4.conf && \
|
||||
cp /usr/lib/$(arch)-linux-gnu/libstdc++.so.6 /distroless/lib/libstdc++.so.6 && \
|
||||
cp /usr/lib/$(arch)-linux-gnu/libgcc_s.so.1 /distroless/lib/libgcc_s.so.1 && \
|
||||
cp /usr/local/bin/node /distroless/bin/node && \
|
||||
cp /etc/ssl/certs/ca-certificates.crt /distroless/etc/ssl/certs/ca-certificates.crt && \
|
||||
rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/*
|
||||
|
||||
## Builder image, install all the dependencies and build the app
|
||||
FROM base AS builder
|
||||
@@ -77,23 +75,21 @@ COPY patches ./patches
|
||||
# bring in desktop workspace manifest so pnpm can resolve it
|
||||
COPY apps/desktop/src/main/package.json ./apps/desktop/src/main/package.json
|
||||
|
||||
RUN <<'EOF'
|
||||
set -e
|
||||
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then
|
||||
export SENTRYCLI_CDNURL="https://npmmirror.com/mirrors/sentry-cli"
|
||||
npm config set registry "https://registry.npmmirror.com/"
|
||||
echo 'canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas' >> .npmrc
|
||||
fi
|
||||
export COREPACK_NPM_REGISTRY=$(npm config get registry | sed 's/\/$//')
|
||||
npm i -g corepack@latest
|
||||
corepack enable
|
||||
corepack use $(sed -n 's/.*"packageManager": "\(.*\)".*/\1/p' package.json)
|
||||
pnpm i
|
||||
mkdir -p /deps
|
||||
cd /deps
|
||||
pnpm init
|
||||
pnpm add pg drizzle-orm
|
||||
EOF
|
||||
RUN set -e && \
|
||||
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then \
|
||||
export SENTRYCLI_CDNURL="https://npmmirror.com/mirrors/sentry-cli"; \
|
||||
npm config set registry "https://registry.npmmirror.com/"; \
|
||||
echo 'canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas' >> .npmrc; \
|
||||
fi && \
|
||||
export COREPACK_NPM_REGISTRY=$(npm config get registry | sed 's/\/$//') && \
|
||||
npm i -g corepack@latest && \
|
||||
corepack enable && \
|
||||
corepack use $(sed -n 's/.*"packageManager": "\(.*\)".*/\1/p' package.json) && \
|
||||
pnpm i && \
|
||||
mkdir -p /deps && \
|
||||
cd /deps && \
|
||||
pnpm init && \
|
||||
pnpm add pg drizzle-orm
|
||||
|
||||
COPY . .
|
||||
|
||||
@@ -101,17 +97,15 @@ COPY . .
|
||||
RUN npm run build:docker
|
||||
|
||||
# Prepare desktop export assets for Electron packaging (if generated)
|
||||
RUN <<'EOF'
|
||||
set -e
|
||||
if [ -d "/app/out" ]; then
|
||||
mkdir -p /app/apps/desktop/dist/next
|
||||
cp -a /app/out/. /app/apps/desktop/dist/next/
|
||||
echo "✅ Copied Next export output into /app/apps/desktop/dist/next"
|
||||
else
|
||||
echo "ℹ️ No Next export output found at /app/out, creating empty directory"
|
||||
mkdir -p /app/apps/desktop/dist/next
|
||||
fi
|
||||
EOF
|
||||
RUN set -e && \
|
||||
if [ -d "/app/out" ]; then \
|
||||
mkdir -p /app/apps/desktop/dist/next && \
|
||||
cp -a /app/out/. /app/apps/desktop/dist/next/ && \
|
||||
echo "Copied Next export output into /app/apps/desktop/dist/next"; \
|
||||
else \
|
||||
echo "No Next export output found at /app/out, creating empty directory" && \
|
||||
mkdir -p /app/apps/desktop/dist/next; \
|
||||
fi
|
||||
|
||||
## Application image, copy all the files for production
|
||||
FROM busybox:latest AS app
|
||||
@@ -138,12 +132,10 @@ COPY --from=builder /deps/node_modules/drizzle-orm /app/node_modules/drizzle-orm
|
||||
COPY --from=builder /app/scripts/serverLauncher/startServer.js /app/startServer.js
|
||||
COPY --from=builder /app/scripts/_shared /app/scripts/_shared
|
||||
|
||||
RUN <<'EOF'
|
||||
set -e
|
||||
addgroup -S -g 1001 nodejs
|
||||
adduser -D -G nodejs -H -S -h /app -u 1001 nextjs
|
||||
chown -R nextjs:nodejs /app /etc/proxychains4.conf
|
||||
EOF
|
||||
RUN set -e && \
|
||||
addgroup -S -g 1001 nodejs && \
|
||||
adduser -D -G nodejs -H -S -h /app -u 1001 nextjs && \
|
||||
chown -R nextjs:nodejs /app /etc/proxychains4.conf
|
||||
|
||||
## Production image, copy all the files and run next
|
||||
FROM scratch
|
||||
@@ -166,14 +158,12 @@ ENV HOSTNAME="0.0.0.0" \
|
||||
PORT="3210"
|
||||
|
||||
# General Variables
|
||||
ENV ACCESS_CODE="" \
|
||||
APP_URL="" \
|
||||
ENV APP_URL="" \
|
||||
API_KEY_SELECT_MODE="" \
|
||||
DEFAULT_AGENT_CONFIG="" \
|
||||
SYSTEM_AGENT="" \
|
||||
FEATURE_FLAGS="" \
|
||||
PROXY_URL="" \
|
||||
ENABLE_AUTH_PROTECTION=""
|
||||
PROXY_URL=""
|
||||
|
||||
# Database
|
||||
ENV KEY_VAULTS_SECRET="" \
|
||||
@@ -184,6 +174,10 @@ ENV KEY_VAULTS_SECRET="" \
|
||||
ENV AUTH_SECRET="" \
|
||||
AUTH_SSO_PROVIDERS="" \
|
||||
AUTH_ALLOWED_EMAILS="" \
|
||||
AUTH_TRUSTED_ORIGINS="" \
|
||||
AUTH_DISABLE_EMAIL_PASSWORD="" \
|
||||
AUTH_EMAIL_VERIFICATION="" \
|
||||
AUTH_ENABLE_MAGIC_LINK="" \
|
||||
# Google
|
||||
AUTH_GOOGLE_ID="" \
|
||||
AUTH_GOOGLE_SECRET="" \
|
||||
|
||||
@@ -37,7 +37,7 @@ We’re building the world’s largest human–agent co-evolving network.
|
||||
[![][share-mastodon-shield]][share-mastodon-link]
|
||||
[![][share-linkedin-shield]][share-linkedin-link]
|
||||
|
||||
<sup>Agent teams that grow with you</sup>
|
||||
<sup>Agent teammates that grow with you</sup>
|
||||
|
||||
[![][github-trending-shield]][github-trending-url]
|
||||
|
||||
@@ -581,7 +581,7 @@ LobeHub provides Self-Hosted Version with Vercel, Alibaba Cloud, and [Docker Ima
|
||||
"If you want to deploy this service yourself on Vercel, Zeabur or Alibaba Cloud, you can follow these steps:
|
||||
|
||||
- Prepare your [OpenAI API Key](https://platform.openai.com/account/api-keys).
|
||||
- Click the button below to start deployment: Log in directly with your GitHub account, and remember to fill in the `OPENAI_API_KEY`(required) and `ACCESS_CODE` (recommended) on the environment variable section.
|
||||
- Click the button below to start deployment: Log in directly with your GitHub account, and remember to fill in the `OPENAI_API_KEY`(required) on the environment variable section.
|
||||
- After deployment, you can start using it.
|
||||
- Bind a custom domain (optional): The DNS of the domain assigned by Vercel is polluted in some areas; binding a custom domain can connect directly.
|
||||
|
||||
@@ -647,7 +647,6 @@ This project provides some additional configuration items set with environment v
|
||||
| -------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| `OPENAI_API_KEY` | Yes | This is the API key you apply on the OpenAI account page | `sk-xxxxxx...xxxxxx` |
|
||||
| `OPENAI_PROXY_URL` | No | If you manually configure the OpenAI interface proxy, you can use this configuration item to override the default OpenAI API request base URL | `https://api.chatanywhere.cn` or `https://aihubmix.com/v1` <br/>The default value is<br/>`https://api.openai.com/v1` |
|
||||
| `ACCESS_CODE` | No | Add a password to access this service; you can set a long password to avoid leaking. If this value contains a comma, it is a password array. | `awCTe)re_r74` or `rtrt_ewee3@09!` or `code1,code2,code3` |
|
||||
| `OPENAI_MODEL_LIST` | No | Used to control the model list. Use `+` to add a model, `-` to hide a model, and `model_name=display_name` to customize the display name of a model, separated by commas. | `qwen-7b-chat,+glm-6b,-gpt-3.5-turbo` |
|
||||
|
||||
> \[!NOTE]
|
||||
@@ -829,7 +828,7 @@ This project is [LobeHub Community License](./LICENSE) licensed.
|
||||
[codespaces-link]: https://codespaces.new/lobehub/lobe-chat
|
||||
[codespaces-shield]: https://github.com/codespaces/badge.svg
|
||||
[deploy-button-image]: https://vercel.com/button
|
||||
[deploy-link]: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat&env=OPENAI_API_KEY,ACCESS_CODE&envDescription=Find%20your%20OpenAI%20API%20Key%20by%20click%20the%20right%20Learn%20More%20button.%20%7C%20Access%20Code%20can%20protect%20your%20website&envLink=https%3A%2F%2Fplatform.openai.com%2Faccount%2Fapi-keys&project-name=lobe-chat&repository-name=lobe-chat
|
||||
[deploy-link]: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat&env=OPENAI_API_KEY&envDescription=Find%20your%20OpenAI%20API%20Key%20by%20click%20the%20right%20Learn%20More%20button.&envLink=https%3A%2F%2Fplatform.openai.com%2Faccount%2Fapi-keys&project-name=lobe-chat&repository-name=lobe-chat
|
||||
[deploy-on-alibaba-cloud-button-image]: https://service-info-public.oss-cn-hangzhou.aliyuncs.com/computenest-en.svg
|
||||
[deploy-on-alibaba-cloud-link]: https://computenest.console.aliyun.com/service/instance/create/default?type=user&ServiceName=LobeHub%E7%A4%BE%E5%8C%BA%E7%89%88
|
||||
[deploy-on-repocloud-button-image]: https://d16t0pc4846x52.cloudfront.net/deploylobe.svg
|
||||
|
||||
+3
-4
@@ -35,7 +35,7 @@ LobeHub 是一个工作与生活空间,用于发现、构建并与会随着您
|
||||
[![][share-weibo-shield]][share-weibo-link]
|
||||
[![][share-mastodon-shield]][share-mastodon-link]
|
||||
|
||||
<sup>Agent teams that grow with you</sup>
|
||||
<sup>Agent teammates that grow with you</sup>
|
||||
|
||||
[![][github-trending-shield]][github-trending-url]
|
||||
[![][github-hello-shield]][github-hello-url]
|
||||
@@ -555,7 +555,7 @@ LobeHub 提供了 Vercel 的 自托管版本 和 [Docker 镜像][docker-release-
|
||||
如果想在 Vercel 、 Zeabur 或 阿里云 上部署该服务,可以按照以下步骤进行操作:
|
||||
|
||||
- 准备好你的 [OpenAI API Key](https://platform.openai.com/account/api-keys) 。
|
||||
- 点击下方按钮开始部署: 直接使用 GitHub 账号登录即可,记得在环境变量页填入 `OPENAI_API_KEY` (必填) and `ACCESS_CODE`(推荐);
|
||||
- 点击下方按钮开始部署: 直接使用 GitHub 账号登录即可,记得在环境变量页填入 `OPENAI_API_KEY` (必填);
|
||||
- 部署完毕后,即可开始使用;
|
||||
- 绑定自定义域名(可选):Vercel 分配的域名 DNS 在某些区域被污染了,绑定自定义域名即可直连。目前 Zeabur 提供的域名还未被污染,大多数地区都可以直连。
|
||||
|
||||
@@ -621,7 +621,6 @@ docker compose up -d
|
||||
| ------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| `OPENAI_API_KEY` | 必选 | 这是你在 OpenAI 账户页面申请的 API 密钥 | `sk-xxxxxx...xxxxxx` |
|
||||
| `OPENAI_PROXY_URL` | 可选 | 如果你手动配置了 OpenAI 接口代理,可以使用此配置项来覆盖默认的 OpenAI API 请求基础 URL | `https://api.chatanywhere.cn` 或 `https://aihubmix.com/v1`<br/>默认值:<br/>`https://api.openai.com/v1` |
|
||||
| `ACCESS_CODE` | 可选 | 添加访问此服务的密码,你可以设置一个长密码以防被爆破,该值用逗号分隔时为密码数组 | `awCTe)re_r74` or `rtrt_ewee3@09!` or `code1,code2,code3` |
|
||||
| `OPENAI_MODEL_LIST` | 可选 | 用来控制模型列表,使用 `+` 增加一个模型,使用 `-` 来隐藏一个模型,使用 `模型名=展示名` 来自定义模型的展示名,用英文逗号隔开。 | `qwen-7b-chat,+glm-6b,-gpt-3.5-turbo` |
|
||||
|
||||
> \[!NOTE]
|
||||
@@ -843,7 +842,7 @@ This project is [LobeHub Community License](./LICENSE) licensed.
|
||||
[codespaces-link]: https://codespaces.new/lobehub/lobe-chat
|
||||
[codespaces-shield]: https://github.com/codespaces/badge.svg
|
||||
[deploy-button-image]: https://vercel.com/button
|
||||
[deploy-link]: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat&env=OPENAI_API_KEY,ACCESS_CODE&envDescription=Find%20your%20OpenAI%20API%20Key%20by%20click%20the%20right%20Learn%20More%20button.%20%7C%20Access%20Code%20can%20protect%20your%20website&envLink=https%3A%2F%2Fplatform.openai.com%2Faccount%2Fapi-keys&project-name=lobe-chat&repository-name=lobe-chat
|
||||
[deploy-link]: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat&env=OPENAI_API_KEY&envDescription=Find%20your%20OpenAI%20API%20Key%20by%20click%20the%20right%20Learn%20More%20button.&envLink=https%3A%2F%2Fplatform.openai.com%2Faccount%2Fapi-keys&project-name=lobe-chat&repository-name=lobe-chat
|
||||
[deploy-on-alibaba-cloud-button-image]: https://service-info-public.oss-cn-hangzhou.aliyuncs.com/computenest-en.svg
|
||||
[deploy-on-alibaba-cloud-link]: https://computenest.console.aliyun.com/service/instance/create/default?type=user&ServiceName=LobeHub%E7%A4%BE%E5%8C%BA%E7%89%88
|
||||
[deploy-on-sealos-button-image]: https://raw.githubusercontent.com/labring-actions/templates/main/Deploy-on-Sealos.svg
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
"main": "./dist/main/index.js",
|
||||
"scripts": {
|
||||
"build": "electron-vite build",
|
||||
"build-local": "npm run build && electron-builder --dir --config electron-builder.mjs --c.mac.notarize=false -c.mac.identity=null --c.asar=false",
|
||||
"build:linux": "npm run build && electron-builder --linux --config electron-builder.mjs --publish never",
|
||||
"build:mac": "npm run build && electron-builder --mac --config electron-builder.mjs --publish never",
|
||||
"build:mac:local": "npm run build && UPDATE_CHANNEL=nightly electron-builder --mac --config electron-builder.mjs --publish never",
|
||||
"build:win": "npm run build && electron-builder --win --config electron-builder.mjs --publish never",
|
||||
"build-local": "npm run build && electron-builder --dir --config electron-builder.mjs --c.mac.notarize=false -c.mac.identity=null --c.asar=false",
|
||||
"dev": "electron-vite dev",
|
||||
"dev:static": "cross-env DESKTOP_RENDERER_STATIC=1 npm run electron:dev",
|
||||
"electron:dev": "electron-vite dev",
|
||||
@@ -47,9 +47,6 @@
|
||||
"get-port-please": "^3.2.0",
|
||||
"superjson": "^2.2.6"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"node-mac-permissions": "^2.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
|
||||
"@electron-toolkit/eslint-config-ts": "^3.1.0",
|
||||
@@ -103,6 +100,9 @@
|
||||
"vitest": "^3.2.4",
|
||||
"zod": "^3.25.76"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"node-mac-permissions": "^2.5.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"@napi-rs/canvas",
|
||||
|
||||
@@ -218,8 +218,13 @@ export default class LocalFileCtr extends ControllerModule {
|
||||
}
|
||||
|
||||
@IpcMethod()
|
||||
async listLocalFiles({ path: dirPath }: ListLocalFileParams): Promise<FileResult[]> {
|
||||
logger.debug('Listing directory contents:', { dirPath });
|
||||
async listLocalFiles({
|
||||
path: dirPath,
|
||||
sortBy = 'modifiedTime',
|
||||
sortOrder = 'desc',
|
||||
limit = 100,
|
||||
}: ListLocalFileParams): Promise<{ files: FileResult[]; totalCount: number }> {
|
||||
logger.debug('Listing directory contents:', { dirPath, limit, sortBy, sortOrder });
|
||||
|
||||
const results: FileResult[] = [];
|
||||
try {
|
||||
@@ -256,22 +261,51 @@ export default class LocalFileCtr extends ControllerModule {
|
||||
}
|
||||
}
|
||||
|
||||
// Sort entries: folders first, then by name
|
||||
// Sort entries based on sortBy and sortOrder
|
||||
results.sort((a, b) => {
|
||||
if (a.isDirectory !== b.isDirectory) {
|
||||
return a.isDirectory ? -1 : 1; // Directories first
|
||||
let comparison = 0;
|
||||
|
||||
switch (sortBy) {
|
||||
case 'name': {
|
||||
comparison = (a.name || '').localeCompare(b.name || '');
|
||||
break;
|
||||
}
|
||||
case 'modifiedTime': {
|
||||
comparison = a.modifiedTime.getTime() - b.modifiedTime.getTime();
|
||||
break;
|
||||
}
|
||||
case 'createdTime': {
|
||||
comparison = a.createdTime.getTime() - b.createdTime.getTime();
|
||||
break;
|
||||
}
|
||||
case 'size': {
|
||||
comparison = a.size - b.size;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
comparison = a.modifiedTime.getTime() - b.modifiedTime.getTime();
|
||||
}
|
||||
}
|
||||
// Add null/undefined checks for robustness if needed, though names should exist
|
||||
return (a.name || '').localeCompare(b.name || ''); // Then sort by name
|
||||
|
||||
return sortOrder === 'desc' ? -comparison : comparison;
|
||||
});
|
||||
|
||||
logger.debug('Directory listing successful', { dirPath, resultCount: results.length });
|
||||
return results;
|
||||
const totalCount = results.length;
|
||||
|
||||
// Apply limit
|
||||
const limitedResults = results.slice(0, limit);
|
||||
|
||||
logger.debug('Directory listing successful', {
|
||||
dirPath,
|
||||
resultCount: limitedResults.length,
|
||||
totalCount,
|
||||
});
|
||||
return { files: limitedResults, totalCount };
|
||||
} catch (error) {
|
||||
logger.error(`Failed to list directory ${dirPath}:`, error);
|
||||
// Rethrow or return an empty array/error object depending on desired behavior
|
||||
// For now, returning empty array on error listing directory itself
|
||||
return [];
|
||||
// For now, returning empty result on error listing directory itself
|
||||
return { files: [], totalCount: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,14 +59,14 @@ interface McpInstallParams {
|
||||
*/
|
||||
export default class McpInstallController extends ControllerModule {
|
||||
/**
|
||||
* 处理 MCP 插件安装请求
|
||||
* @param parsedData 解析后的协议数据
|
||||
* @returns 是否处理成功
|
||||
* Handle MCP plugin installation request
|
||||
* @param parsedData Parsed protocol data
|
||||
* @returns Whether processing succeeded
|
||||
*/
|
||||
@protocolHandler('install')
|
||||
public async handleInstallRequest(parsedData: McpInstallParams): Promise<boolean> {
|
||||
try {
|
||||
// 从参数中提取必需字段
|
||||
// Extract required fields from parameters
|
||||
const { id, schema: schemaParam, marketId } = parsedData;
|
||||
|
||||
if (!id) {
|
||||
@@ -76,11 +76,11 @@ export default class McpInstallController extends ControllerModule {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 映射协议来源
|
||||
// Map protocol source
|
||||
|
||||
const isOfficialMarket = marketId === 'lobehub';
|
||||
|
||||
// 对于官方市场,schema 是可选的;对于第三方市场,schema 是必需的
|
||||
// For official marketplace, schema is optional; for third-party marketplace, schema is required
|
||||
if (!isOfficialMarket && !schemaParam) {
|
||||
logger.warn(`🔧 [McpInstall] Schema is required for third-party marketplace:`, {
|
||||
marketId,
|
||||
@@ -90,7 +90,7 @@ export default class McpInstallController extends ControllerModule {
|
||||
|
||||
let mcpSchema: McpSchema | undefined;
|
||||
|
||||
// 如果提供了 schema 参数,则解析和验证
|
||||
// If schema parameter is provided, parse and validate
|
||||
if (schemaParam) {
|
||||
try {
|
||||
mcpSchema = JSON.parse(schemaParam);
|
||||
@@ -104,7 +104,7 @@ export default class McpInstallController extends ControllerModule {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证 identifier 与 id 参数匹配
|
||||
// Verify identifier matches id parameter
|
||||
if (mcpSchema.identifier !== id) {
|
||||
logger.error(`🔧 [McpInstall] Schema identifier does not match URL id parameter:`, {
|
||||
schemaId: mcpSchema.identifier,
|
||||
@@ -122,7 +122,7 @@ export default class McpInstallController extends ControllerModule {
|
||||
pluginVersion: mcpSchema?.version || 'Unknown',
|
||||
});
|
||||
|
||||
// 广播安装请求到前端
|
||||
// Broadcast installation request to frontend
|
||||
const installRequest = {
|
||||
marketId,
|
||||
pluginId: id,
|
||||
@@ -136,7 +136,7 @@ export default class McpInstallController extends ControllerModule {
|
||||
pluginName: installRequest.schema?.name || 'Unknown',
|
||||
});
|
||||
|
||||
// 通过应用实例广播到前端
|
||||
// Broadcast to frontend via app instance
|
||||
if (this.app?.browserManager) {
|
||||
this.app.browserManager.broadcastToWindow('app', 'mcpInstallRequest', installRequest);
|
||||
logger.debug(`🔧 [McpInstall] Install request broadcasted successfully`);
|
||||
|
||||
@@ -88,7 +88,7 @@ export default class NetworkProxyCtr extends ControllerModule {
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试代理连接
|
||||
* Test proxy connection
|
||||
*/
|
||||
@IpcMethod()
|
||||
async testProxyConnection(url: string): Promise<{ message?: string; success: boolean }> {
|
||||
@@ -108,7 +108,7 @@ export default class NetworkProxyCtr extends ControllerModule {
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试指定代理配置
|
||||
* Test specified proxy configuration
|
||||
*/
|
||||
@IpcMethod()
|
||||
async testProxyConfig({
|
||||
@@ -131,17 +131,17 @@ export default class NetworkProxyCtr extends ControllerModule {
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用初始代理设置
|
||||
* Apply initial proxy settings
|
||||
*/
|
||||
async beforeAppReady(): Promise<void> {
|
||||
try {
|
||||
// 获取存储的代理设置
|
||||
// Get stored proxy settings
|
||||
const networkProxy = this.app.storeManager.get(
|
||||
'networkProxy',
|
||||
defaultProxySettings,
|
||||
) as NetworkProxySettings;
|
||||
|
||||
// 验证配置
|
||||
// Validate configuration
|
||||
const validation = ProxyConfigValidator.validate(networkProxy);
|
||||
if (!validation.isValid) {
|
||||
logger.warn('Invalid stored proxy configuration, using defaults:', validation.errors);
|
||||
@@ -158,7 +158,7 @@ export default class NetworkProxyCtr extends ControllerModule {
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to apply initial proxy settings:', error);
|
||||
// 出错时使用默认设置
|
||||
// Use default settings on error
|
||||
try {
|
||||
await ProxyDispatcherManager.applyProxySettings(defaultProxySettings);
|
||||
logger.info('Fallback to default proxy settings');
|
||||
|
||||
@@ -162,7 +162,7 @@ export default class RemoteServerSyncCtr extends ControllerModule {
|
||||
});
|
||||
});
|
||||
|
||||
// 5. 监听请求本身的错误(如 DNS 解析失败)
|
||||
// 5. Listen for request errors (e.g., DNS resolution failure)
|
||||
clientReq.on('error', (error) => {
|
||||
logger.error(`${logPrefix} Error forwarding request:`, error);
|
||||
if (sender.isDestroyed()) return;
|
||||
@@ -196,7 +196,7 @@ export default class RemoteServerSyncCtr extends ControllerModule {
|
||||
delete requestHeaders['connection']; // Often causes issues
|
||||
// delete requestHeaders['content-length']; // Let node handle it based on body
|
||||
|
||||
// 读取代理配置
|
||||
// Read proxy configuration
|
||||
const proxyConfig = this.app.storeManager.get('networkProxy', defaultProxySettings);
|
||||
|
||||
let agent;
|
||||
|
||||
@@ -20,8 +20,8 @@ vi.mock('@/utils/logger', () => ({
|
||||
|
||||
// Mock file-loaders
|
||||
vi.mock('@lobechat/file-loaders', () => ({
|
||||
SYSTEM_FILES_TO_IGNORE: ['.DS_Store', 'Thumbs.db'],
|
||||
loadFile: vi.fn(),
|
||||
SYSTEM_FILES_TO_IGNORE: ['.DS_Store', 'Thumbs.db', '$RECYCLE.BIN'],
|
||||
}));
|
||||
|
||||
// Mock electron
|
||||
@@ -553,6 +553,514 @@ describe('LocalFileCtr', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('listLocalFiles', () => {
|
||||
it('should list directory contents successfully', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['file1.txt', 'file2.txt', 'folder1']);
|
||||
vi.mocked(mockFsPromises.stat).mockImplementation(async (filePath) => {
|
||||
const name = (filePath as string).split('/').pop();
|
||||
if (name === 'folder1') {
|
||||
return {
|
||||
isDirectory: () => true,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 4096,
|
||||
} as any;
|
||||
}
|
||||
return {
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-02'),
|
||||
mtime: new Date('2024-01-10'),
|
||||
atime: new Date('2024-01-18'),
|
||||
size: 1024,
|
||||
} as any;
|
||||
});
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({ path: '/test' });
|
||||
|
||||
expect(result.files).toHaveLength(3);
|
||||
expect(result.totalCount).toBe(3);
|
||||
expect(mockFsPromises.readdir).toHaveBeenCalledWith('/test');
|
||||
});
|
||||
|
||||
it('should filter out system files like .DS_Store and Thumbs.db', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue([
|
||||
'file1.txt',
|
||||
'.DS_Store',
|
||||
'Thumbs.db',
|
||||
'folder1',
|
||||
]);
|
||||
vi.mocked(mockFsPromises.stat).mockImplementation(async (filePath) => {
|
||||
const name = (filePath as string).split('/').pop();
|
||||
if (name === 'folder1') {
|
||||
return {
|
||||
isDirectory: () => true,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 4096,
|
||||
} as any;
|
||||
}
|
||||
return {
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-02'),
|
||||
mtime: new Date('2024-01-10'),
|
||||
atime: new Date('2024-01-18'),
|
||||
size: 1024,
|
||||
} as any;
|
||||
});
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({ path: '/test' });
|
||||
|
||||
// Should only contain file1.txt and folder1, not .DS_Store or Thumbs.db
|
||||
expect(result.files).toHaveLength(2);
|
||||
expect(result.totalCount).toBe(2);
|
||||
expect(result.files.map((r) => r.name)).not.toContain('.DS_Store');
|
||||
expect(result.files.map((r) => r.name)).not.toContain('Thumbs.db');
|
||||
expect(result.files.map((r) => r.name)).toContain('folder1');
|
||||
expect(result.files.map((r) => r.name)).toContain('file1.txt');
|
||||
});
|
||||
|
||||
it('should filter out $RECYCLE.BIN system folder', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['file1.txt', '$RECYCLE.BIN', 'folder1']);
|
||||
vi.mocked(mockFsPromises.stat).mockImplementation(async (filePath) => {
|
||||
const name = (filePath as string).split('/').pop();
|
||||
const isDir = name === 'folder1' || name === '$RECYCLE.BIN';
|
||||
return {
|
||||
isDirectory: () => isDir,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: isDir ? 4096 : 1024,
|
||||
} as any;
|
||||
});
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({ path: '/test' });
|
||||
|
||||
// Should not contain $RECYCLE.BIN
|
||||
expect(result.files).toHaveLength(2);
|
||||
expect(result.totalCount).toBe(2);
|
||||
expect(result.files.map((r) => r.name)).not.toContain('$RECYCLE.BIN');
|
||||
});
|
||||
|
||||
it('should sort by name ascending when specified', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['zebra.txt', 'alpha.txt', 'apple.txt']);
|
||||
vi.mocked(mockFsPromises.stat).mockResolvedValue({
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 1024,
|
||||
} as any);
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({
|
||||
path: '/test',
|
||||
sortBy: 'name',
|
||||
sortOrder: 'asc',
|
||||
});
|
||||
|
||||
expect(result.files.map((r) => r.name)).toEqual(['alpha.txt', 'apple.txt', 'zebra.txt']);
|
||||
});
|
||||
|
||||
it('should sort by modifiedTime descending by default', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['old.txt', 'new.txt', 'mid.txt']);
|
||||
vi.mocked(mockFsPromises.stat).mockImplementation(async (filePath) => {
|
||||
const name = (filePath as string).split('/').pop();
|
||||
const dates: Record<string, Date> = {
|
||||
'new.txt': new Date('2024-01-20'),
|
||||
'mid.txt': new Date('2024-01-15'),
|
||||
'old.txt': new Date('2024-01-01'),
|
||||
};
|
||||
return {
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: dates[name!] || new Date('2024-01-01'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 1024,
|
||||
} as any;
|
||||
});
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({ path: '/test' });
|
||||
|
||||
// Default sort: modifiedTime descending (newest first)
|
||||
expect(result.files.map((r) => r.name)).toEqual(['new.txt', 'mid.txt', 'old.txt']);
|
||||
});
|
||||
|
||||
it('should sort by size ascending when specified', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['large.txt', 'small.txt', 'medium.txt']);
|
||||
vi.mocked(mockFsPromises.stat).mockImplementation(async (filePath) => {
|
||||
const name = (filePath as string).split('/').pop();
|
||||
const sizes: Record<string, number> = {
|
||||
'large.txt': 10000,
|
||||
'medium.txt': 5000,
|
||||
'small.txt': 1000,
|
||||
};
|
||||
return {
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: sizes[name!] || 1024,
|
||||
} as any;
|
||||
});
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({
|
||||
path: '/test',
|
||||
sortBy: 'size',
|
||||
sortOrder: 'asc',
|
||||
});
|
||||
|
||||
expect(result.files.map((r) => r.name)).toEqual(['small.txt', 'medium.txt', 'large.txt']);
|
||||
});
|
||||
|
||||
it('should apply limit parameter', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue([
|
||||
'file1.txt',
|
||||
'file2.txt',
|
||||
'file3.txt',
|
||||
'file4.txt',
|
||||
'file5.txt',
|
||||
]);
|
||||
vi.mocked(mockFsPromises.stat).mockResolvedValue({
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 1024,
|
||||
} as any);
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({
|
||||
path: '/test',
|
||||
limit: 3,
|
||||
});
|
||||
|
||||
expect(result.files).toHaveLength(3);
|
||||
expect(result.totalCount).toBe(5); // Total is 5, but limited to 3
|
||||
});
|
||||
|
||||
it('should use default limit of 100', async () => {
|
||||
// Create 150 files
|
||||
const files = Array.from({ length: 150 }, (_, i) => `file${i}.txt`);
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(files);
|
||||
vi.mocked(mockFsPromises.stat).mockResolvedValue({
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 1024,
|
||||
} as any);
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({ path: '/test' });
|
||||
|
||||
expect(result.files).toHaveLength(100);
|
||||
expect(result.totalCount).toBe(150); // Total is 150, but limited to 100
|
||||
});
|
||||
|
||||
it('should sort by createdTime ascending when specified', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue([
|
||||
'newest.txt',
|
||||
'oldest.txt',
|
||||
'middle.txt',
|
||||
]);
|
||||
vi.mocked(mockFsPromises.stat).mockImplementation(async (filePath) => {
|
||||
const name = (filePath as string).split('/').pop();
|
||||
const dates: Record<string, Date> = {
|
||||
'newest.txt': new Date('2024-03-01'),
|
||||
'middle.txt': new Date('2024-02-01'),
|
||||
'oldest.txt': new Date('2024-01-01'),
|
||||
};
|
||||
return {
|
||||
isDirectory: () => false,
|
||||
birthtime: dates[name!] || new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 1024,
|
||||
} as any;
|
||||
});
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({
|
||||
path: '/test',
|
||||
sortBy: 'createdTime',
|
||||
sortOrder: 'asc',
|
||||
});
|
||||
|
||||
expect(result.files.map((r) => r.name)).toEqual(['oldest.txt', 'middle.txt', 'newest.txt']);
|
||||
});
|
||||
|
||||
it('should sort by createdTime descending when specified', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue([
|
||||
'newest.txt',
|
||||
'oldest.txt',
|
||||
'middle.txt',
|
||||
]);
|
||||
vi.mocked(mockFsPromises.stat).mockImplementation(async (filePath) => {
|
||||
const name = (filePath as string).split('/').pop();
|
||||
const dates: Record<string, Date> = {
|
||||
'newest.txt': new Date('2024-03-01'),
|
||||
'middle.txt': new Date('2024-02-01'),
|
||||
'oldest.txt': new Date('2024-01-01'),
|
||||
};
|
||||
return {
|
||||
isDirectory: () => false,
|
||||
birthtime: dates[name!] || new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 1024,
|
||||
} as any;
|
||||
});
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({
|
||||
path: '/test',
|
||||
sortBy: 'createdTime',
|
||||
sortOrder: 'desc',
|
||||
});
|
||||
|
||||
expect(result.files.map((r) => r.name)).toEqual(['newest.txt', 'middle.txt', 'oldest.txt']);
|
||||
});
|
||||
|
||||
it('should sort by name descending when specified', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['alpha.txt', 'zebra.txt', 'middle.txt']);
|
||||
vi.mocked(mockFsPromises.stat).mockResolvedValue({
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 1024,
|
||||
} as any);
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({
|
||||
path: '/test',
|
||||
sortBy: 'name',
|
||||
sortOrder: 'desc',
|
||||
});
|
||||
|
||||
expect(result.files.map((r) => r.name)).toEqual(['zebra.txt', 'middle.txt', 'alpha.txt']);
|
||||
});
|
||||
|
||||
it('should sort by size descending when specified', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['small.txt', 'large.txt', 'medium.txt']);
|
||||
vi.mocked(mockFsPromises.stat).mockImplementation(async (filePath) => {
|
||||
const name = (filePath as string).split('/').pop();
|
||||
const sizes: Record<string, number> = {
|
||||
'large.txt': 10000,
|
||||
'medium.txt': 5000,
|
||||
'small.txt': 1000,
|
||||
};
|
||||
return {
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: sizes[name!] || 1024,
|
||||
} as any;
|
||||
});
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({
|
||||
path: '/test',
|
||||
sortBy: 'size',
|
||||
sortOrder: 'desc',
|
||||
});
|
||||
|
||||
expect(result.files.map((r) => r.name)).toEqual(['large.txt', 'medium.txt', 'small.txt']);
|
||||
});
|
||||
|
||||
it('should sort by modifiedTime ascending when specified', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['old.txt', 'new.txt', 'mid.txt']);
|
||||
vi.mocked(mockFsPromises.stat).mockImplementation(async (filePath) => {
|
||||
const name = (filePath as string).split('/').pop();
|
||||
const dates: Record<string, Date> = {
|
||||
'new.txt': new Date('2024-01-20'),
|
||||
'mid.txt': new Date('2024-01-15'),
|
||||
'old.txt': new Date('2024-01-01'),
|
||||
};
|
||||
return {
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: dates[name!] || new Date('2024-01-01'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 1024,
|
||||
} as any;
|
||||
});
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({
|
||||
path: '/test',
|
||||
sortBy: 'modifiedTime',
|
||||
sortOrder: 'asc',
|
||||
});
|
||||
|
||||
expect(result.files.map((r) => r.name)).toEqual(['old.txt', 'mid.txt', 'new.txt']);
|
||||
});
|
||||
|
||||
it('should handle empty directory with sort options', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue([]);
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({
|
||||
path: '/empty',
|
||||
sortBy: 'name',
|
||||
sortOrder: 'asc',
|
||||
});
|
||||
|
||||
expect(result.files).toEqual([]);
|
||||
expect(result.totalCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should apply limit after sorting', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue([
|
||||
'file1.txt',
|
||||
'file2.txt',
|
||||
'file3.txt',
|
||||
'file4.txt',
|
||||
'file5.txt',
|
||||
]);
|
||||
vi.mocked(mockFsPromises.stat).mockImplementation(async (filePath) => {
|
||||
const name = (filePath as string).split('/').pop();
|
||||
const dates: Record<string, Date> = {
|
||||
'file1.txt': new Date('2024-01-01'),
|
||||
'file2.txt': new Date('2024-01-02'),
|
||||
'file3.txt': new Date('2024-01-03'),
|
||||
'file4.txt': new Date('2024-01-04'),
|
||||
'file5.txt': new Date('2024-01-05'),
|
||||
};
|
||||
return {
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: dates[name!] || new Date('2024-01-01'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 1024,
|
||||
} as any;
|
||||
});
|
||||
|
||||
// Sort by modifiedTime desc (default) and limit to 3
|
||||
const result = await localFileCtr.listLocalFiles({
|
||||
path: '/test',
|
||||
limit: 3,
|
||||
});
|
||||
|
||||
// Should get the 3 newest files
|
||||
expect(result.files).toHaveLength(3);
|
||||
expect(result.totalCount).toBe(5); // Total is 5, but limited to 3
|
||||
expect(result.files.map((r) => r.name)).toEqual(['file5.txt', 'file4.txt', 'file3.txt']);
|
||||
});
|
||||
|
||||
it('should handle limit larger than file count', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['file1.txt', 'file2.txt']);
|
||||
vi.mocked(mockFsPromises.stat).mockResolvedValue({
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 1024,
|
||||
} as any);
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({
|
||||
path: '/test',
|
||||
limit: 1000,
|
||||
});
|
||||
|
||||
expect(result.files).toHaveLength(2);
|
||||
expect(result.totalCount).toBe(2);
|
||||
});
|
||||
|
||||
it('should return file metadata including size, times and type', async () => {
|
||||
const createdTime = new Date('2024-01-01');
|
||||
const modifiedTime = new Date('2024-01-15');
|
||||
const accessTime = new Date('2024-01-20');
|
||||
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['document.pdf']);
|
||||
vi.mocked(mockFsPromises.stat).mockResolvedValue({
|
||||
isDirectory: () => false,
|
||||
birthtime: createdTime,
|
||||
mtime: modifiedTime,
|
||||
atime: accessTime,
|
||||
size: 2048,
|
||||
} as any);
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({ path: '/test' });
|
||||
|
||||
expect(result.files).toHaveLength(1);
|
||||
expect(result.totalCount).toBe(1);
|
||||
expect(result.files[0]).toEqual({
|
||||
name: 'document.pdf',
|
||||
path: '/test/document.pdf',
|
||||
isDirectory: false,
|
||||
size: 2048,
|
||||
type: 'pdf',
|
||||
createdTime,
|
||||
modifiedTime,
|
||||
lastAccessTime: accessTime,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return empty result when directory read fails', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockRejectedValue(new Error('Permission denied'));
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({ path: '/protected' });
|
||||
|
||||
expect(result.files).toEqual([]);
|
||||
expect(result.totalCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should skip files that cannot be stat', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['good.txt', 'bad.txt']);
|
||||
vi.mocked(mockFsPromises.stat).mockImplementation(async (filePath) => {
|
||||
if ((filePath as string).includes('bad.txt')) {
|
||||
throw new Error('Cannot stat file');
|
||||
}
|
||||
return {
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 1024,
|
||||
} as any;
|
||||
});
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({ path: '/test' });
|
||||
|
||||
// Should only contain good.txt, bad.txt should be skipped
|
||||
expect(result.files).toHaveLength(1);
|
||||
expect(result.totalCount).toBe(1);
|
||||
expect(result.files[0].name).toBe('good.txt');
|
||||
});
|
||||
|
||||
it('should handle directory type correctly', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['my_folder']);
|
||||
vi.mocked(mockFsPromises.stat).mockResolvedValue({
|
||||
isDirectory: () => true,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 4096,
|
||||
} as any);
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({ path: '/test' });
|
||||
|
||||
expect(result.files).toHaveLength(1);
|
||||
expect(result.totalCount).toBe(1);
|
||||
expect(result.files[0].isDirectory).toBe(true);
|
||||
expect(result.files[0].type).toBe('directory');
|
||||
});
|
||||
|
||||
it('should handle files without extension', async () => {
|
||||
vi.mocked(mockFsPromises.readdir).mockResolvedValue(['Makefile', 'README']);
|
||||
vi.mocked(mockFsPromises.stat).mockResolvedValue({
|
||||
isDirectory: () => false,
|
||||
birthtime: new Date('2024-01-01'),
|
||||
mtime: new Date('2024-01-15'),
|
||||
atime: new Date('2024-01-20'),
|
||||
size: 512,
|
||||
} as any);
|
||||
|
||||
const result = await localFileCtr.listLocalFiles({ path: '/test' });
|
||||
|
||||
expect(result.files).toHaveLength(2);
|
||||
expect(result.totalCount).toBe(2);
|
||||
// Files without extension should have empty type
|
||||
expect(result.files[0].type).toBe('');
|
||||
expect(result.files[1].type).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleGrepContent', () => {
|
||||
it('should search content in a single file', async () => {
|
||||
vi.mocked(mockFsPromises.stat).mockResolvedValue({
|
||||
|
||||
@@ -1,4 +1,72 @@
|
||||
[
|
||||
{
|
||||
"children": {
|
||||
"improvements": ["Improve local-system tool implement."]
|
||||
},
|
||||
"date": "2026-02-01",
|
||||
"version": "2.1.6"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Slove the group member agents cant set skills problem."]
|
||||
},
|
||||
"date": "2026-01-31",
|
||||
"version": "2.1.5"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"improvements": ["Update i18n, Update Kimi K2.5 & Qwen3 Max Thinking models."]
|
||||
},
|
||||
"date": "2026-01-31",
|
||||
"version": "2.1.4"
|
||||
},
|
||||
{
|
||||
"children": {},
|
||||
"date": "2026-01-31",
|
||||
"version": "2.1.3"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Fix feishu sso provider."]
|
||||
},
|
||||
"date": "2026-01-30",
|
||||
"version": "2.1.2"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Correct desktop download URL path."]
|
||||
},
|
||||
"date": "2026-01-30",
|
||||
"version": "2.1.1"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"features": ["Refactor cron job UI and use runtime enableBusinessFeatures flag."]
|
||||
},
|
||||
"date": "2026-01-30",
|
||||
"version": "2.1.0"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"improvements": ["Fix usage table display issues."]
|
||||
},
|
||||
"date": "2026-01-29",
|
||||
"version": "2.0.13"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Group publish to market should set local group market identifer."]
|
||||
},
|
||||
"date": "2026-01-29",
|
||||
"version": "2.0.12"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"improvements": ["Fix group task render."]
|
||||
},
|
||||
"date": "2026-01-29",
|
||||
"version": "2.0.11"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Add ExtendParamsTypeSchema for enhanced model settings."]
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# Proxy, if you need it
|
||||
# HTTP_PROXY=http://localhost:7890
|
||||
# HTTPS_PROXY=http://localhost:7890
|
||||
|
||||
# Allowed email addresses for login, separated by commas
|
||||
# When set, only emails in the list can log in, other users cannot log in
|
||||
# Leave empty to allow all users to register
|
||||
# AUTH_ALLOWED_EMAILS=user1@example.com,user2@example.com
|
||||
|
||||
# Disable user registration (SSO-only mode)
|
||||
# When set to 1, users cannot register via email/password, only SSO login is allowed
|
||||
# AUTH_DISABLE_EMAIL_PASSWORD=1
|
||||
|
||||
# ===========================
|
||||
# ====== Preset config ======
|
||||
# ===========================
|
||||
# if no special requirements, no need to change
|
||||
LOBE_PORT=3210
|
||||
RUSTFS_PORT=9000
|
||||
APP_URL=http://localhost:3210
|
||||
# INTERNAL_APP_URL is optional, used for server-to-server calls
|
||||
# to bypass CDN/proxy. If not set, defaults to APP_URL.
|
||||
# Example: INTERNAL_APP_URL=http://localhost:3210
|
||||
|
||||
# Postgres related, which are the necessary environment variables for DB
|
||||
LOBE_DB_NAME=lobechat
|
||||
POSTGRES_PASSWORD=uWNZugjBqixf8dxC
|
||||
|
||||
# RUSTFS S3 configuration
|
||||
RUSTFS_ACCESS_KEY=admin
|
||||
RUSTFS_SECRET_KEY=YOUR_RUSTFS_PASSWORD
|
||||
|
||||
# Configure the bucket information of RUSTFS
|
||||
S3_ENDPOINT=http://localhost:9000
|
||||
RUSTFS_LOBE_BUCKET=lobe
|
||||
|
||||
JWKS_KEY={"keys":[{"d":"PVoFyqyrGstB8wU52S7gqqQQdZLtin_thcEM0nrNtqp9U-NlKLlhgEcWp5t89ycgvhsAzmrRbezGj4JBTr3jn7eWdwQpPJNYiipnsgeJn0pwsB0H2dMqtavxinoPVXkMTOuGHMTFhhyguFBw2JbIL0PTQUcUlXjv40OoJpYHZeggSxgfV-TuxjwW8Ll4-n84M5IOi6A53RvioE-Hm1iyIc2XLBCfyOu-SbAQYi8HzrA64kCxobAB0peLQMiAzfZmwPKiGOhnhKrAlYmG02qFnbUYiJu_-AXwsAyGv9S9i6dwK7QXaGGWYyis8LlPpd_JmPrBnrWomwDlI045NUMWZQ","dp":"OSXI2NBBZl2r0Dpf4-1z44A_jC5lOyXtJhXQYnSXy5eIuxTJcEtkUYagGEwnREO4Q3t-4J-lT_6Y71M1ZlgKG1upwfw1O4aE3vGpHOik9iZYYCjA8fe5uBfOpX1ELmOtHNoHRhMtyjuPxSFXLlSp3bgcF1f3F40ClukdvXCx0Mc","dq":"m6hNdfj-F8E_7nUlX2nG95OffkFrhHTo67ML9aPgpvFwBlzg-hk5LwtxMfUzngqWF78TMl0JDm7vS1bz0xlWqXqu8pFPoTUnUoWgYfvuyHLBwR5TgccQkfoKbkSMzYNy8VJPXZeyIjVXsW98tZvj-NZF-M9Pke_EWJm-jjXCu_8","e":"AQAB","kty":"RSA","n":"piffosMS0HOSgsSr_zQkXYaQt1kOCD73VR0b2XJD6UdQCKPbnBOzTIuA_xowX61QVsl5pCZLTw8ERC3r2Nlxj5Rp_H6RuOT7ioUqlbnxSGnfuAn8dFupY3A-sf9HVDOvtJdlS-nO9yA4wWU-A50zZ1Mf0pPZlUZE6dUQfsJFi5yXaNAybyk3U4VpMO_SXAilWEHVhiO0F0ccpJMCkT47AeXmYH9MlWwIGcay0UiAsdrs8J-q1arZ7Mbq0oxHmUXJG0vwRvAL8KnCEi8cJ3e2kKCRcr-BQCujsHUyUl6f_ATwSVuTHdAR1IzIcW37v27h3WQK_v0ffQM1NstamDX5vQ","p":"4myVm2M5cZGvVXsOmWUTUG87VC1GlQcL5tmMNSGSpQCL8yWZ1vANkmCxSMptrKB4dU9DAB3On6_oMhW1pJ3uYNGSW49BcmJoLkiWKeg5zWFnKPQNuThQmY1sCCubtKhBQgaYUr7TVzN9smrDV3zCu9MlRl-XPwnEmWaDII3g-f8","q":"u9v4IOEsb4l2Y3eWKE2bwJh5fJRR4vivaYA7U-1-OpvDwB3A48Rey9IL1ucXqE5G1Du8BtijPm5oSAar5uzrjtg1bZ9gevif6DnBGaIRE7LnSrUsTPfZwzntJ1rTaGiVe_pAdnTKXXaH6DxygXxH4wvGgA44V3TTfBXQUcjzdEM","qi":"lDBnSPKkRnYqQvbqVD1LxzqBPEeqEA3GyCqMj6fIZNgoEaBSLi0TSsUyGZ5mahX3KO35vKAZa5jvGjhvUGUiXycq8KvRZdeGK45vJdwZT2TiXiDwo9IQgJcbFMpxaB9DhjX2x0yqxgUY5ca75jLqbMuKBKBN0PVqIr9jlHkR8_s","use":"sig","kid":"6823046760c5d460","alg":"RS256"}]}
|
||||
@@ -0,0 +1,34 @@
|
||||
# Proxy,如果你需要的话(比如你使用 GitHub 作为鉴权服务提供商)
|
||||
# HTTP_PROXY=http://localhost:7890
|
||||
# HTTPS_PROXY=http://localhost:7890
|
||||
|
||||
# 允许登录的邮箱地址,用英文逗号分隔
|
||||
# 设置后只有列表中的邮箱可以登录,其他用户可以注册但无法登录
|
||||
# 留空则允许所有用户注册登录
|
||||
# AUTH_ALLOWED_EMAILS=user1@example.com,user2@example.com
|
||||
|
||||
# 禁用用户注册(仅允许 SSO 登录)
|
||||
# 设置为 1 后,用户无法通过邮箱密码注册,只能通过 SSO 登录
|
||||
# AUTH_DISABLE_EMAIL_PASSWORD=1
|
||||
|
||||
# ===================
|
||||
# ===== 预设配置 =====
|
||||
# ===================
|
||||
# 如没有特殊需要不用更改
|
||||
LOBE_PORT=3210
|
||||
RUSTFS_PORT=9000
|
||||
APP_URL=http://localhost:3210
|
||||
|
||||
# Postgres 相关,也即 DB 必须的环境变量
|
||||
LOBE_DB_NAME=lobehub
|
||||
POSTGRES_PASSWORD=uWNZugjBqixf8dxC
|
||||
|
||||
# RustFS S3 配置
|
||||
RUSTFS_ACCESS_KEY=admin
|
||||
RUSTFS_SECRET_KEY=YOUR_RUSTFS_PASSWORD
|
||||
|
||||
# 在下方配置 rustfs 中添加的桶
|
||||
S3_ENDPOINT=http://localhost:9000
|
||||
RUSTFS_LOBE_BUCKET=lobe
|
||||
|
||||
JWKS_KEY={"keys":[{"d":"PVoFyqyrGstB8wU52S7gqqQQdZLtin_thcEM0nrNtqp9U-NlKLlhgEcWp5t89ycgvhsAzmrRbezGj4JBTr3jn7eWdwQpPJNYiipnsgeJn0pwsB0H2dMqtavxinoPVXkMTOuGHMTFhhyguFBw2JbIL0PTQUcUlXjv40OoJpYHZeggSxgfV-TuxjwW8Ll4-n84M5IOi6A53RvioE-Hm1iyIc2XLBCfyOu-SbAQYi8HzrA64kCxobAB0peLQMiAzfZmwPKiGOhnhKrAlYmG02qFnbUYiJu_-AXwsAyGv9S9i6dwK7QXaGGWYyis8LlPpd_JmPrBnrWomwDlI045NUMWZQ","dp":"OSXI2NBBZl2r0Dpf4-1z44A_jC5lOyXtJhXQYnSXy5eIuxTJcEtkUYagGEwnREO4Q3t-4J-lT_6Y71M1ZlgKG1upwfw1O4aE3vGpHOik9iZYYCjA8fe5uBfOpX1ELmOtHNoHRhMtyjuPxSFXLlSp3bgcF1f3F40ClukdvXCx0Mc","dq":"m6hNdfj-F8E_7nUlX2nG95OffkFrhHTo67ML9aPgpvFwBlzg-hk5LwtxMfUzngqWF78TMl0JDm7vS1bz0xlWqXqu8pFPoTUnUoWgYfvuyHLBwR5TgccQkfoKbkSMzYNy8VJPXZeyIjVXsW98tZvj-NZF-M9Pke_EWJm-jjXCu_8","e":"AQAB","kty":"RSA","n":"piffosMS0HOSgsSr_zQkXYaQt1kOCD73VR0b2XJD6UdQCKPbnBOzTIuA_xowX61QVsl5pCZLTw8ERC3r2Nlxj5Rp_H6RuOT7ioUqlbnxSGnfuAn8dFupY3A-sf9HVDOvtJdlS-nO9yA4wWU-A50zZ1Mf0pPZlUZE6dUQfsJFi5yXaNAybyk3U4VpMO_SXAilWEHVhiO0F0ccpJMCkT47AeXmYH9MlWwIGcay0UiAsdrs8J-q1arZ7Mbq0oxHmUXJG0vwRvAL8KnCEi8cJ3e2kKCRcr-BQCujsHUyUl6f_ATwSVuTHdAR1IzIcW37v27h3WQK_v0ffQM1NstamDX5vQ","p":"4myVm2M5cZGvVXsOmWUTUG87VC1GlQcL5tmMNSGSpQCL8yWZ1vANkmCxSMptrKB4dU9DAB3On6_oMhW1pJ3uYNGSW49BcmJoLkiWKeg5zWFnKPQNuThQmY1sCCubtKhBQgaYUr7TVzN9smrDV3zCu9MlRl-XPwnEmWaDII3g-f8","q":"u9v4IOEsb4l2Y3eWKE2bwJh5fJRR4vivaYA7U-1-OpvDwB3A48Rey9IL1ucXqE5G1Du8BtijPm5oSAar5uzrjtg1bZ9gevif6DnBGaIRE7LnSrUsTPfZwzntJ1rTaGiVe_pAdnTKXXaH6DxygXxH4wvGgA44V3TTfBXQUcjzdEM","qi":"lDBnSPKkRnYqQvbqVD1LxzqBPEeqEA3GyCqMj6fIZNgoEaBSLi0TSsUyGZ5mahX3KO35vKAZa5jvGjhvUGUiXycq8KvRZdeGK45vJdwZT2TiXiDwo9IQgJcbFMpxaB9DhjX2x0yqxgUY5ca75jLqbMuKBKBN0PVqIr9jlHkR8_s","use":"sig","kid":"6823046760c5d460","alg":"RS256"}]}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"ID": "",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": ["*"]
|
||||
},
|
||||
"Action": ["s3:GetObject"],
|
||||
"NotAction": [],
|
||||
"Resource": ["arn:aws:s3:::lobe/*"],
|
||||
"NotResource": [],
|
||||
"Condition": {}
|
||||
}
|
||||
],
|
||||
"Version": "2012-10-17"
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
name: lobehub
|
||||
services:
|
||||
network-service:
|
||||
image: alpine
|
||||
container_name: lobe-network
|
||||
restart: always
|
||||
ports:
|
||||
- '${RUSTFS_PORT}:9000' # RustFS API
|
||||
- '9001:9001' # RustFS Console
|
||||
- '${LOBE_PORT}:3210' # LobeChat
|
||||
command: tail -f /dev/null
|
||||
networks:
|
||||
- lobe-network
|
||||
|
||||
postgresql:
|
||||
image: paradedb/paradedb:latest-pg17
|
||||
container_name: lobe-postgres
|
||||
ports:
|
||||
- '5432:5432'
|
||||
volumes:
|
||||
- './data:/var/lib/postgresql/data'
|
||||
environment:
|
||||
- 'POSTGRES_DB=${LOBE_DB_NAME}'
|
||||
- 'POSTGRES_PASSWORD=${POSTGRES_PASSWORD}'
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'pg_isready -U postgres']
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
restart: always
|
||||
networks:
|
||||
- lobe-network
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: lobe-redis
|
||||
ports:
|
||||
- '6379:6379'
|
||||
command: redis-server --save 60 1000 --appendonly yes
|
||||
volumes:
|
||||
- 'redis_data:/data'
|
||||
healthcheck:
|
||||
test: ['CMD', 'redis-cli', 'ping']
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
restart: always
|
||||
networks:
|
||||
- lobe-network
|
||||
|
||||
rustfs:
|
||||
image: rustfs/rustfs:latest
|
||||
container_name: lobe-rustfs
|
||||
network_mode: 'service:network-service'
|
||||
environment:
|
||||
- RUSTFS_CONSOLE_ENABLE=true
|
||||
- RUSTFS_ACCESS_KEY=${RUSTFS_ACCESS_KEY}
|
||||
- RUSTFS_SECRET_KEY=${RUSTFS_SECRET_KEY}
|
||||
volumes:
|
||||
- rustfs-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://localhost:9000/health >/dev/null 2>&1 || exit 1"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 30
|
||||
command: ["--access-key","${RUSTFS_ACCESS_KEY}","--secret-key","${RUSTFS_SECRET_KEY}","/data"]
|
||||
|
||||
rustfs-init:
|
||||
image: minio/mc:latest
|
||||
container_name: lobe-rustfs-init
|
||||
depends_on:
|
||||
rustfs:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ./bucket.config.json:/bucket.config.json:ro
|
||||
entrypoint: /bin/sh
|
||||
command: -c '
|
||||
set -eux;
|
||||
echo "S3_ACCESS_KEY=${RUSTFS_ACCESS_KEY}, S3_SECRET_KEY=${RUSTFS_SECRET_KEY}";
|
||||
mc --version;
|
||||
mc alias set rustfs "http://network-service:9000" "${RUSTFS_ACCESS_KEY}" "${RUSTFS_SECRET_KEY}";
|
||||
mc ls rustfs || true;
|
||||
mc mb "rustfs/lobe" --ignore-existing;
|
||||
mc admin info rustfs || true;
|
||||
mc anonymous set-json "/bucket.config.json" "rustfs/lobe";
|
||||
'
|
||||
restart: "no"
|
||||
networks:
|
||||
- lobe-network
|
||||
|
||||
searxng:
|
||||
image: searxng/searxng
|
||||
container_name: lobe-searxng
|
||||
volumes:
|
||||
- './searxng-settings.yml:/etc/searxng/settings.yml'
|
||||
environment:
|
||||
- 'SEARXNG_SETTINGS_FILE=/etc/searxng/settings.yml'
|
||||
restart: always
|
||||
networks:
|
||||
- lobe-network
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
lobe:
|
||||
image: lobehub/lobehub
|
||||
container_name: lobehub
|
||||
network_mode: 'service:network-service'
|
||||
depends_on:
|
||||
postgresql:
|
||||
condition: service_healthy
|
||||
network-service:
|
||||
condition: service_started
|
||||
rustfs:
|
||||
condition: service_healthy
|
||||
rustfs-init:
|
||||
condition: service_completed_successfully
|
||||
redis:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- 'KEY_VAULTS_SECRET=Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ='
|
||||
- 'AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg'
|
||||
- 'DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgresql:5432/${LOBE_DB_NAME}'
|
||||
- 'S3_BUCKET=${RUSTFS_LOBE_BUCKET}'
|
||||
- 'S3_ENABLE_PATH_STYLE=1'
|
||||
- 'S3_ACCESS_KEY=${RUSTFS_ACCESS_KEY}'
|
||||
- 'S3_ACCESS_KEY_ID=${RUSTFS_ACCESS_KEY}'
|
||||
- 'S3_SECRET_ACCESS_KEY=${RUSTFS_SECRET_KEY}'
|
||||
- 'LLM_VISION_IMAGE_USE_BASE64=1'
|
||||
- 'S3_SET_ACL=0'
|
||||
- 'SEARXNG_URL=http://searxng:8080'
|
||||
- 'REDIS_URL=redis://redis:6379'
|
||||
- 'REDIS_PREFIX=lobechat'
|
||||
- 'REDIS_TLS=0'
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
rustfs-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
lobe-network:
|
||||
driver: bridge
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,7 +37,6 @@ RUSTFS_ACCESS_KEY=admin
|
||||
RUSTFS_SECRET_KEY=YOUR_RUSTFS_PASSWORD
|
||||
|
||||
# Configure the bucket information of RUSTFS
|
||||
S3_PUBLIC_DOMAIN=http://localhost:9000
|
||||
S3_ENDPOINT=http://localhost:9000
|
||||
RUSTFS_LOBE_BUCKET=lobe
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ RUSTFS_ACCESS_KEY=admin
|
||||
RUSTFS_SECRET_KEY=YOUR_RUSTFS_PASSWORD
|
||||
|
||||
# 在下方配置 rustfs 中添加的桶
|
||||
S3_PUBLIC_DOMAIN=http://localhost:9000
|
||||
S3_ENDPOINT=http://localhost:9000
|
||||
RUSTFS_LOBE_BUCKET=lobe
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ MINIO_ROOT_USER=admin
|
||||
MINIO_ROOT_PASSWORD=YOUR_MINIO_PASSWORD
|
||||
|
||||
# Configure the bucket information of MinIO
|
||||
S3_PUBLIC_DOMAIN=http://localhost:9000
|
||||
S3_ENDPOINT=http://localhost:9000
|
||||
MINIO_LOBE_BUCKET=lobe
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ MINIO_ROOT_USER=admin
|
||||
MINIO_ROOT_PASSWORD=YOUR_MINIO_PASSWORD
|
||||
|
||||
# 在下方配置 minio 中添加的桶
|
||||
S3_PUBLIC_DOMAIN=http://localhost:9000
|
||||
S3_ENDPOINT=http://localhost:9000
|
||||
MINIO_LOBE_BUCKET=lobe
|
||||
|
||||
|
||||
@@ -103,7 +103,6 @@ services:
|
||||
- 'DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgresql:5432/${LOBE_DB_NAME}'
|
||||
- 'S3_ENDPOINT=http://localhost:${MINIO_PORT}'
|
||||
- 'S3_BUCKET=${MINIO_LOBE_BUCKET}'
|
||||
- 'S3_PUBLIC_DOMAIN=http://localhost:${MINIO_PORT}'
|
||||
- 'S3_ENABLE_PATH_STYLE=1'
|
||||
- 'REDIS_URL=redis://redis:6379'
|
||||
- 'REDIS_PREFIX=lobechat'
|
||||
|
||||
@@ -21,8 +21,7 @@ AUTH_ZITADEL_ISSUER=http://localhost:8080
|
||||
S3_ACCESS_KEY_ID=
|
||||
S3_SECRET_ACCESS_KEY=
|
||||
S3_ENDPOINT=http://localhost:9000
|
||||
S3_BUCKET=lobe
|
||||
S3_PUBLIC_DOMAIN=http://localhost:9000
|
||||
S3_BUCKET=lobe
|
||||
S3_ENABLE_PATH_STYLE=1
|
||||
LLM_VISION_IMAGE_USE_BASE64=1
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@ AUTH_ZITADEL_ISSUER=http://localhost:8080
|
||||
S3_ACCESS_KEY_ID=
|
||||
S3_SECRET_ACCESS_KEY=
|
||||
S3_ENDPOINT=http://localhost:9000
|
||||
S3_BUCKET=lobe
|
||||
S3_PUBLIC_DOMAIN=http://localhost:9000
|
||||
S3_BUCKET=lobe
|
||||
S3_ENABLE_PATH_STYLE=1
|
||||
LLM_VISION_IMAGE_USE_BASE64=1
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ MINIO_ROOT_USER=admin
|
||||
MINIO_ROOT_PASSWORD=YOUR_MINIO_PASSWORD
|
||||
|
||||
# Configure the bucket information of MinIO
|
||||
S3_PUBLIC_DOMAIN=http://localhost:9000
|
||||
S3_ENDPOINT=http://localhost:9000
|
||||
MINIO_LOBE_BUCKET=lobe
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ MINIO_ROOT_USER=admin
|
||||
MINIO_ROOT_PASSWORD=YOUR_MINIO_PASSWORD
|
||||
|
||||
# 在下方配置 minio 中添加的桶
|
||||
S3_PUBLIC_DOMAIN=http://localhost:9000
|
||||
S3_ENDPOINT=http://localhost:9000
|
||||
MINIO_LOBE_BUCKET=lobe
|
||||
|
||||
|
||||
@@ -38,8 +38,6 @@ S3_SECRET_ACCESS_KEY=YOUR_S3_SECRET_ACCESS_KEY
|
||||
S3_ENDPOINT=https://lobe-s3-api.example.com
|
||||
# Required: S3 Bucket (invalid until manually created in MinIO UI)
|
||||
S3_BUCKET=lobe
|
||||
# Required: S3 Public Domain for client access to unstructured data
|
||||
S3_PUBLIC_DOMAIN=https://lobe-s3-api.example.com
|
||||
# Optional: S3 Enable Path Style
|
||||
# Use 0 for mainstream S3 cloud providers; use 1 for self-hosted MinIO
|
||||
# See: https://lobehub.com/docs/self-hosting/advanced/s3#s-3-enable-path-style
|
||||
|
||||
@@ -38,8 +38,6 @@ S3_SECRET_ACCESS_KEY=YOUR_S3_SECRET_ACCESS_KEY
|
||||
S3_ENDPOINT=https://lobe-s3-api.example.com
|
||||
# 必填,S3 的 Bucket,直到在 MinIO UI 中手动创建之前都是无效的
|
||||
S3_BUCKET=lobe
|
||||
# 必填,S3 的 Public Domain,用于客户端通过公开连接访问非结构化数据
|
||||
S3_PUBLIC_DOMAIN=https://lobe-s3-api.example.com
|
||||
# 选填,S3 的 Enable Path Style
|
||||
# 对于主流 S3 Cloud 服务商,一般填 0 即可;对于自部署的 MinIO,请填 1
|
||||
# 请参考:https://lobehub.com/zh/docs/self-hosting/advanced/s3#s-3-enable-path-style
|
||||
|
||||
@@ -35,8 +35,6 @@ S3_SECRET_ACCESS_KEY=YOUR_S3_SECRET_ACCESS_KEY
|
||||
S3_ENDPOINT=https://lobe-s3-api.example.com
|
||||
# Required: S3 Bucket (invalid until manually created in MinIO UI)
|
||||
S3_BUCKET=lobe
|
||||
# Required: S3 Public Domain for client access to unstructured data
|
||||
S3_PUBLIC_DOMAIN=https://lobe-s3-api.example.com
|
||||
# Optional: S3 Enable Path Style
|
||||
# Use 0 for mainstream S3 cloud providers; use 1 for self-hosted MinIO
|
||||
# See: https://lobehub.com/docs/self-hosting/advanced/s3#s-3-enable-path-style
|
||||
|
||||
@@ -31,8 +31,6 @@ S3_SECRET_ACCESS_KEY=YOUR_S3_SECRET_ACCESS_KEY
|
||||
S3_ENDPOINT=https://lobe-s3-api.example.com
|
||||
# 必填,S3 的 Bucket,直到在 MinIO UI 中手动创建之前都是无效的
|
||||
S3_BUCKET=lobe
|
||||
# 必填,S3 的 Public Domain,用于客户端通过公开连接访问非结构化数据
|
||||
S3_PUBLIC_DOMAIN=https://lobe-s3-api.example.com
|
||||
# 选填,S3 的 Enable Path Style
|
||||
# 对于主流 S3 Cloud 服务商,一般填 0 即可;对于自部署的 MinIO,请填 1
|
||||
# 请参考:https://lobehub.com/zh/docs/self-hosting/advanced/s3#s-3-enable-path-style
|
||||
|
||||
+53
-90
@@ -230,6 +230,20 @@ show_message() {
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
tips_disable_registration)
|
||||
case $LANGUAGE in
|
||||
zh_CN)
|
||||
echo "如需限制用户注册,可在 .env 中配置:"
|
||||
echo " - 使用 SSO 登录时,设置 AUTH_DISABLE_EMAIL_PASSWORD=1 可禁用邮箱密码注册"
|
||||
echo " - 使用邮箱密码登录时,设置 AUTH_ALLOWED_EMAILS=user1@example.com,user2@example.com 可限制允许登录的邮箱"
|
||||
;;
|
||||
*)
|
||||
echo "To restrict user registration, configure in .env:"
|
||||
echo " - For SSO login: set AUTH_DISABLE_EMAIL_PASSWORD=1 to disable email/password registration"
|
||||
echo " - For email/password login: set AUTH_ALLOWED_EMAILS=user1@example.com,user2@example.com to allow specific emails"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
tips_show_documentation)
|
||||
case $LANGUAGE in
|
||||
zh_CN)
|
||||
@@ -263,10 +277,10 @@ show_message() {
|
||||
tips_allow_ports)
|
||||
case $LANGUAGE in
|
||||
zh_CN)
|
||||
echo "请确保服务器以下端口未被占用且能被访问:3210, 9000, 9001, 8000"
|
||||
echo "请确保服务器以下端口未被占用且能被访问:3210, 9000, 9001"
|
||||
;;
|
||||
*)
|
||||
echo "Please make sure the following ports on the server are not occupied and can be accessed: 3210, 9000, 9001, 8000"
|
||||
echo "Please make sure the following ports on the server are not occupied and can be accessed: 3210, 9000, 9001"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
@@ -315,12 +329,10 @@ show_message() {
|
||||
tips_init_database_failed)
|
||||
case $LANGUAGE in
|
||||
zh_CN)
|
||||
echo "无法初始化数据库,为了避免你的数据重复初始化,请在首次成功启动时运行以下指令清空 Casdoor 初始配置文件:"
|
||||
echo "echo '{}' > init_data.json"
|
||||
echo "无法初始化数据库"
|
||||
;;
|
||||
*)
|
||||
echo "Failed to initialize the database. To avoid your data being initialized repeatedly, run the following command to unmount the initial configuration file of Casdoor when you first start successfully:"
|
||||
echo "echo '{}' > init_data.json"
|
||||
echo "Failed to initialize the database."
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
@@ -338,7 +350,7 @@ show_message() {
|
||||
case $LANGUAGE in
|
||||
zh_CN)
|
||||
echo "请选择部署模式:"
|
||||
echo "(0) 域名模式(访问时无需指明端口),需要使用反向代理服务 LobeHub, RustFS, Casdoor ,并分别分配一个域名;"
|
||||
echo "(0) 域名模式(访问时无需指明端口),需要使用反向代理服务 LobeHub, RustFS,并分别分配一个域名;"
|
||||
echo "(1) 端口模式(访问时需要指明端口,如使用IP访问,或域名+端口访问),需要放开指定端口;"
|
||||
echo "(2) 本地模式(仅供本地测试使用)"
|
||||
echo "如果你对这些内容疑惑,可以先选择使用本地模式进行部署,稍后根据文档指引再进行修改。"
|
||||
@@ -346,7 +358,7 @@ show_message() {
|
||||
;;
|
||||
*)
|
||||
echo "Please select the deployment mode:"
|
||||
echo "(0) Domain mode (no need to specify the port when accessing), you need to use the reverse proxy service LobeHub, RustFS, Casdoor, and assign a domain name respectively;"
|
||||
echo "(0) Domain mode (no need to specify the port when accessing), you need to use the reverse proxy service LobeHub, RustFS, and assign a domain name respectively;"
|
||||
echo "(1) Port mode (need to specify the port when accessing, such as using IP access, or domain name + port access), you need to open the specified port;"
|
||||
echo "(2) Local mode (for local testing only)"
|
||||
echo "If you are confused about these contents, you can choose to deploy in local mode first, and then modify according to the document guide later."
|
||||
@@ -408,31 +420,33 @@ download_file() {
|
||||
}
|
||||
|
||||
print_centered() {
|
||||
# Define colors
|
||||
declare -A colors
|
||||
colors=(
|
||||
[black]="\e[30m"
|
||||
[red]="\e[31m"
|
||||
[green]="\e[32m"
|
||||
[yellow]="\e[33m"
|
||||
[blue]="\e[34m"
|
||||
[magenta]="\e[35m"
|
||||
[cyan]="\e[36m"
|
||||
[white]="\e[37m"
|
||||
[reset]="\e[0m"
|
||||
)
|
||||
local text="$1" # Get input texts
|
||||
local color="${2:-reset}" # Get color, default to reset
|
||||
local term_width=$(tput cols) # Get terminal width
|
||||
local text_length=${#text} # Get text length
|
||||
local padding=$(((term_width - text_length) / 2)) # Get padding
|
||||
# Check if the color is valid
|
||||
if [[ -z "${colors[$color]}" ]]; then
|
||||
echo "Invalid color specified. Available colors: ${!colors[@]}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get color code (compatible with bash 3.x)
|
||||
local color_code=""
|
||||
local reset_code="\e[0m"
|
||||
case "$color" in
|
||||
black) color_code="\e[30m" ;;
|
||||
red) color_code="\e[31m" ;;
|
||||
green) color_code="\e[32m" ;;
|
||||
yellow) color_code="\e[33m" ;;
|
||||
blue) color_code="\e[34m" ;;
|
||||
magenta) color_code="\e[35m" ;;
|
||||
cyan) color_code="\e[36m" ;;
|
||||
white) color_code="\e[37m" ;;
|
||||
reset) color_code="\e[0m" ;;
|
||||
*)
|
||||
echo "Invalid color specified. Available colors: black red green yellow blue magenta cyan white reset"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Print the text with padding
|
||||
printf "%*s${colors[$color]}%s${colors[reset]}\n" $padding "" "$text"
|
||||
printf "%*s${color_code}%s${reset_code}\n" $padding "" "$text"
|
||||
}
|
||||
|
||||
# Usage:
|
||||
@@ -469,10 +483,9 @@ ask() {
|
||||
# == Variables ==
|
||||
# ===============
|
||||
# File list
|
||||
SUB_DIR="docker-compose/local"
|
||||
SUB_DIR="docker-compose/deploy"
|
||||
FILES=(
|
||||
"$SUB_DIR/docker-compose.yml"
|
||||
"$SUB_DIR/init_data.json"
|
||||
"$SUB_DIR/searxng-settings.yml"
|
||||
"$SUB_DIR/bucket.config.json"
|
||||
)
|
||||
@@ -481,10 +494,7 @@ ENV_EXAMPLES=(
|
||||
"$SUB_DIR/.env.example"
|
||||
)
|
||||
# Default values
|
||||
CASDOOR_PASSWORD="pswd123"
|
||||
CASDOOR_SECRET="CASDOOR_SECRET"
|
||||
RUSTFS_SECRET_KEY="YOUR_RUSTFS_PASSWORD"
|
||||
CASDOOR_HOST="localhost:8000"
|
||||
RUSTFS_HOST="localhost:9000"
|
||||
PROTOCOL="http"
|
||||
|
||||
@@ -514,9 +524,8 @@ section_download_files(){
|
||||
fi
|
||||
|
||||
download_file "$SOURCE_URL/${FILES[0]}" "docker-compose.yml"
|
||||
download_file "$SOURCE_URL/${FILES[1]}" "init_data.json"
|
||||
download_file "$SOURCE_URL/${FILES[2]}" "searxng-settings.yml"
|
||||
download_file "$SOURCE_URL/${FILES[3]}" "bucket.config.json"
|
||||
download_file "$SOURCE_URL/${FILES[1]}" "searxng-settings.yml"
|
||||
download_file "$SOURCE_URL/${FILES[2]}" "bucket.config.json"
|
||||
# Download .env.example with the specified language
|
||||
if [ "$LANGUAGE" = "zh_CN" ]; then
|
||||
download_file "$SOURCE_URL/${ENV_EXAMPLES[0]}" ".env"
|
||||
@@ -576,15 +585,10 @@ section_configurate_host() {
|
||||
echo "LobeHub" $(show_message "ask_domain" "example.com")
|
||||
ask "(example.com)"
|
||||
LOBE_HOST="$ask_result"
|
||||
# If user use domain mode, ask for the domain of RustFS and Casdoor
|
||||
# If user use domain mode, ask for the domain of RustFS
|
||||
echo "RustFS S3 API" $(show_message "ask_domain" "s3.example.com")
|
||||
ask "(s3.example.com)"
|
||||
RUSTFS_HOST="$ask_result"
|
||||
echo "Casdoor API" $(show_message "ask_domain" "auth.example.com")
|
||||
ask "(auth.example.com)"
|
||||
CASDOOR_HOST="$ask_result"
|
||||
# Setup callback url for Casdoor
|
||||
sed "${SED_INPLACE_ARGS[@]}" "s/"example.com"/${LOBE_HOST}/" init_data.json
|
||||
;;
|
||||
1)
|
||||
DEPLOY_MODE="ip"
|
||||
@@ -595,23 +599,16 @@ section_configurate_host() {
|
||||
# If user use ip mode, append the port to the host
|
||||
LOBE_HOST="${HOST}:3210"
|
||||
RUSTFS_HOST="${HOST}:9000"
|
||||
CASDOOR_HOST="${HOST}:8000"
|
||||
# Setup callback url for Casdoor
|
||||
sed "${SED_INPLACE_ARGS[@]}" "s/"localhost:3210"/${LOBE_HOST}/" init_data.json
|
||||
;;
|
||||
*)
|
||||
echo "Invalid deploy mode: $ask_result"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
# lobe host
|
||||
sed "${SED_INPLACE_ARGS[@]}" "s#^APP_URL=.*#APP_URL=$PROTOCOL://$LOBE_HOST#" .env
|
||||
# auth related
|
||||
sed "${SED_INPLACE_ARGS[@]}" "s#^AUTH_CASDOOR_ISSUER=.*#AUTH_CASDOOR_ISSUER=$PROTOCOL://$CASDOOR_HOST#" .env
|
||||
sed "${SED_INPLACE_ARGS[@]}" "s#^origin=.*#origin=$PROTOCOL://$CASDOOR_HOST#" .env
|
||||
# s3 related
|
||||
sed "${SED_INPLACE_ARGS[@]}" "s#^S3_PUBLIC_DOMAIN=.*#S3_PUBLIC_DOMAIN=$PROTOCOL://$RUSTFS_HOST#" .env
|
||||
sed "${SED_INPLACE_ARGS[@]}" "s#^S3_ENDPOINT=.*#S3_ENDPOINT=$PROTOCOL://$RUSTFS_HOST#" .env
|
||||
|
||||
|
||||
@@ -664,37 +661,7 @@ section_regenerate_secrets() {
|
||||
exit 1
|
||||
fi
|
||||
echo $(show_message "security_secrect_regenerate")
|
||||
|
||||
# Generate CASDOOR_SECRET
|
||||
CASDOOR_SECRET=$(generate_key 32)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo $(show_message "security_secrect_regenerate_failed") "CASDOOR_SECRET"
|
||||
else
|
||||
# Search and replace the value of CASDOOR_SECRET in .env
|
||||
sed "${SED_INPLACE_ARGS[@]}" "s#^AUTH_CASDOOR_SECRET=.*#AUTH_CASDOOR_SECRET=${CASDOOR_SECRET}#" .env
|
||||
if [ $? -ne 0 ]; then
|
||||
echo $(show_message "security_secrect_regenerate_failed") "AUTH_CASDOOR_SECRET in \`.env\`"
|
||||
fi
|
||||
# replace `clientSecrect` in init_data.json
|
||||
sed "${SED_INPLACE_ARGS[@]}" "s#dbf205949d704de81b0b5b3603174e23fbecc354#${CASDOOR_SECRET}#" init_data.json
|
||||
if [ $? -ne 0 ]; then
|
||||
echo $(show_message "security_secrect_regenerate_failed") "AUTH_CASDOOR_SECRET in \`init_data.json\`"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Generate Casdoor User
|
||||
CASDOOR_USER="admin"
|
||||
CASDOOR_PASSWORD=$(generate_key 10)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo $(show_message "security_secrect_regenerate_failed") "CASDOOR_PASSWORD"
|
||||
CASDOOR_PASSWORD="pswd123"
|
||||
else
|
||||
# replace `password` in init_data.json
|
||||
sed "${SED_INPLACE_ARGS[@]}" "s/"pswd123"/${CASDOOR_PASSWORD}/" init_data.json
|
||||
if [ $? -ne 0 ]; then
|
||||
echo $(show_message "security_secrect_regenerate_failed") "CASDOOR_PASSWORD in \`init_data.json\`"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Generate RUSTFS S3 User Password
|
||||
RUSTFS_SECRET_KEY=$(generate_key 8)
|
||||
if [ $? -ne 0 ]; then
|
||||
@@ -735,13 +702,10 @@ section_init_database() {
|
||||
fi
|
||||
|
||||
docker compose pull
|
||||
docker compose up --detach postgresql casdoor
|
||||
docker compose up --detach postgresql
|
||||
# hopefully enough time for even the slower systems
|
||||
sleep 15
|
||||
docker compose stop
|
||||
|
||||
# Init finished, remove init mount
|
||||
echo '{}' > init_data.json
|
||||
}
|
||||
|
||||
show_message "ask_init_database"
|
||||
@@ -759,16 +723,14 @@ fi
|
||||
section_display_configurated_report() {
|
||||
# Display configuration reports
|
||||
echo $(show_message "security_secrect_regenerate_report")
|
||||
|
||||
echo -e "LobeHub: \n - URL: $PROTOCOL://$LOBE_HOST \n - Username: user \n - Password: ${CASDOOR_PASSWORD} "
|
||||
echo -e "Casdoor: \n - URL: $PROTOCOL://$CASDOOR_HOST \n - Username: admin \n - Password: ${CASDOOR_PASSWORD}\n"
|
||||
|
||||
echo -e "LobeHub: \n - URL: $PROTOCOL://$LOBE_HOST"
|
||||
echo -e "RustFS: \n - URL: $PROTOCOL://$RUSTFS_HOST \n - Username: admin\n - Password: ${RUSTFS_SECRET_KEY}\n"
|
||||
|
||||
|
||||
# if user run in domain mode, diplay reverse proxy configuration
|
||||
if [[ "$DEPLOY_MODE" == "domain" ]]; then
|
||||
echo $(show_message "tips_add_reverse_proxy")
|
||||
printf "\n%s\t->\t%s\n" "$LOBE_HOST" "127.0.0.1:3210"
|
||||
printf "%s\t->\t%s\n" "$CASDOOR_HOST" "127.0.0.1:8000"
|
||||
printf "%s\t->\t%s\n" "$RUSTFS_HOST" "127.0.0.1:9000"
|
||||
fi
|
||||
|
||||
@@ -777,7 +739,8 @@ section_display_configurated_report() {
|
||||
printf "\n%s\n\n" "$(show_message "tips_run_command")"
|
||||
print_centered "docker compose up --no-attach searxng" "green"
|
||||
printf "\n%s\n" "$(show_message "tips_if_run_normally")"
|
||||
printf "\n%s\n\n" "$(show_message "tips_regen_jwks")"
|
||||
printf "\n%s\n" "$(show_message "tips_regen_jwks")"
|
||||
printf "\n%s\n\n" "$(show_message "tips_disable_registration")"
|
||||
print_centered "docker compose up -d --no-attach searxng" "green"
|
||||
printf "\n%s\n" "$(show_message "tips_if_want_searxng_logs")"
|
||||
print_centered "docker compose logs -f searxng" "white"
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# Seamless DeepSeek R1 Integration, Unlock a New Chain-of-Thought Experience
|
||||
|
||||
LobeChat completed its largest AI ecosystem expansion ever in February, delivering a more powerful and flexible AI chat experience.
|
||||
LobeHub completed its largest AI ecosystem expansion ever in February, delivering a more powerful and flexible AI chat experience.
|
||||
|
||||
## 🌟 Major Updates
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# 完美集成 DeepSeek R1 ,开启思维链新体验
|
||||
|
||||
LobeChat 在二月完成了史上最大规模的 AI 生态扩展,带来更强大、更灵活的 AI 对话体验。
|
||||
LobeHub 在二月完成了史上最大规模的 AI 生态扩展,带来更强大、更灵活的 AI 对话体验。
|
||||
|
||||
## 🌟 重大更新
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# Seamless DeepSeek R1 Integration, Unlock a New Chain-of-Thought Experience
|
||||
|
||||
In March, LobeChat continued to refine the user experience—adding practical features like customizable hotkeys and data export, while further expanding the AI provider ecosystem.
|
||||
In March, LobeHub continued to refine the user experience—adding practical features like customizable hotkeys and data export, while further expanding the AI provider ecosystem.
|
||||
|
||||
## 🌟 Key Updates
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# 完美集成 DeepSeek R1 ,开启思维链新体验
|
||||
|
||||
LobeChat 在三月持续优化用户体验,新增快捷键自定义、数据导出等实用功能,并扩展 AI 服务商生态。
|
||||
LobeHub 在三月持续优化用户体验,新增快捷键自定义、数据导出等实用功能,并扩展 AI 服务商生态。
|
||||
|
||||
## 🌟 重要更新
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Brand-New Design Style and Desktop App Release ✨
|
||||
description: LobeChat officially launches the desktop app, delivering a more modern and smoother experience.
|
||||
description: LobeHub officially launches the desktop app, delivering a more modern and smoother experience.
|
||||
tags:
|
||||
- Desktop App
|
||||
- LobeHub
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# Brand-New Design Style and Desktop App Release ✨
|
||||
|
||||
In April, LobeChat shipped a major visual upgrade with the brand-new Lobe UI v2 design system, and officially released the desktop app—bringing a more modern and fluid experience.
|
||||
In April, LobeHub shipped a major visual upgrade with the brand-new Lobe UI v2 design system, and officially released the desktop app—bringing a more modern and fluid experience.
|
||||
|
||||
## 🌟 Major Updates
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 全新设计风格与桌面端发布 ✨
|
||||
description: LobeChat 正式发布桌面端应用,带来更现代、更流畅的使用体验
|
||||
description: LobeHub 正式发布桌面端应用,带来更现代、更流畅的使用体验
|
||||
tags:
|
||||
- 桌面端
|
||||
- LobeHub
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# 全新设计风格与桌面端发布 ✨
|
||||
|
||||
LobeChat 在四月完成重大视觉升级,推出全新 Lobe UI v2 设计系统,并正式发布桌面端应用,带来更现代、更流畅的使用体验。
|
||||
LobeHub 在四月完成重大视觉升级,推出全新 Lobe UI v2 设计系统,并正式发布桌面端应用,带来更现代、更流畅的使用体验。
|
||||
|
||||
## 🌟 重大更新
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# Prompt Variables and Claude 4 Reasoning Model Support 🚀
|
||||
|
||||
From May to June, LobeChat continued to refine core capabilities—introducing a prompt-variables system, adding support for Claude 4 reasoning models, and expanding search and crawling across multiple AI providers.
|
||||
From May to June, LobeHub continued to refine core capabilities—introducing a prompt-variables system, adding support for Claude 4 reasoning models, and expanding search and crawling across multiple AI providers.
|
||||
|
||||
## 🌟 Key Updates
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# 提示词变量与 Claude 4 推理模型支持 🚀
|
||||
|
||||
LobeChat 在五月至六月持续优化核心功能,新增提示词变量系统、支持 Claude 4 推理模型,并扩展多个 AI 服务商的搜索与推理能力。
|
||||
LobeHub 在五月至六月持续优化核心功能,新增提示词变量系统、支持 Claude 4 推理模型,并扩展多个 AI 服务商的搜索与推理能力。
|
||||
|
||||
## 🌟 主要更新
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# MCP Marketplace and Search Provider Expansion 🔍
|
||||
|
||||
From June to July, LobeChat launched the MCP plugin marketplace, added support for multiple search providers, and integrated Amazon Cognito and Google SSO—continuing to improve both user experience and the developer ecosystem.
|
||||
From June to July, LobeHub launched the MCP plugin marketplace, added support for multiple search providers, and integrated Amazon Cognito and Google SSO—continuing to improve both user experience and the developer ecosystem.
|
||||
|
||||
## 🌟 Major Updates
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# MCP 市场与搜索服务商扩展 🔍
|
||||
|
||||
LobeChat 在六月至七月推出 MCP 插件市场,新增多个搜索服务商支持,并集成 Amazon Cognito 与 Google SSO 认证,持续优化用户体验与开发者生态。
|
||||
LobeHub 在六月至七月推出 MCP 插件市场,新增多个搜索服务商支持,并集成 Amazon Cognito 与 Google SSO 认证,持续优化用户体验与开发者生态。
|
||||
|
||||
## 🌟 重大更新
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# AI Image Generation and Desktop Enhancements 🎨
|
||||
|
||||
From July to August, LobeChat introduced AI image generation, added support for multiple providers, and continued improving the desktop experience and authentication system.
|
||||
From July to August, LobeHub introduced AI image generation, added support for multiple providers, and continued improving the desktop experience and authentication system.
|
||||
|
||||
## 🌟 Major Updates
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# AI 图像生成与桌面端增强 🎨
|
||||
|
||||
LobeChat 在七月至八月推出 AI 图像生成功能,新增多个服务商支持,并持续优化桌面端体验与认证系统。
|
||||
LobeHub 在七月至八月推出 AI 图像生成功能,新增多个服务商支持,并持续优化桌面端体验与认证系统。
|
||||
|
||||
## 🌟 重大更新
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# Gemini Image Generation and Non-Streaming Mode Support 🎨
|
||||
|
||||
From August to September, LobeChat added Gemini 2.5 Flash Image generation, introduced non-streaming response mode support, and expanded provider and model support across the ecosystem.
|
||||
From August to September, LobeHub added Gemini 2.5 Flash Image generation, introduced non-streaming response mode support, and expanded provider and model support across the ecosystem.
|
||||
|
||||
## 🌟 Major Updates
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# Gemini 图像生成与非流式模式支持 🎨
|
||||
|
||||
LobeChat 在八月至九月新增 Gemini 2.5 Flash Image 图像生成能力,支持非流式响应模式,并扩展多个 AI 服务商与模型支持。
|
||||
LobeHub 在八月至九月新增 Gemini 2.5 Flash Image 图像生成能力,支持非流式响应模式,并扩展多个 AI 服务商与模型支持。
|
||||
|
||||
## 🌟 重大更新
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# Claude Sonnet 4.5 and Built-in Python Plugin 🐍
|
||||
|
||||
From September to October, LobeChat added support for Claude Sonnet 4.5, introduced a built-in Python plugin, and improved chat list navigation and rich text editing.
|
||||
From September to October, LobeHub added support for Claude Sonnet 4.5, introduced a built-in Python plugin, and improved chat list navigation and rich text editing.
|
||||
|
||||
## 🌟 Key Updates
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# Claude Sonnet 4.5 与内置 Python 插件 🐍
|
||||
|
||||
LobeChat 在九月至十月新增 Claude Sonnet 4.5 模型支持,推出内置 Python 插件,并优化聊天列表导航与富文本编辑体验。
|
||||
LobeHub 在九月至十月新增 Claude Sonnet 4.5 模型支持,推出内置 Python 插件,并优化聊天列表导航与富文本编辑体验。
|
||||
|
||||
## 🌟 主要更新
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# ComfyUI Integration and Knowledge Base Improvements ⭐
|
||||
|
||||
From October to November, LobeChat integrated ComfyUI workflows, added support for multiple AI providers and models, and continued to improve the knowledge base and overall user experience.
|
||||
From October to November, LobeHub integrated ComfyUI workflows, added support for multiple AI providers and models, and continued to improve the knowledge base and overall user experience.
|
||||
|
||||
## 🌟 Key Updates
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# ComfyUI 集成与知识库优化 ⭐
|
||||
|
||||
LobeChat 在十月至十一月集成 ComfyUI 工作流,新增多个 AI 服务商与模型支持,并持续优化知识库与用户体验。
|
||||
LobeHub 在十月至十一月集成 ComfyUI 工作流,新增多个 AI 服务商与模型支持,并持续优化知识库与用户体验。
|
||||
|
||||
## 🌟 重要更新
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ tags:
|
||||
|
||||
# MCP Cloud Endpoints and Model Library Expansion 🔌
|
||||
|
||||
In November, LobeChat continued to improve model support and user experience by adding multiple AI providers and enhancing knowledge base capabilities.
|
||||
In November, LobeHub continued to improve model support and user experience by adding multiple AI providers and enhancing knowledge base capabilities.
|
||||
|
||||
## 🌟 Key Updates
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ tags:
|
||||
|
||||
# MCP 云端点与模型库扩展 🔌
|
||||
|
||||
LobeChat 在十一月持续优化模型支持与用户体验,新增多个 AI 服务商,并改进知识库功能。
|
||||
LobeHub 在十一月持续优化模型支持与用户体验,新增多个 AI 服务商,并改进知识库功能。
|
||||
|
||||
## 🌟 重要更新
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ tags:
|
||||
|
||||
LobeHub 使用 [Auth.js v5](https://authjs.dev/) 作为外部身份验证服务。Auth.js 是一个开源的身份验证库,它提供了一种简单的方式来实现身份验证和授权功能。本文档将介绍如何使用 Auth.js 来实现新的身份验证方式。
|
||||
|
||||
LobeChat 使用 [Better Auth](https://www.better-auth.com) 作为身份验证服务。本文档介绍如何添加新的 SSO 身份验证提供商。
|
||||
LobeHub 使用 [Better Auth](https://www.better-auth.com) 作为身份验证服务。本文档介绍如何添加新的 SSO 身份验证提供商。
|
||||
|
||||
为了在 LobeHub 中添加新的身份验证提供者(例如添加 Okta),你需要完成以下步骤:
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ tags:
|
||||
|
||||
# Adding New Image Models
|
||||
|
||||
> Learn more about the AI image generation modal design in the [AI Image Generation Modal Design Discussion](https://github.com/lobehub/lobe-chat/discussions/7442)
|
||||
> Learn more about the AI image generation modal design in the [AI Image Generation Modal Design Discussion](https://github.com/lobehub/lobehub/discussions/7442)
|
||||
|
||||
## Parameter Standardization
|
||||
|
||||
@@ -65,7 +65,7 @@ For image generation models that are not compatible with OpenAI format, you need
|
||||
|
||||
### Method 1: Using OpenAI Compatible Factory
|
||||
|
||||
Most Providers use `openaiCompatibleFactory` for OpenAI compatibility. You can pass in a custom `createImage` function (reference [PR #8534](https://github.com/lobehub/lobe-chat/pull/8534)).
|
||||
Most Providers use `openaiCompatibleFactory` for OpenAI compatibility. You can pass in a custom `createImage` function (reference [PR #8534](https://github.com/lobehub/lobehub/pull/8534)).
|
||||
|
||||
**Implementation Steps**:
|
||||
|
||||
@@ -124,7 +124,7 @@ export const LobeProviderAI = openaiCompatibleFactory({
|
||||
|
||||
### Method 2: Direct Implementation in Provider Class
|
||||
|
||||
If your Provider has an independent class implementation, you can directly add the `createImage` method in the class (reference [PR #8503](https://github.com/lobehub/lobe-chat/pull/8503)).
|
||||
If your Provider has an independent class implementation, you can directly add the `createImage` method in the class (reference [PR #8503](https://github.com/lobehub/lobehub/pull/8503)).
|
||||
|
||||
**Implementation Steps**:
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ tags:
|
||||
|
||||
# 添加新的图像模型
|
||||
|
||||
> 了解更多关于 AI 绘画模态的设计,请参考 [AI 绘画模态设计讨论](https://github.com/lobehub/lobe-chat/discussions/7442)
|
||||
> 了解更多关于 AI 绘画模态的设计,请参考 [AI 绘画模态设计讨论](https://github.com/lobehub/lobehub/discussions/7442)
|
||||
|
||||
## 参数标准化
|
||||
|
||||
@@ -63,7 +63,7 @@ const zhipuImageModels: AIImageModelCard[] = [
|
||||
|
||||
### 方式一:使用 OpenAI Compatible Factory
|
||||
|
||||
大部分 Provider 都使用 `openaiCompatibleFactory` 来兼容 OpenAI,可以通过传入自定义的 `createImage` 函数(参考 [PR #8534](https://github.com/lobehub/lobe-chat/pull/8534))。
|
||||
大部分 Provider 都使用 `openaiCompatibleFactory` 来兼容 OpenAI,可以通过传入自定义的 `createImage` 函数(参考 [PR #8534](https://github.com/lobehub/lobehub/pull/8534))。
|
||||
|
||||
**实现步骤**:
|
||||
|
||||
@@ -122,7 +122,7 @@ export const LobeProviderAI = openaiCompatibleFactory({
|
||||
|
||||
### 方式二:在 Provider 类中直接实现
|
||||
|
||||
如果你的 Provider 有独立的类实现,可以直接在类中添加 `createImage` 方法(参考 [PR #8503](https://github.com/lobehub/lobe-chat/pull/8503))。
|
||||
如果你的 Provider 有独立的类实现,可以直接在类中添加 `createImage` 方法(参考 [PR #8503](https://github.com/lobehub/lobehub/pull/8503))。
|
||||
|
||||
**实现步骤**:
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
---
|
||||
title: Lobe Chat API Client-Server Interaction Logic
|
||||
title: LobeHub API Client-Server Interaction Logic
|
||||
description: >-
|
||||
Explore the client-server interaction logic of Lobe Chat API, including event
|
||||
Explore the client-server interaction logic of LobeHub API, including event
|
||||
sequences.
|
||||
tags:
|
||||
- Lobe Chat API
|
||||
- LobeHub API
|
||||
- Client-Server Interaction
|
||||
- Event Sequences
|
||||
- API Logic
|
||||
---
|
||||
|
||||
# Lobe Chat API Client-Server Interaction Logic
|
||||
# LobeHub API Client-Server Interaction Logic
|
||||
|
||||
This document explains the implementation logic of Lobe Chat API in client-server interactions, including event sequences and core components involved.
|
||||
This document explains the implementation logic of LobeHub API in client-server interactions, including event sequences and core components involved.
|
||||
|
||||
## Interaction Sequence Diagram
|
||||
|
||||
@@ -201,7 +201,7 @@ sequenceDiagram
|
||||
|
||||
## AgentRuntime Overview
|
||||
|
||||
AgentRuntime is a core abstraction layer in Lobe Chat that encapsulates a unified interface for interacting with different AI model providers. Its main responsibilities and features include:
|
||||
AgentRuntime is a core abstraction layer in LobeHub that encapsulates a unified interface for interacting with different AI model providers. Its main responsibilities and features include:
|
||||
|
||||
1. **Unified Abstraction Layer**: AgentRuntime provides a unified interface that hides the implementation details and differences between various AI provider APIs (such as OpenAI, Anthropic, Bedrock, etc.).
|
||||
|
||||
@@ -244,7 +244,7 @@ AgentRuntime is a core abstraction layer in Lobe Chat that encapsulates a unifie
|
||||
|
||||
**Adapter Implementation Examples**:
|
||||
|
||||
1. **OpenRouter Adapter**: OpenRouter is a unified API that allows access to AI models from multiple providers. Lobe Chat implements support for OpenRouter through an adapter:
|
||||
1. **OpenRouter Adapter**: OpenRouter is a unified API that allows access to AI models from multiple providers. LobeHub implements support for OpenRouter through an adapter:
|
||||
|
||||
```ts
|
||||
// OpenRouter adapter implementation
|
||||
@@ -258,7 +258,7 @@ AgentRuntime is a core abstraction layer in Lobe Chat that encapsulates a unifie
|
||||
apiKey: options.apiKey,
|
||||
baseURL: OPENROUTER_BASE_URL,
|
||||
defaultHeaders: {
|
||||
'HTTP-Referer': 'https://github.com/lobehub/lobe-chat',
|
||||
'HTTP-Referer': 'https://github.com/lobehub/lobehub',
|
||||
'X-Title': 'LobeHub',
|
||||
},
|
||||
});
|
||||
@@ -267,7 +267,7 @@ AgentRuntime is a core abstraction layer in Lobe Chat that encapsulates a unifie
|
||||
|
||||
// Implement chat functionality
|
||||
async chat(payload: ChatCompletionCreateParamsBase, options?: RequestOptions) {
|
||||
// Convert Lobe Chat request format to OpenRouter format
|
||||
// Convert LobeHub request format to OpenRouter format
|
||||
// Handle model mapping, message format, etc.
|
||||
return this.client.chat.completions.create(
|
||||
{
|
||||
@@ -282,7 +282,7 @@ AgentRuntime is a core abstraction layer in Lobe Chat that encapsulates a unifie
|
||||
}
|
||||
```
|
||||
|
||||
2. **Google Gemini Adapter**: Gemini is Google's large language model. Lobe Chat supports Gemini series models through a dedicated adapter:
|
||||
2. **Google Gemini Adapter**: Gemini is Google's large language model. LobeHub supports Gemini series models through a dedicated adapter:
|
||||
|
||||
```ts
|
||||
import { GoogleGenerativeAI } from '@google/generative-ai';
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
---
|
||||
title: Lobe Chat API 前后端交互逻辑
|
||||
description: 深入了解 Lobe Chat API 的前后端交互实现逻辑和核心组件。
|
||||
title: LobeHub API 前后端交互逻辑
|
||||
description: 深入了解 LobeHub API 的前后端交互实现逻辑和核心组件。
|
||||
tags:
|
||||
- Lobe Chat API
|
||||
- LobeHub API
|
||||
- 前后端交互
|
||||
- 事件序列
|
||||
- 核心组件
|
||||
---
|
||||
|
||||
# Lobe Chat API 前后端交互逻辑
|
||||
# LobeHub API 前后端交互逻辑
|
||||
|
||||
本文档说明了 Lobe Chat API 在前后端交互中的实现逻辑,包括事件序列和涉及的核心组件。
|
||||
本文档说明了 LobeHub API 在前后端交互中的实现逻辑,包括事件序列和涉及的核心组件。
|
||||
|
||||
## 交互时序图
|
||||
|
||||
@@ -199,7 +199,7 @@ sequenceDiagram
|
||||
|
||||
## AgentRuntime 说明
|
||||
|
||||
AgentRuntime 是 Lobe Chat 中的一个核心抽象层,它封装了与不同 AI 模型提供商交互的统一接口。其主要职责和特点包括:
|
||||
AgentRuntime 是 LobeHub 中的一个核心抽象层,它封装了与不同 AI 模型提供商交互的统一接口。其主要职责和特点包括:
|
||||
|
||||
1. **统一抽象层**:AgentRuntime 提供了一个统一的接口,隐藏了不同 AI 提供商 API 的实现细节差异(如 OpenAI、Anthropic、Bedrock 等)。
|
||||
|
||||
@@ -242,7 +242,7 @@ AgentRuntime 是 Lobe Chat 中的一个核心抽象层,它封装了与不同 A
|
||||
|
||||
**适配器实现示例**:
|
||||
|
||||
1. **OpenRouter 适配器**:OpenRouter 是一个统一 API,可以通过它访问多个模型提供商的 AI 模型。Lobe Chat 通过适配器实现对 OpenRouter 的支持:
|
||||
1. **OpenRouter 适配器**:OpenRouter 是一个统一 API,可以通过它访问多个模型提供商的 AI 模型。LobeHub 通过适配器实现对 OpenRouter 的支持:
|
||||
|
||||
```ts
|
||||
// OpenRouter 适配器实现
|
||||
@@ -256,7 +256,7 @@ AgentRuntime 是 Lobe Chat 中的一个核心抽象层,它封装了与不同 A
|
||||
apiKey: options.apiKey,
|
||||
baseURL: OPENROUTER_BASE_URL,
|
||||
defaultHeaders: {
|
||||
'HTTP-Referer': 'https://github.com/lobehub/lobe-chat',
|
||||
'HTTP-Referer': 'https://github.com/lobehub/lobehub',
|
||||
'X-Title': 'LobeHub',
|
||||
},
|
||||
});
|
||||
@@ -265,7 +265,7 @@ AgentRuntime 是 Lobe Chat 中的一个核心抽象层,它封装了与不同 A
|
||||
|
||||
// 实现聊天功能
|
||||
async chat(payload: ChatCompletionCreateParamsBase, options?: RequestOptions) {
|
||||
// 将 Lobe Chat 的请求格式转换为 OpenRouter 格式
|
||||
// 将 LobeHub 的请求格式转换为 OpenRouter 格式
|
||||
// 处理模型映射、消息格式等
|
||||
return this.client.chat.completions.create(
|
||||
{
|
||||
@@ -280,7 +280,7 @@ AgentRuntime 是 Lobe Chat 中的一个核心抽象层,它封装了与不同 A
|
||||
}
|
||||
```
|
||||
|
||||
2. **Google Gemini 适配器**:Gemini 是 Google 的大语言模型,Lobe Chat 通过专门的适配器支持 Gemini 系列模型:
|
||||
2. **Google Gemini 适配器**:Gemini 是 Google 的大语言模型,LobeHub 通过专门的适配器支持 Gemini 系列模型:
|
||||
|
||||
```ts
|
||||
import { GoogleGenerativeAI } from '@google/generative-ai';
|
||||
|
||||
@@ -13,11 +13,11 @@ tags:
|
||||
|
||||
This document aims to guide developers on how to develop a complete feature in LobeHub.
|
||||
|
||||
We will use [RFC 021 - Custom Assistant Opening Guidance](https://github.com/lobehub/lobe-chat/discussions/891) as an example to illustrate the complete implementation process.
|
||||
We will use [RFC 021 - Custom Assistant Opening Guidance](https://github.com/lobehub/lobehub/discussions/891) as an example to illustrate the complete implementation process.
|
||||
|
||||
## 1. Update Schema
|
||||
|
||||
lobe-chat uses a postgres database, with the browser-side local database using [pglite](https://pglite.dev/) (wasm version of postgres). The project also uses [drizzle](https://orm.drizzle.team/) ORM to operate the database.
|
||||
lobehub uses a postgres database, with the browser-side local database using [pglite](https://pglite.dev/) (wasm version of postgres). The project also uses [drizzle](https://orm.drizzle.team/) ORM to operate the database.
|
||||
|
||||
Compared to the old solution where the browser side used indexDB, having both the browser side and server side use postgres has the advantage that the model layer code can be completely reused.
|
||||
|
||||
@@ -160,7 +160,7 @@ Foreseeably, the frontend will add two inputs, calling updateSessionConfig upon
|
||||
|
||||
### Data Flow Store Implementation
|
||||
|
||||
lobe-chat uses [zustand](https://zustand.docs.pmnd.rs/getting-started/introduction) as the global state management framework. For detailed practices on state management, you can refer to [📘 State Management Best Practices](/docs/development/state-management/state-management-intro).
|
||||
lobehub uses [zustand](https://zustand.docs.pmnd.rs/getting-started/introduction) as the global state management framework. For detailed practices on state management, you can refer to [📘 State Management Best Practices](/docs/development/state-management/state-management-intro).
|
||||
|
||||
There are two stores related to the agent:
|
||||
|
||||
@@ -254,7 +254,7 @@ We're adding a new category of settings this time. In `src/features/AgentSetting
|
||||
- [@ant-design/icons](https://ant.design/components/icon-cn) and [lucide](https://lucide.dev/icons/): icon libraries
|
||||
- [react-i18next](https://github.com/i18next/react-i18next) and [lobe-i18n](https://github.com/lobehub/lobe-cli-toolbox/tree/master/packages/lobe-i18n): i18n framework and multi-language automatic translation tool
|
||||
|
||||
lobe-chat is an internationalized project, so newly added text needs to update the default `locale` file: `src/locales/default/setting.ts`.
|
||||
lobehub is an internationalized project, so newly added text needs to update the default `locale` file: `src/locales/default/setting.ts`.
|
||||
|
||||
Let's take the subcomponent `OpeningQuestion.tsx` as an example. Component implementation:
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@ tags:
|
||||
|
||||
本文档旨在指导开发者了解如何在 LobeHub 中开发一块完整的功能需求。
|
||||
|
||||
我们将以 [RFC 021 - 自定义助手开场引导](https://github.com/lobehub/lobe-chat/discussions/891) 为例,阐述完整的实现流程。
|
||||
我们将以 [RFC 021 - 自定义助手开场引导](https://github.com/lobehub/lobehub/discussions/891) 为例,阐述完整的实现流程。
|
||||
|
||||
## 一、更新 schema
|
||||
|
||||
lobe-chat 使用 postgres 数据库,浏览器端本地数据库使用 [pglite](https://pglite.dev/)(wasm 版本 postgres)。项目还使用了 [drizzle](https://orm.drizzle.team/) ORM 用来操作数据库。
|
||||
lobehub 使用 postgres 数据库,浏览器端本地数据库使用 [pglite](https://pglite.dev/)(wasm 版本 postgres)。项目还使用了 [drizzle](https://orm.drizzle.team/) ORM 用来操作数据库。
|
||||
|
||||
相比旧方案浏览器端使用 indexDB 来说,浏览器端和 server 端都使用 postgres 好处在于 model 层代码可以完全复用。
|
||||
|
||||
@@ -159,7 +159,7 @@ export const sessionRouter = router({
|
||||
|
||||
### 数据流 store 实现
|
||||
|
||||
lobe-chat 使用 [zustand](https://zustand.docs.pmnd.rs/getting-started/introduction) 作为全局状态管理框架,对于状态管理的详细实践介绍,可以查阅 [📘 状态管理最佳实践](/zh/docs/development/state-management/state-management-intro)。
|
||||
lobehub 使用 [zustand](https://zustand.docs.pmnd.rs/getting-started/introduction) 作为全局状态管理框架,对于状态管理的详细实践介绍,可以查阅 [📘 状态管理最佳实践](/zh/docs/development/state-management/state-management-intro)。
|
||||
|
||||
和 agent 相关的 store 有两个:
|
||||
|
||||
@@ -253,7 +253,7 @@ export const agentSelectors = {
|
||||
- [@ant-design/icons](https://ant.design/components/icon-cn) 和 [lucide](https://lucide.dev/icons/): 图标库
|
||||
- [react-i18next](https://github.com/i18next/react-i18next) 和 [lobe-i18n](https://github.com/lobehub/lobe-cli-toolbox/tree/master/packages/lobe-i18n) :i18n 框架和多语言自动翻译工具
|
||||
|
||||
lobe-chat 是个国际化项目,新加的文案需要更新默认的 `locale` 文件: `src/locales/default/setting.ts` 。
|
||||
lobehub 是个国际化项目,新加的文案需要更新默认的 `locale` 文件: `src/locales/default/setting.ts` 。
|
||||
|
||||
我们以子组件 `OpeningQuestion.tsx` 为例,组件实现:
|
||||
|
||||
|
||||
@@ -17,20 +17,29 @@ The directory structure of LobeHub is as follows:
|
||||
|
||||
```bash
|
||||
src
|
||||
├── app # Next.js App Router implementation with route groups and API routes
|
||||
├── components # Reusable UI components
|
||||
├── config # Application configuration files, including client-side and server-side environment variables
|
||||
├── features # Function modules related to business functions, such as agent settings, plugin development pop-ups, etc.
|
||||
├── hooks # Custom utility hooks reused throughout the application
|
||||
├── layout # Application layout components, such as navigation bars, sidebars, etc.
|
||||
├── libs # Third-party integrations (analytics, OIDC, etc.)
|
||||
├── locales # Internationalization language files
|
||||
├── server # Server-side modules and services
|
||||
├── services # Encapsulated backend service interfaces, such as HTTP requests
|
||||
├── store # Zustand store for state management
|
||||
├── styles # Global styles and CSS-in-JS configurations
|
||||
├── types # TypeScript type definition files
|
||||
└── utils # Common utility functions
|
||||
├── app # Next.js App Router implementation with route groups and API routes
|
||||
├── business # Business logic modules (client and server)
|
||||
├── components # Reusable UI components
|
||||
├── config # Application configuration files, including client-side and server-side environment variables
|
||||
├── const # Application constants and enums
|
||||
├── envs # Environment variable definitions and validation (analytics, auth, llm, etc.)
|
||||
├── features # Function modules related to business functions, such as agent settings, plugin development pop-ups, etc.
|
||||
├── helpers # Utility helpers for tool engineering, placeholder parsing, etc.
|
||||
├── hooks # Custom utility hooks reused throughout the application
|
||||
├── layout # Application layout components, such as navigation bars, sidebars, etc.
|
||||
├── libs # Third-party integrations (analytics, OIDC, etc.)
|
||||
├── locales # Internationalization language files
|
||||
├── server # Server-side modules and services
|
||||
├── services # Encapsulated backend service interfaces, such as HTTP requests
|
||||
├── store # Zustand store for state management
|
||||
├── styles # Global styles and CSS-in-JS configurations
|
||||
├── tools # Built-in tools (artifacts, inspectors, interventions, etc.)
|
||||
├── types # TypeScript type definition files
|
||||
├── utils # Common utility functions
|
||||
├── auth.ts # Authentication configuration (Better Auth)
|
||||
├── instrumentation.ts # Application monitoring and telemetry setup
|
||||
├── instrumentation.node.ts # Node.js-specific instrumentation
|
||||
└── proxy.ts # Next.js middleware proxy configuration
|
||||
```
|
||||
|
||||
## app
|
||||
|
||||
@@ -15,20 +15,29 @@ LobeHub 的文件夹目录架构如下:
|
||||
|
||||
```bash
|
||||
src
|
||||
├── app # Next.js App Router 实现,包含路由组和 API 路由
|
||||
├── components # 可复用的 UI 组件
|
||||
├── config # 应用的配置文件,包含客户端环境变量与服务端环境变量
|
||||
├── features # 与业务功能相关的功能模块,如 Agent 设置、插件开发弹窗等
|
||||
├── hooks # 全应用复用自定义的工具 Hooks
|
||||
├── layout # 应用的布局组件,如导航栏、侧边栏等
|
||||
├── libs # 第三方集成(分析、OIDC 等)
|
||||
├── locales # 国际化的语言文件
|
||||
├── server # 服务端模块和服务
|
||||
├── services # 封装的后端服务接口,如 HTTP 请求
|
||||
├── store # 用于状态管理的 zustand store
|
||||
├── styles # 全局样式和 CSS-in-JS 配置
|
||||
├── types # TypeScript 的类型定义文件
|
||||
└── utils # 通用的工具函数
|
||||
├── app # Next.js App Router 实现,包含路由组和 API 路由
|
||||
├── business # 业务逻辑模块(客户端和服务端)
|
||||
├── components # 可复用的 UI 组件
|
||||
├── config # 应用的配置文件,包含客户端环境变量与服务端环境变量
|
||||
├── const # 应用常量和枚举
|
||||
├── envs # 环境变量定义和校验(分析、认证、LLM 等)
|
||||
├── features # 与业务功能相关的功能模块,如 Agent 设置、插件开发弹窗等
|
||||
├── helpers # 工具辅助函数,用于工具工程、占位符解析等
|
||||
├── hooks # 全应用复用自定义的工具 Hooks
|
||||
├── layout # 应用的布局组件,如导航栏、侧边栏等
|
||||
├── libs # 第三方集成(分析、OIDC 等)
|
||||
├── locales # 国际化的语言文件
|
||||
├── server # 服务端模块和服务
|
||||
├── services # 封装的后端服务接口,如 HTTP 请求
|
||||
├── store # 用于状态管理的 zustand store
|
||||
├── styles # 全局样式和 CSS-in-JS 配置
|
||||
├── tools # 内置工具(artifacts、inspectors、interventions 等)
|
||||
├── types # TypeScript 的类型定义文件
|
||||
├── utils # 通用的工具函数
|
||||
├── auth.ts # 认证配置(Better Auth)
|
||||
├── instrumentation.ts # 应用监控和遥测设置
|
||||
├── instrumentation.node.ts # Node.js 专用的 instrumentation
|
||||
└── proxy.ts # Next.js 中间件代理配置
|
||||
```
|
||||
|
||||
## app
|
||||
|
||||
@@ -39,7 +39,7 @@ First, you need to install the following software:
|
||||
|
||||
### VSCode Users
|
||||
|
||||
We recommend installing the extensions listed in [.vscode/extensions.json](https://github.com/lobehub/lobe-chat/blob/main/.vscode/extensions.json) for the best development experience.
|
||||
We recommend installing the extensions listed in [.vscode/extensions.json](https://github.com/lobehub/lobehub/blob/main/.vscode/extensions.json) for the best development experience.
|
||||
|
||||
### Project Setup
|
||||
|
||||
@@ -48,13 +48,13 @@ After installing the above software, you can start setting up the LobeHub projec
|
||||
1. **Get the code**: First, you need to clone the LobeHub codebase from GitHub. Run the following command in the terminal:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/lobehub/lobe-chat.git
|
||||
git clone https://github.com/lobehub/lobehub.git
|
||||
```
|
||||
|
||||
2. **Install dependencies**: Then, navigate to the project directory and use PNPM to install the project's dependencies:
|
||||
|
||||
```bash
|
||||
cd lobe-chat
|
||||
cd lobehub
|
||||
pnpm i
|
||||
```
|
||||
|
||||
@@ -82,5 +82,5 @@ Please refer to the [Work with Server-Side Database](/docs/development/basic/wor
|
||||
|
||||
During the development process, if you encounter any issues with environment setup or have any questions about LobeHub development, feel free to ask us at any time. We look forward to seeing your contributions!
|
||||
|
||||
[codespaces-link]: https://codespaces.new/lobehub/lobe-chat
|
||||
[codespaces-link]: https://codespaces.new/lobehub/lobehub
|
||||
[codespaces-shield]: https://github.com/codespaces/badge.svg
|
||||
|
||||
@@ -35,7 +35,7 @@ tags:
|
||||
|
||||
### VSCode 用户
|
||||
|
||||
推荐安装 [.vscode/extensions.json](https://github.com/lobehub/lobe-chat/blob/main/.vscode/extensions.json) 中推荐安装的扩展获得最佳开发体验。
|
||||
推荐安装 [.vscode/extensions.json](https://github.com/lobehub/lobehub/blob/main/.vscode/extensions.json) 中推荐安装的扩展获得最佳开发体验。
|
||||
|
||||
### 项目设置
|
||||
|
||||
@@ -44,13 +44,13 @@ tags:
|
||||
1. **获取代码**:首先,你需要从 GitHub 上克隆 LobeHub 的代码库。在终端中运行以下命令:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/lobehub/lobe-chat.git
|
||||
git clone https://github.com/lobehub/lobehub.git
|
||||
```
|
||||
|
||||
2. **安装依赖**:然后,进入项目目录,并使用 `pnpm` 安装项目的依赖包:
|
||||
|
||||
```bash
|
||||
cd lobe-chat
|
||||
cd lobehub
|
||||
pnpm i
|
||||
```
|
||||
|
||||
@@ -78,5 +78,5 @@ bun run dev
|
||||
|
||||
在开发过程中,如果你在环境设置上遇到任何问题,或者有任何关于 LobeHub 开发的问题,欢迎随时向我们提问。我们期待看到你的贡献!
|
||||
|
||||
[codespaces-link]: https://codespaces.new/lobehub/lobe-chat
|
||||
[codespaces-link]: https://codespaces.new/lobehub/lobehub
|
||||
[codespaces-shield]: https://github.com/codespaces/badge.svg
|
||||
|
||||
@@ -101,7 +101,6 @@ S3_ACCESS_KEY_ID=${MINIO_ROOT_USER}
|
||||
S3_SECRET_ACCESS_KEY=${MINIO_ROOT_PASSWORD}
|
||||
S3_ENDPOINT=http://localhost:${MINIO_PORT}
|
||||
S3_BUCKET=${MINIO_LOBE_BUCKET}
|
||||
S3_PUBLIC_DOMAIN=http://localhost:${MINIO_PORT}
|
||||
S3_ENABLE_PATH_STYLE=1 # Required for MinIO
|
||||
S3_SET_ACL=0 # MinIO compatibility
|
||||
```
|
||||
|
||||
@@ -101,7 +101,6 @@ S3_ACCESS_KEY_ID=${MINIO_ROOT_USER}
|
||||
S3_SECRET_ACCESS_KEY=${MINIO_ROOT_PASSWORD}
|
||||
S3_ENDPOINT=http://localhost:${MINIO_PORT}
|
||||
S3_BUCKET=${MINIO_LOBE_BUCKET}
|
||||
S3_PUBLIC_DOMAIN=http://localhost:${MINIO_PORT}
|
||||
S3_ENABLE_PATH_STYLE=1 # MinIO 必需
|
||||
S3_SET_ACL=0 # MinIO 兼容性
|
||||
```
|
||||
|
||||
@@ -54,7 +54,7 @@ This will utilize the `lobe-i18n` tool to process the language files.
|
||||
|
||||
Once you have completed the above steps, you need to submit your changes and create a Pull Request.
|
||||
|
||||
Ensure that you follow LobeHub's contribution guidelines and provide a necessary description to explain your changes. For example, refer to a similar previous Pull Request [#759](https://github.com/lobehub/lobe-chat/pull/759).
|
||||
Ensure that you follow LobeHub's contribution guidelines and provide a necessary description to explain your changes. For example, refer to a similar previous Pull Request [#759](https://github.com/lobehub/lobehub/pull/759).
|
||||
|
||||
### Additional Information
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ npm run i18n
|
||||
|
||||
一旦你完成了上述步骤,你需要提交你的更改并创建一个 Pull Request。
|
||||
|
||||
请确保你遵循了 LobeHub 的贡献指南,并提供必要的描述来说明你的更改。例如,参考之前的类似 Pull Request [#759](https://github.com/lobehub/lobe-chat/pull/759)。
|
||||
请确保你遵循了 LobeHub 的贡献指南,并提供必要的描述来说明你的更改。例如,参考之前的类似 Pull Request [#759](https://github.com/lobehub/lobehub/pull/759)。
|
||||
|
||||
### 附加信息
|
||||
|
||||
|
||||
@@ -114,11 +114,11 @@ In this example, we demonstrate how to use `i18next` and related plugins to init
|
||||
|
||||
We have already supported a variety of languages globally through the following efforts:
|
||||
|
||||
- [✨ feat: adding Arabic Language Support #1049](https://github.com/lobehub/lobe-chat/pull/1049)
|
||||
- [🌐 style: Add Vietnamese files and add the vi-VN option in the General Settings #860](https://github.com/lobehub/lobe-chat/pull/860)
|
||||
- [🌐 style: support it-IT nl-NL and pl-PL locales #759](https://github.com/lobehub/lobe-chat/pull/759)
|
||||
- [🌐 feat(locale): Add fr-FR (#637) #645](https://github.com/lobehub/lobe-chat/pull/645)
|
||||
- [🌐 Add russian localy #137](https://github.com/lobehub/lobe-chat/pull/137)
|
||||
- [✨ feat: adding Arabic Language Support #1049](https://github.com/lobehub/lobehub/pull/1049)
|
||||
- [🌐 style: Add Vietnamese files and add the vi-VN option in the General Settings #860](https://github.com/lobehub/lobehub/pull/860)
|
||||
- [🌐 style: support it-IT nl-NL and pl-PL locales #759](https://github.com/lobehub/lobehub/pull/759)
|
||||
- [🌐 feat(locale): Add fr-FR (#637) #645](https://github.com/lobehub/lobehub/pull/645)
|
||||
- [🌐 Add russian localy #137](https://github.com/lobehub/lobehub/pull/137)
|
||||
|
||||
To add support for new languages, please refer to the detailed steps in the [New Locale Addition Guide](add-new-locale).
|
||||
|
||||
|
||||
@@ -111,11 +111,11 @@ const createI18nInstance = (lang) => {
|
||||
|
||||
我们通过以下工作,已经支持了全球多种语言:
|
||||
|
||||
- [✨ feat: adding Arabic Language Support #1049](https://github.com/lobehub/lobe-chat/pull/1049)
|
||||
- [🌐 style: Add Vietnamese files and add the vi-VN option in the General Settings #860](https://github.com/lobehub/lobe-chat/pull/860)
|
||||
- [🌐 style: support it-IT nl-NL and pl-PL locales #759](https://github.com/lobehub/lobe-chat/pull/759)
|
||||
- [🌐 feat(locale): Add fr-FR (#637) #645](https://github.com/lobehub/lobe-chat/pull/645)
|
||||
- [🌐 Add russian localy #137](https://github.com/lobehub/lobe-chat/pull/137)
|
||||
- [✨ feat: adding Arabic Language Support #1049](https://github.com/lobehub/lobehub/pull/1049)
|
||||
- [🌐 style: Add Vietnamese files and add the vi-VN option in the General Settings #860](https://github.com/lobehub/lobehub/pull/860)
|
||||
- [🌐 style: support it-IT nl-NL and pl-PL locales #759](https://github.com/lobehub/lobehub/pull/759)
|
||||
- [🌐 feat(locale): Add fr-FR (#637) #645](https://github.com/lobehub/lobehub/pull/645)
|
||||
- [🌐 Add russian localy #137](https://github.com/lobehub/lobehub/pull/137)
|
||||
|
||||
要添加新的语种支持, 详细步骤请参考:[新语种添加指南](/zh/docs/development/internationalization/add-new-locale)。
|
||||
|
||||
|
||||
@@ -29,11 +29,11 @@ tags:
|
||||
| ![][discover-desktop] | ![][discover-mobile] |
|
||||
| [⚡️ Lighthouse Report][discover-desktop-report] | [⚡️ Lighthouse Report][discover-mobile-report] |
|
||||
|
||||
[chat-desktop]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/chat/desktop/pagespeed.svg
|
||||
[chat-desktop-report]: https://lobehub.github.io/lobe-chat/lighthouse/chat/desktop/LobeHub_com_chat.html
|
||||
[chat-mobile]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/chat/mobile/pagespeed.svg
|
||||
[chat-mobile-report]: https://lobehub.github.io/lobe-chat/lighthouse/chat/mobile/LobeHub_com_chat.html
|
||||
[discover-desktop]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/discover/desktop/pagespeed.svg
|
||||
[discover-desktop-report]: https://lobehub.github.io/lobe-chat/lighthouse/discover/desktop/LobeHub_com_discover.html
|
||||
[discover-mobile]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/discover/mobile/pagespeed.svg
|
||||
[discover-mobile-report]: https://lobehub.github.io/lobe-chat/lighthouse/discover/mobile/LobeHub_com_discover.html
|
||||
[chat-desktop]: https://raw.githubusercontent.com/lobehub/lobehub/lighthouse/lighthouse/chat/desktop/pagespeed.svg
|
||||
[chat-desktop-report]: https://lobehub.github.io/lobehub/lighthouse/chat/desktop/LobeHub_com_chat.html
|
||||
[chat-mobile]: https://raw.githubusercontent.com/lobehub/lobehub/lighthouse/lighthouse/chat/mobile/pagespeed.svg
|
||||
[chat-mobile-report]: https://lobehub.github.io/lobehub/lighthouse/chat/mobile/LobeHub_com_chat.html
|
||||
[discover-desktop]: https://raw.githubusercontent.com/lobehub/lobehub/lighthouse/lighthouse/discover/desktop/pagespeed.svg
|
||||
[discover-desktop-report]: https://lobehub.github.io/lobehub/lighthouse/discover/desktop/LobeHub_com_discover.html
|
||||
[discover-mobile]: https://raw.githubusercontent.com/lobehub/lobehub/lighthouse/lighthouse/discover/mobile/pagespeed.svg
|
||||
[discover-mobile-report]: https://lobehub.github.io/lobehub/lighthouse/discover/mobile/LobeHub_com_discover.html
|
||||
|
||||
@@ -30,11 +30,11 @@ tags:
|
||||
| ![][discover-desktop] | ![][discover-mobile] |
|
||||
| [⚡️ Lighthouse Report][discover-desktop-report] | [⚡️ Lighthouse Report][discover-mobile-report] |
|
||||
|
||||
[chat-desktop]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/chat/desktop/pagespeed.svg
|
||||
[chat-desktop-report]: https://lobehub.github.io/lobe-chat/lighthouse/chat/desktop/LobeHub_com_chat.html
|
||||
[chat-mobile]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/chat/mobile/pagespeed.svg
|
||||
[chat-mobile-report]: https://lobehub.github.io/lobe-chat/lighthouse/chat/mobile/LobeHub_com_chat.html
|
||||
[discover-desktop]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/discover/desktop/pagespeed.svg
|
||||
[discover-desktop-report]: https://lobehub.github.io/lobe-chat/lighthouse/discover/desktop/LobeHub_com_discover.html
|
||||
[discover-mobile]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/discover/mobile/pagespeed.svg
|
||||
[discover-mobile-report]: https://lobehub.github.io/lobe-chat/lighthouse/discover/mobile/LobeHub_com_discover.html
|
||||
[chat-desktop]: https://raw.githubusercontent.com/lobehub/lobehub/lighthouse/lighthouse/chat/desktop/pagespeed.svg
|
||||
[chat-desktop-report]: https://lobehub.github.io/lobehub/lighthouse/chat/desktop/LobeHub_com_chat.html
|
||||
[chat-mobile]: https://raw.githubusercontent.com/lobehub/lobehub/lighthouse/lighthouse/chat/mobile/pagespeed.svg
|
||||
[chat-mobile-report]: https://lobehub.github.io/lobehub/lighthouse/chat/mobile/LobeHub_com_chat.html
|
||||
[discover-desktop]: https://raw.githubusercontent.com/lobehub/lobehub/lighthouse/lighthouse/discover/desktop/pagespeed.svg
|
||||
[discover-desktop-report]: https://lobehub.github.io/lobehub/lighthouse/discover/desktop/LobeHub_com_discover.html
|
||||
[discover-mobile]: https://raw.githubusercontent.com/lobehub/lobehub/lighthouse/lighthouse/discover/mobile/pagespeed.svg
|
||||
[discover-mobile-report]: https://lobehub.github.io/lobehub/lighthouse/discover/mobile/LobeHub_com_discover.html
|
||||
|
||||
+22
-15
@@ -34,18 +34,25 @@ The folder directory structure of LobeHub is as follows:
|
||||
|
||||
```bash
|
||||
src
|
||||
├── app # Code related to the main logic and state management of the application
|
||||
├── components # Reusable UI components
|
||||
├── config # Application configuration files, including client and server environment variables
|
||||
├── const # Used to define constants, such as action types, route names, etc.
|
||||
├── features # Business-related feature modules, such as Agent settings, plugin development pop-ups, etc.
|
||||
├── hooks # Custom utility Hooks reusable across the application
|
||||
├── layout # Application layout components, such as navigation bars, sidebars, etc.
|
||||
├── locales # Language files for internationalization
|
||||
├── services # Encapsulated backend service interfaces, such as HTTP requests
|
||||
├── store # Zustand store for state management
|
||||
├── types # TypeScript type definition files
|
||||
└── utils # General utility functions
|
||||
├── app # Next.js App Router implementation with route groups and API routes
|
||||
├── business # Business logic modules (client and server)
|
||||
├── components # Reusable UI components
|
||||
├── config # Application configuration files, including client and server environment variables
|
||||
├── const # Application constants and enums
|
||||
├── envs # Environment variable definitions and validation (analytics, auth, llm, etc.)
|
||||
├── features # Business-related feature modules, such as Agent settings, plugin development pop-ups, etc.
|
||||
├── helpers # Utility helpers for tool engineering, placeholder parsing, etc.
|
||||
├── hooks # Custom utility Hooks reusable across the application
|
||||
├── layout # Application layout components, such as navigation bars, sidebars, etc.
|
||||
├── libs # Third-party integrations (analytics, OIDC, etc.)
|
||||
├── locales # Language files for internationalization
|
||||
├── server # Server-side modules and services
|
||||
├── services # Encapsulated backend service interfaces, such as HTTP requests
|
||||
├── store # Zustand store for state management
|
||||
├── styles # Global styles and CSS-in-JS configurations
|
||||
├── tools # Built-in tools (artifacts, inspectors, interventions, etc.)
|
||||
├── types # TypeScript type definition files
|
||||
└── utils # General utility functions
|
||||
```
|
||||
|
||||
For a detailed introduction to the directory structure, see: [Folder Directory Structure](/docs/development/basic/folder-structure)
|
||||
@@ -59,13 +66,13 @@ We recommend using WebStorm as your integrated development environment (IDE).
|
||||
1. **Get the code**: Clone the LobeHub code repository locally:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/lobehub/lobe-chat.git
|
||||
git clone https://github.com/lobehub/lobehub.git
|
||||
```
|
||||
|
||||
2. **Install dependencies**: Enter the project directory and install the required dependencies:
|
||||
|
||||
```bash
|
||||
cd lobe-chat
|
||||
cd lobehub
|
||||
# If you use Bun
|
||||
bun install
|
||||
# If you use PNPM
|
||||
@@ -110,6 +117,6 @@ For a detailed guide on internationalization implementation, please refer to [In
|
||||
|
||||
To support developers in better understanding and using the technology stack of LobeHub, we provide a comprehensive list of resources and references — [LobeHub Resources and References](/docs/development/basic/resources) - Visit our maintained list of resources, including tutorials, articles, and other useful links.
|
||||
|
||||
We encourage developers to utilize these resources to deepen their learning and enhance their skills, join community discussions through [LobeHub GitHub Discussions](https://github.com/lobehub/lobe-chat/discussions) or [Discord](https://discord.com/invite/AYFPHvv2jT), ask questions, or share your experiences.
|
||||
We encourage developers to utilize these resources to deepen their learning and enhance their skills, join community discussions through [LobeHub GitHub Discussions](https://github.com/lobehub/lobehub/discussions) or [Discord](https://discord.com/invite/AYFPHvv2jT), ask questions, or share your experiences.
|
||||
|
||||
If you have any questions or need further assistance, please do not hesitate to contact us through the above channels.
|
||||
|
||||
@@ -32,18 +32,25 @@ LobeHub 的文件夹目录架构如下:
|
||||
|
||||
```bash
|
||||
src
|
||||
├── app # 应用主要逻辑和状态管理相关的代码
|
||||
├── components # 可复用的 UI 组件
|
||||
├── config # 应用的配置文件,包含客户端环境变量与服务端环境变量
|
||||
├── const # 用于定义常量,如 action 类型、路由名等
|
||||
├── features # 与业务功能相关的功能模块,如 Agent 设置、插件开发弹窗等
|
||||
├── hooks # 全应用复用自定义的工具 Hooks
|
||||
├── layout # 应用的布局组件,如导航栏、侧边栏等
|
||||
├── locales # 国际化的语言文件
|
||||
├── services # 封装的后端服务接口,如 HTTP 请求
|
||||
├── store # 用于状态管理的 zustand store
|
||||
├── types # TypeScript 的类型定义文件
|
||||
└── utils # 通用的工具函数
|
||||
├── app # Next.js App Router 实现,包含路由组和 API 路由
|
||||
├── business # 业务逻辑模块(客户端和服务端)
|
||||
├── components # 可复用的 UI 组件
|
||||
├── config # 应用的配置文件,包含客户端环境变量与服务端环境变量
|
||||
├── const # 应用常量和枚举
|
||||
├── envs # 环境变量定义和校验(分析、认证、LLM 等)
|
||||
├── features # 与业务功能相关的功能模块,如 Agent 设置、插件开发弹窗等
|
||||
├── helpers # 工具辅助函数,用于工具工程、占位符解析等
|
||||
├── hooks # 全应用复用自定义的工具 Hooks
|
||||
├── layout # 应用的布局组件,如导航栏、侧边栏等
|
||||
├── libs # 第三方集成(分析、OIDC 等)
|
||||
├── locales # 国际化的语言文件
|
||||
├── server # 服务端模块和服务
|
||||
├── services # 封装的后端服务接口,如 HTTP 请求
|
||||
├── store # 用于状态管理的 zustand store
|
||||
├── styles # 全局样式和 CSS-in-JS 配置
|
||||
├── tools # 内置工具(artifacts、inspectors、interventions 等)
|
||||
├── types # TypeScript 的类型定义文件
|
||||
└── utils # 通用的工具函数
|
||||
```
|
||||
|
||||
有关目录架构的详细介绍,详见: [文件夹目录架构](/zh/docs/development/basic/folder-structure)
|
||||
@@ -57,13 +64,13 @@ src
|
||||
1. **获取代码**:克隆 LobeHub 的代码库到本地:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/lobehub/lobe-chat.git
|
||||
git clone https://github.com/lobehub/lobehub.git
|
||||
```
|
||||
|
||||
2. **安装依赖**:进入项目目录,并安装所需依赖:
|
||||
|
||||
```bash
|
||||
cd lobe-chat
|
||||
cd lobehub
|
||||
# 如果你使用 Bun
|
||||
bun install
|
||||
# 如果你使用 PNPM
|
||||
@@ -108,6 +115,6 @@ LobeHub 采用 `i18next` 和 `lobe-i18n` 实现多语言支持,确保用户全
|
||||
|
||||
为了支持开发者更好地理解和使用 LobeHub 的技术栈,我们提供了一份详尽的资源与参考列表 —— [LobeHub 资源与参考](/zh/docs/development/basic/resources) - 访问我们维护的资源列表,包括教程、文章和其他有用的链接。
|
||||
|
||||
我们鼓励开发者利用这些资源深入学习和提升技能,通过 [LobeHub GitHub Discussions](https://github.com/lobehub/lobe-chat/discussions) 或者 [Discord](https://discord.com/invite/AYFPHvv2jT) 加入社区讨论,提出问题或分享你的经验。
|
||||
我们鼓励开发者利用这些资源深入学习和提升技能,通过 [LobeHub GitHub Discussions](https://github.com/lobehub/lobehub/discussions) 或者 [Discord](https://discord.com/invite/AYFPHvv2jT) 加入社区讨论,提出问题或分享你的经验。
|
||||
|
||||
如果你有任何疑问,或者需要进一步的帮助,请不要犹豫,请通过上述渠道与我们联系。
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
---
|
||||
title: Configuring Casdoor Authentication for LobeChat
|
||||
description: >-
|
||||
Learn how to configure Casdoor SSO for LobeChat, including creating an
|
||||
application and setting up environment variables.
|
||||
tags:
|
||||
- Casdoor
|
||||
- Authentication
|
||||
- LobeChat
|
||||
- Single Sign-On
|
||||
- OIDC
|
||||
---
|
||||
|
||||
# Configuring Casdoor Authentication
|
||||
|
||||
[Casdoor](https://casdoor.org/) is an open-source Identity Access Management (IAM) platform with web UI for SSO.
|
||||
|
||||
<Steps>
|
||||
### Create Application in Casdoor
|
||||
|
||||
1. Log in to your Casdoor admin console
|
||||
2. Go to **Applications** and click **Add**
|
||||
3. Configure the application:
|
||||
- Name: `LobeChat`
|
||||
- Organization: Select your organization
|
||||
- Redirect URLs: Add your callback URL
|
||||
|
||||
<Callout type={'info'}>
|
||||
**Callback URL Format**: `https://your-domain.com/api/auth/callback/casdoor`
|
||||
</Callout>
|
||||
|
||||
4. Save and note down the **Client ID** and **Client Secret**
|
||||
|
||||
### Get Issuer URL
|
||||
|
||||
The issuer URL is your Casdoor server URL, typically: `https://your-casdoor-domain`
|
||||
|
||||
### Configure Environment Variables
|
||||
|
||||
When deploying LobeChat, you need to configure the following environment variables:
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| ------------------------ | -------- | ----------------------------------------------------------------------------- |
|
||||
| `AUTH_SECRET` | Required | Key used to encrypt session tokens. Generate using: `openssl rand -base64 32` |
|
||||
| `AUTH_SSO_PROVIDERS` | Required | SSO provider for LobeChat. Use `casdoor` for Casdoor |
|
||||
| `AUTH_CASDOOR_ID` | Required | Client ID from Casdoor application |
|
||||
| `AUTH_CASDOOR_SECRET` | Required | Client Secret from Casdoor application |
|
||||
| `AUTH_CASDOOR_ISSUER` | Required | Casdoor server URL (e.g., `https://your-casdoor-domain`) |
|
||||
| `CASDOOR_WEBHOOK_SECRET` | Optional | Secret key for validating Webhook requests from Casdoor |
|
||||
|
||||
<Callout type={'tip'}>
|
||||
Go to [📘 Environment Variables](/docs/self-hosting/environment-variables/auth#casdoor) for detailed information on these variables.
|
||||
</Callout>
|
||||
|
||||
### Configure Webhook (Optional)
|
||||
|
||||
> Available in Casdoor `>=1.843.0`.
|
||||
|
||||
Configure Casdoor [Webhook](https://www.casdoor.org/docs/webhooks/overview#setting-up-a-webhook) to sync user data updates to LobeChat.
|
||||
|
||||
**Synced data fields**:
|
||||
|
||||
- Avatar (`avatar`)
|
||||
- Email (`email`)
|
||||
- Display name (`displayName`)
|
||||
|
||||
**Configuration steps**:
|
||||
|
||||
1. Go to **Admin Tools** -> **Webhooks** and create a Webhook
|
||||
2. Fill in the following fields:
|
||||
- URL: `https://your-domain.com/api/webhooks/casdoor`
|
||||
- Method: `POST`
|
||||
- Content Type: `application/json`
|
||||
- Headers: `casdoor-secret`: `your-webhook-secret`
|
||||
- Events: `update-user`
|
||||
3. Generate a secret at [generate-secret.vercel.app/10](https://generate-secret.vercel.app/10)
|
||||
4. Set the secret in the `CASDOOR_WEBHOOK_SECRET` environment variable
|
||||
</Steps>
|
||||
|
||||
<Callout type={'info'}>
|
||||
After successful deployment, users will be able to authenticate with Casdoor and use LobeChat.
|
||||
</Callout>
|
||||
|
||||
## Related Resources
|
||||
|
||||
- [Casdoor Documentation](https://casdoor.org/docs/overview)
|
||||
- [Casdoor Application Configuration](https://casdoor.org/docs/application/config)
|
||||
@@ -1,83 +0,0 @@
|
||||
---
|
||||
title: 在 LobeChat 中配置 Casdoor 身份验证
|
||||
description: 学习如何在 LobeChat 中配置 Casdoor SSO,包括创建应用和设置环境变量。
|
||||
tags:
|
||||
- Casdoor
|
||||
- 身份验证
|
||||
- LobeChat
|
||||
- 单点登录
|
||||
- OIDC
|
||||
---
|
||||
|
||||
# 配置 Casdoor 身份验证
|
||||
|
||||
[Casdoor](https://casdoor.org/) 是一个开源的身份访问管理 (IAM) 平台,提供 Web UI 支持单点登录。
|
||||
|
||||
<Steps>
|
||||
### 在 Casdoor 中创建应用
|
||||
|
||||
1. 登录 Casdoor 管理控制台
|
||||
2. 前往 **Applications**,点击 **Add**
|
||||
3. 配置应用:
|
||||
- Name: `LobeChat`
|
||||
- Organization: 选择你的组织
|
||||
- Redirect URLs: 添加回调 URL
|
||||
|
||||
<Callout type={'info'}>
|
||||
**回调 URL 格式**: `https://your-domain.com/api/auth/callback/casdoor`
|
||||
</Callout>
|
||||
|
||||
4. 保存并记下 **Client ID** 和 **Client Secret**
|
||||
|
||||
### 获取 Issuer URL
|
||||
|
||||
Issuer URL 是 Casdoor 服务器 URL,通常为:`https://your-casdoor-domain`
|
||||
|
||||
### 配置环境变量
|
||||
|
||||
在部署 LobeChat 时,你需要配置以下环境变量:
|
||||
|
||||
| 环境变量 | 类型 | 描述 |
|
||||
| ------------------------ | -- | ------------------------------------------------- |
|
||||
| `AUTH_SECRET` | 必选 | 用于加密会话令牌的密钥。使用以下命令生成:`openssl rand -base64 32` |
|
||||
| `AUTH_SSO_PROVIDERS` | 必选 | SSO 提供商。使用 Casdoor 请填写 `casdoor` |
|
||||
| `AUTH_CASDOOR_ID` | 必选 | Casdoor 应用的 Client ID |
|
||||
| `AUTH_CASDOOR_SECRET` | 必选 | Casdoor 应用的 Client Secret |
|
||||
| `AUTH_CASDOOR_ISSUER` | 必选 | Casdoor 服务器 URL(例如 `https://your-casdoor-domain`) |
|
||||
| `CASDOOR_WEBHOOK_SECRET` | 可选 | 用于验证 Casdoor 发送的 Webhook 请求是否合法的密钥 |
|
||||
|
||||
<Callout type={'tip'}>
|
||||
前往 [📘 环境变量](/zh/docs/self-hosting/environment-variables/auth#casdoor) 可查阅相关变量详情。
|
||||
</Callout>
|
||||
|
||||
### 配置 Webhook(可选)
|
||||
|
||||
> 在 Casdoor `>=1.843.0` 上可用。
|
||||
|
||||
配置 Casdoor 的 [Webhook](https://www.casdoor.org/docs/webhooks/overview#setting-up-a-webhook) 以便在用户信息更新时同步到 LobeChat。
|
||||
|
||||
**同步的数据字段**:
|
||||
|
||||
- 头像 (`avatar`)
|
||||
- 邮箱 (`email`)
|
||||
- 显示名称 (`displayName`)
|
||||
|
||||
**配置步骤**:
|
||||
|
||||
1. 前往 `管理工具` -> `Webhooks`,创建一个 Webhook
|
||||
2. 填写以下字段:
|
||||
- 链接:`https://your-domain.com/api/webhooks/casdoor`
|
||||
- 方法:`POST`
|
||||
- 内容类型:`application/json`
|
||||
- 协议头:`casdoor-secret`: `你的Webhook密钥`
|
||||
- 事件:`update-user`
|
||||
3. 密钥可前往 [generate-secret.vercel.app/10](https://generate-secret.vercel.app/10) 生成
|
||||
4. 将密钥填写到环境变量 `CASDOOR_WEBHOOK_SECRET`
|
||||
</Steps>
|
||||
|
||||
<Callout type={'info'}>部署成功后,用户将可以通过 Casdoor 身份认证并使用 LobeChat。</Callout>
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [Casdoor 文档](https://casdoor.org/docs/overview)
|
||||
- [Casdoor 应用配置](https://casdoor.org/docs/application/config)
|
||||
@@ -57,4 +57,4 @@ You can achieve various feature combinations using the above configuration synta
|
||||
| `commercial_hide_github` | Hides GitHub-related links in settings footer (requires commercial license). | Disabled |
|
||||
| `commercial_hide_docs` | Hides documentation and help menu including changelog, docs, and feedback (requires commercial license). | Disabled |
|
||||
|
||||
You can always check the [featureFlags](https://github.com/lobehub/lobe-chat/blob/main/src/config/featureFlags/schema.ts) to get the latest list of feature flags.
|
||||
You can always check the [featureFlags](https://github.com/lobehub/lobehub/blob/main/src/config/featureFlags/schema.ts) to get the latest list of feature flags.
|
||||
|
||||
@@ -53,4 +53,4 @@ tags:
|
||||
| `commercial_hide_github` | 隐藏设置页面底部的 GitHub 相关链接(需要商业授权)。 | 关闭 |
|
||||
| `commercial_hide_docs` | 隐藏文档和帮助菜单,包括更新日志、文档和反馈(需要商业授权)。 | 关闭 |
|
||||
|
||||
你可以随时检查 [featureFlags](https://github.com/lobehub/lobe-chat/blob/main/src/config/featureFlags/schema.ts) 以获取最新的特性标志列表。
|
||||
你可以随时检查 [featureFlags](https://github.com/lobehub/lobehub/blob/main/src/config/featureFlags/schema.ts) 以获取最新的特性标志列表。
|
||||
|
||||
@@ -22,12 +22,12 @@ LobeHub supports file upload and knowledge base management. This feature relies
|
||||
PostgreSQL is a powerful open-source relational database system, and PGVector is its extension for vector operations.
|
||||
|
||||
- **Purpose**: Store structured data and vector indexes
|
||||
- **Deployment Tip**: Use official Docker image for quick deployment
|
||||
- **Deployment Tip**: Use the ParadeDB Docker image for quick deployment with pgvector and pg\_search plugins
|
||||
|
||||
Deployment script example:
|
||||
|
||||
```
|
||||
docker run -p 5432:5432 -d --name pg -e POSTGRES_PASSWORD=mysecretpassword pgvector/pgvector:pg17
|
||||
docker run -p 5432:5432 -d --name pg -e POSTGRES_PASSWORD=mysecretpassword paradedb/paradedb:latest-pg17
|
||||
```
|
||||
|
||||
- **Note**: Ensure sufficient resources for vector operations
|
||||
|
||||
@@ -20,12 +20,12 @@ LobeHub 支持文件上传 / 知识库管理。该功能依赖于以下核心技
|
||||
PostgreSQL 是一个强大的开源关系型数据库系统,而 PGVector 是其扩展,为向量操作提供支持。
|
||||
|
||||
- **用途**:存储结构化数据和向量索引
|
||||
- **部署建议**:使用官方 Docker 镜像可以快速部署 PostgreSQL 和 PGVector
|
||||
- **部署建议**:使用 ParadeDB Docker 镜像可以快速部署包含 pgvector 和 pg\_search 插件的 PostgreSQL
|
||||
|
||||
示例部署脚本:
|
||||
|
||||
```
|
||||
docker run -p 5432:5432 -d --name pg -e POSTGRES_PASSWORD=mysecretpassword pgvector/pgvector:pg17
|
||||
docker run -p 5432:5432 -d --name pg -e POSTGRES_PASSWORD=mysecretpassword paradedb/paradedb:latest-pg17
|
||||
```
|
||||
|
||||
- **注意事项**:确保分配足够的资源以处理向量操作
|
||||
|
||||
@@ -191,7 +191,7 @@ This URL should point to a functional SearXNG instance. You can choose to self-h
|
||||
|
||||
You can find publicly available SearXNG instances in the [SearXNG instance list](https://searx.space/). Choose an instance that is fast and reliable, and then configure its URL in LobeHub.
|
||||
|
||||
> Note that the `searxng` you use must have `json` output enabled; otherwise, the `lobe-chat` call will result in an error. If self-hosting, find the `searxng` configuration file and add `json` as shown below.
|
||||
> Note that the `searxng` you use must have `json` output enabled; otherwise, the `lobehub` call will result in an error. If self-hosting, find the `searxng` configuration file and add `json` as shown below.
|
||||
|
||||
```bash
|
||||
$ vi searxng/settings.yml
|
||||
|
||||
@@ -186,7 +186,7 @@ SEARXNG_URL=https://searxng-instance.com
|
||||
|
||||
您可以在 [SearXNG 实例列表](https://searx.space/) 中找到公开可用的 SearXNG 实例。选择一个响应速度快、可靠性高的实例,然后将其 URL 配置到 LobeHub 中。
|
||||
|
||||
> 注意,使用的 `searxng` 必须开启 `json` 输出,否则 `lobe-chat` 调用会报错。如果是自托管,类似下面这样,找到 `searxng` 的配置文件,追加 `json` 即可。
|
||||
> 注意,使用的 `searxng` 必须开启 `json` 输出,否则 `lobehub` 调用会报错。如果是自托管,类似下面这样,找到 `searxng` 的配置文件,追加 `json` 即可。
|
||||
|
||||
```bash
|
||||
$ vi searxng/settings.yml
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Configure Redis Cache Service
|
||||
description: Learn how to configure Redis cache service to optimize LobeChat performance and session management.
|
||||
description: Learn how to configure Redis cache service to optimize LobeHub performance and session management.
|
||||
tags:
|
||||
- Redis
|
||||
- Cache
|
||||
@@ -10,17 +10,17 @@ tags:
|
||||
|
||||
# Configure Redis Cache Service
|
||||
|
||||
LobeChat uses Redis as a high-performance cache and session storage service to optimize system performance and manage user authentication state.
|
||||
LobeHub uses Redis as a high-performance cache and session storage service to optimize system performance and manage user authentication state.
|
||||
|
||||
<Callout type={'info'}>
|
||||
LobeChat uses the standard Redis protocol (via ioredis library), supporting any Redis
|
||||
LobeHub uses the standard Redis protocol (via ioredis library), supporting any Redis
|
||||
protocol-compatible service, including official Redis, self-hosted Redis, and cloud provider Redis
|
||||
services (such as AWS ElastiCache, Alibaba Cloud Redis, etc.).
|
||||
</Callout>
|
||||
|
||||
## Use Cases
|
||||
|
||||
Redis is used in LobeChat for the following scenarios:
|
||||
Redis is used in LobeHub for the following scenarios:
|
||||
|
||||
### Authentication Session Storage
|
||||
|
||||
@@ -57,7 +57,7 @@ Caches Agent configuration data to reduce database queries and improve response
|
||||
|
||||
### `REDIS_PREFIX`
|
||||
|
||||
The prefix for Redis keys, used to isolate LobeChat data in a shared Redis instance.
|
||||
The prefix for Redis keys, used to isolate LobeHub data in a shared Redis instance.
|
||||
|
||||
- Default: `lobechat`
|
||||
- Example: `REDIS_PREFIX=my-lobechat`
|
||||
@@ -119,7 +119,7 @@ REDIS_PREFIX=lobechat
|
||||
## Notes
|
||||
|
||||
<Callout type={'warning'}>
|
||||
Redis is an optional service. If `REDIS_URL` is not configured, LobeChat will still function
|
||||
Redis is an optional service. If `REDIS_URL` is not configured, LobeHub will still function
|
||||
normally, but will lose the caching and session management optimizations mentioned above.
|
||||
</Callout>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 配置 Redis 缓存服务
|
||||
description: 了解如何配置 Redis 缓存服务以优化 LobeChat 的性能和会话管理。
|
||||
description: 了解如何配置 Redis 缓存服务以优化 LobeHub 的性能和会话管理。
|
||||
tags:
|
||||
- Redis
|
||||
- 缓存
|
||||
@@ -10,17 +10,17 @@ tags:
|
||||
|
||||
# 配置 Redis 缓存服务
|
||||
|
||||
LobeChat 使用 Redis 作为高性能缓存和会话存储服务,用于优化系统性能和管理用户认证状态。
|
||||
LobeHub 使用 Redis 作为高性能缓存和会话存储服务,用于优化系统性能和管理用户认证状态。
|
||||
|
||||
<Callout type={'info'}>
|
||||
LobeChat 使用标准 Redis 协议(通过 ioredis 库),支持任何兼容 Redis 协议的服务,包括 Redis
|
||||
LobeHub 使用标准 Redis 协议(通过 ioredis 库),支持任何兼容 Redis 协议的服务,包括 Redis
|
||||
官方服务、自部署 Redis、以及云服务商提供的 Redis 服务(如 AWS ElastiCache、阿里云 Redis
|
||||
等)。
|
||||
</Callout>
|
||||
|
||||
## 使用场景
|
||||
|
||||
Redis 在 LobeChat 中主要用于以下场景:
|
||||
Redis 在 LobeHub 中主要用于以下场景:
|
||||
|
||||
### 认证会话存储
|
||||
|
||||
@@ -57,7 +57,7 @@ Redis 在 LobeChat 中主要用于以下场景:
|
||||
|
||||
### `REDIS_PREFIX`
|
||||
|
||||
Redis 键的前缀,用于在共享 Redis 实例中隔离 LobeChat 的数据。
|
||||
Redis 键的前缀,用于在共享 Redis 实例中隔离 LobeHub 的数据。
|
||||
|
||||
- 默认值:`lobechat`
|
||||
- 示例:`REDIS_PREFIX=my-lobechat`
|
||||
@@ -118,7 +118,7 @@ REDIS_PREFIX=lobechat
|
||||
## 注意事项
|
||||
|
||||
<Callout type={'warning'}>
|
||||
Redis 是可选服务。如果不配置 `REDIS_URL`,LobeChat 仍然可以正常运行,但会失去上述缓存和会话管理的优化功能。
|
||||
Redis 是可选服务。如果不配置 `REDIS_URL`,LobeHub 仍然可以正常运行,但会失去上述缓存和会话管理的优化功能。
|
||||
</Callout>
|
||||
|
||||
- **内存管理**:Redis 是内存数据库,请确保服务器有足够的内存
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Configuring Upstash Redis Service
|
||||
description: Step-by-step guide to configure Upstash Redis for LobeChat cache and session storage.
|
||||
description: Step-by-step guide to configure Upstash Redis for LobeHub cache and session storage.
|
||||
tags:
|
||||
- Upstash
|
||||
- Redis
|
||||
@@ -10,7 +10,7 @@ tags:
|
||||
|
||||
# Configuring Upstash Redis Service
|
||||
|
||||
[Upstash](https://upstash.com/) is a serverless Redis service that provides a free tier and pay-as-you-go pricing, making it ideal for LobeChat deployments.
|
||||
[Upstash](https://upstash.com/) is a serverless Redis service that provides a free tier and pay-as-you-go pricing, making it ideal for LobeHub deployments.
|
||||
|
||||
## Configuration Steps
|
||||
|
||||
@@ -37,7 +37,7 @@ tags:
|
||||
```
|
||||
|
||||
<Callout type={'info'}>
|
||||
Upstash uses `rediss://` (with double 's') for TLS connections. LobeChat supports this format automatically.
|
||||
Upstash uses `rediss://` (with double 's') for TLS connections. LobeHub supports this format automatically.
|
||||
</Callout>
|
||||
</Steps>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 配置 Upstash Redis 服务
|
||||
description: 详细指南:如何配置 Upstash Redis 用于 LobeChat 的缓存和会话存储。
|
||||
description: 详细指南:如何配置 Upstash Redis 用于 LobeHub 的缓存和会话存储。
|
||||
tags:
|
||||
- Upstash
|
||||
- Redis
|
||||
@@ -10,7 +10,7 @@ tags:
|
||||
|
||||
# 配置 Upstash Redis 服务
|
||||
|
||||
[Upstash](https://upstash.com/) 是一个 Serverless Redis 服务,提供免费额度和按量付费模式,非常适合 LobeChat 部署使用。
|
||||
[Upstash](https://upstash.com/) 是一个 Serverless Redis 服务,提供免费额度和按量付费模式,非常适合 LobeHub 部署使用。
|
||||
|
||||
## 配置步骤
|
||||
|
||||
@@ -37,7 +37,7 @@ tags:
|
||||
```
|
||||
|
||||
<Callout type={'info'}>
|
||||
Upstash 使用 `rediss://`(双 's')表示 TLS 连接,LobeChat 自动支持此格式。
|
||||
Upstash 使用 `rediss://`(双's')表示 TLS 连接,LobeHub 自动支持此格式。
|
||||
</Callout>
|
||||
</Steps>
|
||||
|
||||
|
||||
@@ -50,15 +50,6 @@ The best practice in this area is to use a file storage service (S3) to store im
|
||||
|
||||
Whether to set the ACL to `public-read` when uploading files. This option is enabled by default. If the service provider does not support setting individual ACLs for files (i.e., all files inherit the ACL of the storage bucket), enabling this option may cause request errors. Set `S3_SET_ACL` to `0` to disable it.
|
||||
|
||||
### `S3_PUBLIC_DOMAIN`
|
||||
|
||||
The public access domain of the storage bucket, used to access files in the storage bucket. This address needs to be **publicly readable**. The reason is that when OpenAI's gpt-4o and other vision models recognize images, OpenAI will try to download this image link on their servers. Therefore, this link must be publicly accessible. If it is a private link, OpenAI will not be able to access the image and thus will not be able to recognize the image content properly.
|
||||
|
||||
<Callout type={'warning'}>
|
||||
Additionally, since this access domain is often a separate URL, it needs to be configured to allow
|
||||
cross-origin access to the site. Otherwise, cross-origin issues will occur in the browser.
|
||||
</Callout>
|
||||
|
||||
### `S3_ENABLE_PATH_STYLE`
|
||||
|
||||
Whether to enable the `path-style` access mode of S3. This option is disabled by default. If your S3 service provider uses `path-style`, set `S3_ENABLE_PATH_STYLE` to `1` to enable it.
|
||||
|
||||
@@ -46,14 +46,6 @@ LobeHub 在 [很早以前](https://x.com/lobehub/status/1724289575672291782) 就
|
||||
|
||||
是否在上传文件时设置 ACL 为 `public-read`。该选项默认启用。如果服务商不支持为文件设置单独的 ACL(即所有文件继承存储桶的 ACL),启用此选项可能会导致请求错误,将 `S3_SET_ACL` 设置为 `0` 即可关闭。
|
||||
|
||||
### `S3_PUBLIC_DOMAIN`
|
||||
|
||||
存储桶对外的访问域名,用于访问存储桶中的文件,这个地址需要**允许互联网可读**。 原因是 OpenAI 的 gpt-4o 等视觉模型识别图片时,OpenAI 会尝试在他们的服务器中下载这个图片链接,因此这个链接必须是公开可访问的,如果是私有的链接,OpenAI 将无法访问到这个图片,进而无法正常识别到图片内容。
|
||||
|
||||
<Callout type={'warning'}>
|
||||
此外,由于该访问域名往往是一个独立的网址,因此需要配置允许站点的跨域访问,否则会在浏览器中出现跨域问题。
|
||||
</Callout>
|
||||
|
||||
### `S3_ENABLE_PATH_STYLE`
|
||||
|
||||
是否启用 S3 的 `path-style` 访问模式。此选项默认禁用。如果您的 S3 服务提供商使用 `path-style`,请将 `S3_ENABLE_PATH_STYLE` 设置为 `1` 以启用它。
|
||||
|
||||
@@ -39,8 +39,6 @@ We need to configure an S3 storage service in the server-side database to store
|
||||
S3_BUCKET=LobeHub
|
||||
# Request endpoint of the bucket (note that the path in this link includes the bucket name, which must be removed, or use the link provided on the page for applying S3 API token)
|
||||
S3_ENDPOINT=https://0b33a03b5c993fd2f453379dc36558e5.r2.cloudflarestorage.com
|
||||
# Access domain of the bucket
|
||||
S3_PUBLIC_DOMAIN=https://s3-for-LobeHub.your-domain.com
|
||||
```
|
||||
|
||||
<Callout type={'warning'}>
|
||||
@@ -118,9 +116,6 @@ S3_SECRET_ACCESS_KEY=55af75d8eb6b99f189f6a35f855336ea62cd9c4751a5cf4337c53c1d3f4
|
||||
S3_BUCKET=LobeHub
|
||||
# Bucket Request Endpoint
|
||||
S3_ENDPOINT=https://0b33a03b5c993fd2f453379dc36558e5.r2.cloudflarestorage.com
|
||||
# Public Access Domain for the Bucket
|
||||
S3_PUBLIC_DOMAIN=https://s3-dev.your-domain.com
|
||||
|
||||
# Bucket Region, such as us-west-1. Generally not required, but some service providers may need it.
|
||||
# S3_REGION=us-west-1
|
||||
```
|
||||
|
||||
@@ -40,8 +40,6 @@ tags:
|
||||
S3_BUCKET=LobeHub
|
||||
# 存储桶的请求端点(注意此处链接的路径带存储桶名称,必须删除该路径,或使用申请 S3 API token 页面所提供的链接)
|
||||
S3_ENDPOINT=https://0b33a03b5c993fd2f453379dc36558e5.r2.cloudflarestorage.com
|
||||
# 存储桶对外的访问域名
|
||||
S3_PUBLIC_DOMAIN=https://s3-for-LobeHub.your-domain.com
|
||||
```
|
||||
|
||||
<Callout type={'warning'}>`S3_ENDPOINT`必须删除其路径,否则会无法访问所上传文件</Callout>
|
||||
@@ -115,9 +113,6 @@ S3_SECRET_ACCESS_KEY=55af75d8eb6b99f189f6a35f855336ea62cd9c4751a5cf4337c53c1d3f4
|
||||
S3_BUCKET=LobeHub
|
||||
# 存储桶的请求端点
|
||||
S3_ENDPOINT=https://0b33a03b5c993fd2f453379dc36558e5.r2.cloudflarestorage.com
|
||||
# 存储桶对外的访问域名
|
||||
S3_PUBLIC_DOMAIN=https://s3-dev.your-domain.com
|
||||
|
||||
# 桶的区域,如 us-west-1,一般来说不需要添加,但某些服务商则需要配置
|
||||
# S3_REGION=us-west-1
|
||||
```
|
||||
|
||||
@@ -12,131 +12,129 @@ tags:
|
||||
We need to configure an S3-compatible storage service in the server-side database to store files.
|
||||
|
||||
<Callout type={'info'}>
|
||||
Due to recent changes in MinIO's commercial strategy, we no longer recommend MinIO as the S3 storage backend. Please migrate to open-source solutions such as [RustFS](https://rustfs.com/) or [ceph](https://ceph.io/), or to cloud providers like Tencent Cloud Object Storage or Cloudflare R2.
|
||||
Due to recent changes in MinIO's commercial strategy, we no longer recommend MinIO as the S3 storage backend. Please migrate to open-source solutions such as [RustFS](https://rustfs.com/) or [ceph](https://ceph.io/), or to cloud providers like Tencent Cloud Object Storage or Cloudflare R2.
|
||||
</Callout>
|
||||
|
||||
## Configuration Steps
|
||||
|
||||
<Steps>
|
||||
### Deploy RustFS
|
||||
### Deploy RustFS
|
||||
|
||||
First, pull the RustFS Docker image:
|
||||
First, pull the RustFS Docker image:
|
||||
|
||||
```shell
|
||||
docker pull rustfs/rustfs:latest
|
||||
```
|
||||
```shell
|
||||
docker pull rustfs/rustfs:latest
|
||||
```
|
||||
|
||||
You can inspect its version with the following command. We recommend version v1.0.0 or above:
|
||||
You can inspect its version with the following command. We recommend version v1.0.0 or above:
|
||||
|
||||
```shell
|
||||
docker inspect --format='{{index .Config.Labels "version"}}' rustfs/rustfs:latest
|
||||
```
|
||||
```shell
|
||||
docker inspect --format='{{index .Config.Labels "version"}}' rustfs/rustfs:latest
|
||||
```
|
||||
|
||||
We recommend using Docker Compose to deploy RustFS:
|
||||
We recommend using Docker Compose to deploy RustFS:
|
||||
|
||||
```yml
|
||||
services:
|
||||
rustfs:
|
||||
image: rustfs/rustfs:latest
|
||||
container_name: lobe-rustfs
|
||||
ports:
|
||||
- '9000:9000'
|
||||
- '9001:9001'
|
||||
environment:
|
||||
- RUSTFS_CONSOLE_ENABLE=true
|
||||
- RUSTFS_ACCESS_KEY=<YOUR_ACCESS_KEY>
|
||||
- RUSTFS_SECRET_KEY=<YOUR_SECRET_KEY>
|
||||
volumes:
|
||||
- rustfs-data:/data
|
||||
```yml
|
||||
services:
|
||||
rustfs:
|
||||
image: rustfs/rustfs:latest
|
||||
container_name: lobe-rustfs
|
||||
ports:
|
||||
- '9000:9000'
|
||||
- '9001:9001'
|
||||
environment:
|
||||
- RUSTFS_CONSOLE_ENABLE=true
|
||||
- RUSTFS_ACCESS_KEY=<YOUR_ACCESS_KEY>
|
||||
- RUSTFS_SECRET_KEY=<YOUR_SECRET_KEY>
|
||||
volumes:
|
||||
- rustfs-data:/data
|
||||
|
||||
volumes:
|
||||
rustfs-data:
|
||||
```
|
||||
volumes:
|
||||
rustfs-data:
|
||||
```
|
||||
|
||||
Then start RustFS:
|
||||
Then start RustFS:
|
||||
|
||||
```shell
|
||||
docker compose up -d
|
||||
```
|
||||
```shell
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Create a Bucket
|
||||
### Create a Bucket
|
||||
|
||||
Open the RustFS WebUI (`http://localhost:9001/`) and you will be redirected to the login screen. Enter the username (`RUSTFS_ACCESS_KEY` in the `docker-compose.yml`) and password (`RUSTFS_SECRET_KEY` in the same file) to sign in.
|
||||
Open the RustFS WebUI (`http://localhost:9001/`) and you will be redirected to the login screen. Enter the username (`RUSTFS_ACCESS_KEY` in the `docker-compose.yml`) and password (`RUSTFS_SECRET_KEY` in the same file) to sign in.
|
||||
|
||||
Click `Object Storage` in the left sidebar, then the `Create Bucket` button in the top-right corner to create a new bucket. This example uses the name `lobe`. Leave Versioning and Object Lock disabled (default settings).
|
||||
Click `Object Storage` in the left sidebar, then the `Create Bucket` button in the top-right corner to create a new bucket. This example uses the name `lobe`. Leave Versioning and Object Lock disabled (default settings).
|
||||
|
||||
<Image alt={"Create Bucket"} src={'https://github.com/user-attachments/assets/27c37617-a813-4de5-b0bf-c7167999c856'} />
|
||||
<Image alt={"Create Bucket"} src={'https://github.com/user-attachments/assets/27c37617-a813-4de5-b0bf-c7167999c856'} />
|
||||
|
||||
Go to the bucket and click `Settings`, choose `Custom` for the policy, and paste the following JSON to make the bucket public-read/private-write:
|
||||
Go to the bucket and click `Settings`, choose `Custom` for the policy, and paste the following JSON to make the bucket public-read/private-write:
|
||||
|
||||
```json
|
||||
{
|
||||
"ID": "",
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": [
|
||||
"*"
|
||||
]
|
||||
},
|
||||
"Action": [
|
||||
"s3:GetObject"
|
||||
],
|
||||
"NotAction": [],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::lobe/*"
|
||||
],
|
||||
"NotResource": [],
|
||||
"Condition": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
```json
|
||||
{
|
||||
"ID": "",
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": [
|
||||
"*"
|
||||
]
|
||||
},
|
||||
"Action": [
|
||||
"s3:GetObject"
|
||||
],
|
||||
"NotAction": [],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::lobe/*"
|
||||
],
|
||||
"NotResource": [],
|
||||
"Condition": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Save the settings to apply the policy.
|
||||
Save the settings to apply the policy.
|
||||
|
||||
### Configure Access Keys
|
||||
### Configure Access Keys
|
||||
|
||||
<Callout type={'warning'}>
|
||||
You can reuse the `RUSTFS_ACCESS_KEY` and `RUSTFS_SECRET_KEY` defined in the `docker-compose.yml`, but for better security we recommend creating a dedicated access key.
|
||||
</Callout>
|
||||
<Callout type={'warning'}>
|
||||
You can reuse the `RUSTFS_ACCESS_KEY` and `RUSTFS_SECRET_KEY` defined in the `docker-compose.yml`, but for better security we recommend creating a dedicated access key.
|
||||
</Callout>
|
||||
|
||||
Click `Access Key` in the left sidebar, then `Add Access Key` to create a new key. The name is arbitrary, and you can keep the default main-account policy.
|
||||
Click `Access Key` in the left sidebar, then `Add Access Key` to create a new key. The name is arbitrary, and you can keep the default main-account policy.
|
||||
|
||||
Copy the generated Access Key and Secret Key (the `Export` button lets you save the JSON locally). The English labels in the UI are confusing, but remember the shorter string is the Access Key and the longer string is the Secret Key (the exported JSON is correct).
|
||||
Copy the generated Access Key and Secret Key (the `Export` button lets you save the JSON locally). The English labels in the UI are confusing, but remember the shorter string is the Access Key and the longer string is the Secret Key (the exported JSON is correct).
|
||||
|
||||
<Image alt={"Add Key"} src={'https://github.com/user-attachments/assets/81f18b20-3918-4f77-8571-07d0c4a79aec'} />
|
||||
<Image alt={"Add Key"} src={'https://github.com/user-attachments/assets/81f18b20-3918-4f77-8571-07d0c4a79aec'} />
|
||||
|
||||
<Image alt={"Export Key"} src={'https://github.com/user-attachments/assets/4dde41ec-985b-4781-8c77-aac65555a32f'} />
|
||||
<Image alt={"Export Key"} src={'https://github.com/user-attachments/assets/4dde41ec-985b-4781-8c77-aac65555a32f'} />
|
||||
|
||||
### Configure Reverse Proxy
|
||||
### Configure Reverse Proxy
|
||||
|
||||
You also need reverse-proxy rules so that RustFS is accessible from the LAN/public internet. Map the following ports to domains:
|
||||
You also need reverse-proxy rules so that RustFS is accessible from the LAN/public internet. Map the following ports to domains:
|
||||
|
||||
| Domain | Port | Required |
|
||||
| ---------------------------- | ------ | -------- |
|
||||
| `lobe-s3-api.example.com` | `9000` | Yes |
|
||||
| `lobe-s3-ui.example.com` | `9001` | |
|
||||
| Domain | Port | Required |
|
||||
| ------------------------- | ------ | -------- |
|
||||
| `lobe-s3-api.example.com` | `9000` | Yes |
|
||||
| `lobe-s3-ui.example.com` | `9001` | |
|
||||
|
||||
After completing the reverse proxy, remember to configure the corresponding SSL certificate and enable HTTPS access.
|
||||
After completing the reverse proxy, remember to configure the corresponding SSL certificate and enable HTTPS access.
|
||||
|
||||
### Set Environment Variables
|
||||
### Set Environment Variables
|
||||
|
||||
Update the LobeChat `.env` file with the following environment variables to use RustFS as the S3 backend:
|
||||
Update the LobeHub `.env` file with the following environment variables to use RustFS as the S3 backend:
|
||||
|
||||
```shell
|
||||
# RustFS Access Key / Secret Key
|
||||
S3_ACCESS_KEY_ID=<YOUR_ACCESS_KEY>
|
||||
S3_SECRET_ACCESS_KEY=<YOUR_SECRET_KEY>
|
||||
# RustFS API endpoint
|
||||
S3_ENDPOINT=https://lobe-s3-api.example.com
|
||||
# Bucket name
|
||||
S3_BUCKET=lobe
|
||||
# Public domain for accessing the bucket
|
||||
S3_PUBLIC_DOMAIN=https://lobe-s3-api.example.com
|
||||
S3_ENABLE_PATH_STYLE=1
|
||||
```
|
||||
```shell
|
||||
# RustFS Access Key / Secret Key
|
||||
S3_ACCESS_KEY_ID=<YOUR_ACCESS_KEY>
|
||||
S3_SECRET_ACCESS_KEY=<YOUR_SECRET_KEY>
|
||||
# RustFS API endpoint
|
||||
S3_ENDPOINT=https://lobe-s3-api.example.com
|
||||
# Bucket name
|
||||
S3_BUCKET=lobe
|
||||
S3_ENABLE_PATH_STYLE=1
|
||||
```
|
||||
</Steps>
|
||||
|
||||
@@ -11,133 +11,130 @@ tags:
|
||||
|
||||
在服务端数据库中我们需要配置 S3 存储服务来存储文件。
|
||||
|
||||
|
||||
<Callout type={'info'}>
|
||||
由于近期 MinIO 的商业化策略调整,我们不再推荐使用 MinIO 作为 S3 存储服务,建议所有仍在使用 MinIO 的用户迁移至 [RustFS](https://rustfs.com/) 或者 [ceph](https://ceph.io/) 等开源的 S3 存储服务或者腾讯云对象存储、Cloudflare R2 等云服务商的 S3 存储服务。
|
||||
由于近期 MinIO 的商业化策略调整,我们不再推荐使用 MinIO 作为 S3 存储服务,建议所有仍在使用 MinIO 的用户迁移至 [RustFS](https://rustfs.com/) 或者 [ceph](https://ceph.io/) 等开源的 S3 存储服务或者腾讯云对象存储、Cloudflare R2 等云服务商的 S3 存储服务。
|
||||
</Callout>
|
||||
|
||||
## 配置步骤
|
||||
|
||||
<Steps>
|
||||
### 部署 RustFS
|
||||
### 部署 RustFS
|
||||
|
||||
首先,拉取 RustFS 的 Docker 镜像:
|
||||
首先,拉取 RustFS 的 Docker 镜像:
|
||||
|
||||
```shell
|
||||
docker pull rustfs/rustfs:latest
|
||||
```
|
||||
```shell
|
||||
docker pull rustfs/rustfs:latest
|
||||
```
|
||||
|
||||
你可以使用如下命令来查看其版本,建议使用 v1.0.0 及以上版本:
|
||||
你可以使用如下命令来查看其版本,建议使用 v1.0.0 及以上版本:
|
||||
|
||||
```shell
|
||||
docker inspect --format='{{index .Config.Labels "version"}}' rustfs/rustfs:latest
|
||||
```
|
||||
```shell
|
||||
docker inspect --format='{{index .Config.Labels "version"}}' rustfs/rustfs:latest
|
||||
```
|
||||
|
||||
我们推荐使用 Docker Compose 来部署 RustFS:
|
||||
我们推荐使用 Docker Compose 来部署 RustFS:
|
||||
|
||||
```yml
|
||||
services:
|
||||
rustfs:
|
||||
image: rustfs/rustfs:latest
|
||||
container_name: lobe-rustfs
|
||||
ports:
|
||||
- '9000:9000'
|
||||
- '9001:9001'
|
||||
environment:
|
||||
- RUSTFS_CONSOLE_ENABLE=true
|
||||
- RUSTFS_ACCESS_KEY=<YOUR_ACCESS_KEY>
|
||||
- RUSTFS_SECRET_KEY=<YOUR_SECRET_KEY>
|
||||
volumes:
|
||||
- rustfs-data:/data
|
||||
```yml
|
||||
services:
|
||||
rustfs:
|
||||
image: rustfs/rustfs:latest
|
||||
container_name: lobe-rustfs
|
||||
ports:
|
||||
- '9000:9000'
|
||||
- '9001:9001'
|
||||
environment:
|
||||
- RUSTFS_CONSOLE_ENABLE=true
|
||||
- RUSTFS_ACCESS_KEY=<YOUR_ACCESS_KEY>
|
||||
- RUSTFS_SECRET_KEY=<YOUR_SECRET_KEY>
|
||||
volumes:
|
||||
- rustfs-data:/data
|
||||
|
||||
volumes:
|
||||
rustfs-data:
|
||||
```
|
||||
volumes:
|
||||
rustfs-data:
|
||||
```
|
||||
|
||||
然后,启动 RustFS:
|
||||
然后,启动 RustFS:
|
||||
|
||||
```shell
|
||||
docker compose up -d
|
||||
```
|
||||
```shell
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 创建存储桶
|
||||
### 创建存储桶
|
||||
|
||||
访问 RustFS 的 WebUI(`http://localhost:9001/`),即可自动跳转到登录页。输入账号(上述 `docker-compose.yml` 文件中的 `RUSTFS_ACCESS_KEY`)、密码(上述 `docker-compose.yml` 文件中的 `RUSTFS_SECRET_KEY`),即可登录。
|
||||
访问 RustFS 的 WebUI(`http://localhost:9001/`),即可自动跳转到登录页。输入账号(上述 `docker-compose.yml` 文件中的 `RUSTFS_ACCESS_KEY`)、密码(上述 `docker-compose.yml` 文件中的 `RUSTFS_SECRET_KEY`),即可登录。
|
||||
|
||||
点击左侧边栏的 `对象存储` 菜单,右上角 `创建存储桶` 按钮,创建一个新的存储桶(Bucket)。创建存储桶时将指定其名称,下文以 `lobe` 为例。版本、对象锁依照默认配置不开启。
|
||||
点击左侧边栏的 `对象存储` 菜单,右上角 `创建存储桶` 按钮,创建一个新的存储桶(Bucket)。创建存储桶时将指定其名称,下文以 `lobe` 为例。版本、对象锁依照默认配置不开启。
|
||||
|
||||
<Image alt={"Create Bucket"} src={'https://github.com/user-attachments/assets/27c37617-a813-4de5-b0bf-c7167999c856'} />
|
||||
<Image alt={"Create Bucket"} src={'https://github.com/user-attachments/assets/27c37617-a813-4de5-b0bf-c7167999c856'} />
|
||||
|
||||
点击存储桶 - `配置` 按钮,选择策略为 `自定义`,然后填入如下 JSON,设置存储桶的权限为 `公有读私有写`:
|
||||
点击存储桶 - `配置` 按钮,选择策略为 `自定义`,然后填入如下 JSON,设置存储桶的权限为 `公有读私有写`:
|
||||
|
||||
```json
|
||||
{
|
||||
"ID": "",
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": [
|
||||
"*"
|
||||
]
|
||||
},
|
||||
"Action": [
|
||||
"s3:GetObject"
|
||||
],
|
||||
"NotAction": [],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::lobe/*"
|
||||
],
|
||||
"NotResource": [],
|
||||
"Condition": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
```json
|
||||
{
|
||||
"ID": "",
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": [
|
||||
"*"
|
||||
]
|
||||
},
|
||||
"Action": [
|
||||
"s3:GetObject"
|
||||
],
|
||||
"NotAction": [],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::lobe/*"
|
||||
],
|
||||
"NotResource": [],
|
||||
"Condition": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
点击保存即可。
|
||||
点击保存即可。
|
||||
|
||||
### 设置访问密钥
|
||||
### 设置访问密钥
|
||||
|
||||
<Callout type={'warning'}>
|
||||
有关这部分,你可以直接使用在 `docker-compose.yml` 文件中配置的 `RUSTFS_ACCESS_KEY` 和 `RUSTFS_SECRET_KEY`,但出于安全考虑,我们推荐你手动创建一个访问密钥。
|
||||
</Callout>
|
||||
<Callout type={'warning'}>
|
||||
有关这部分,你可以直接使用在 `docker-compose.yml` 文件中配置的 `RUSTFS_ACCESS_KEY` 和 `RUSTFS_SECRET_KEY`,但出于安全考虑,我们推荐你手动创建一个访问密钥。
|
||||
</Callout>
|
||||
|
||||
点击左侧边栏的 `访问密钥` 菜单,右上角 `添加访问密钥` 按钮,创建一个新的访问密钥(Access Key)。名称随意,按照默认配置使用主账号策略即可。
|
||||
点击左侧边栏的 `访问密钥` 菜单,右上角 `添加访问密钥` 按钮,创建一个新的访问密钥(Access Key)。名称随意,按照默认配置使用主账号策略即可。
|
||||
|
||||
记录好得到的访问密钥和密钥(你可以点击 `导出` 按钮以在本地保存)。这里 RustFS 的翻译有点迷惑,但你只需要记住上面那个短的是 `Access Key`,长的是 `Secret Key` 即可(导出的 JSON 中是对的)。
|
||||
记录好得到的访问密钥和密钥(你可以点击 `导出` 按钮以在本地保存)。这里 RustFS 的翻译有点迷惑,但你只需要记住上面那个短的是 `Access Key`,长的是 `Secret Key` 即可(导出的 JSON 中是对的)。
|
||||
|
||||
<Image alt={"Add Key"} src={'https://github.com/user-attachments/assets/81f18b20-3918-4f77-8571-07d0c4a79aec'} />
|
||||
<Image alt={"Add Key"} src={'https://github.com/user-attachments/assets/81f18b20-3918-4f77-8571-07d0c4a79aec'} />
|
||||
|
||||
<Image alt={"Export Key"} src={'https://github.com/user-attachments/assets/4dde41ec-985b-4781-8c77-aac65555a32f'} />
|
||||
<Image alt={"Export Key"} src={'https://github.com/user-attachments/assets/4dde41ec-985b-4781-8c77-aac65555a32f'} />
|
||||
|
||||
### 配置反向代理
|
||||
### 配置反向代理
|
||||
|
||||
你还需要完成反向代理配置,并确保局域网 / 公网能访问到 RustFS 的服务。请使用反向代理将以下服务端口映射到域名:
|
||||
你还需要完成反向代理配置,并确保局域网 / 公网能访问到 RustFS 的服务。请使用反向代理将以下服务端口映射到域名:
|
||||
|
||||
| 域名 | 反代端口 | 是否必选 |
|
||||
| ---------------------- | ------ | ---- |
|
||||
| `lobe-s3-api.example.com` | `9000` | 必选 |
|
||||
| `lobe-s3-ui.example.com` | `9001` | |
|
||||
| 域名 | 反代端口 | 是否必选 |
|
||||
| ------------------------- | ------ | ---- |
|
||||
| `lobe-s3-api.example.com` | `9000` | 必选 |
|
||||
| `lobe-s3-ui.example.com` | `9001` | |
|
||||
|
||||
完成反向代理后,记得配置对应的 SSL 证书,启用 HTTPS 访问。
|
||||
完成反向代理后,记得配置对应的 SSL 证书,启用 HTTPS 访问。
|
||||
|
||||
### 设置环境变量
|
||||
### 设置环境变量
|
||||
|
||||
修改 LobeChat 的 `.env` 文件,添加如下环境变量,即可完成配置,使用 RustFS 作为 S3 存储服务:
|
||||
修改 LobeHub 的 `.env` 文件,添加如下环境变量,即可完成配置,使用 RustFS 作为 S3 存储服务:
|
||||
|
||||
```shell
|
||||
# RustFS 的鉴权 Access Key / Secret Key
|
||||
S3_ACCESS_KEY_ID=<YOUR_ACCESS_KEY>
|
||||
S3_SECRET_ACCESS_KEY=<YOUR_SECRET_KEY>
|
||||
# RustFS API 的请求端点
|
||||
S3_ENDPOINT=https://lobe-s3-api.example.com
|
||||
# 存储桶的名称
|
||||
S3_BUCKET=lobe
|
||||
# 存储桶对外的访问域名
|
||||
S3_PUBLIC_DOMAIN=https://lobe-s3-api.example.com
|
||||
S3_ENABLE_PATH_STYLE=1
|
||||
```
|
||||
```shell
|
||||
# RustFS 的鉴权 Access Key / Secret Key
|
||||
S3_ACCESS_KEY_ID=<YOUR_ACCESS_KEY>
|
||||
S3_SECRET_ACCESS_KEY=<YOUR_SECRET_KEY>
|
||||
# RustFS API 的请求端点
|
||||
S3_ENDPOINT=https://lobe-s3-api.example.com
|
||||
# 存储桶的名称
|
||||
S3_BUCKET=lobe
|
||||
S3_ENABLE_PATH_STYLE=1
|
||||
```
|
||||
</Steps>
|
||||
|
||||
@@ -39,7 +39,6 @@ We need to configure S3 storage service for file storage in the server-side data
|
||||
S3_BUCKET=lobe-130xxxxxx2
|
||||
S3_ENDPOINT=https://cos.ap-chengdu.myqcloud.com
|
||||
S3_REGION=ap-chengdu
|
||||
S3_PUBLIC_DOMAIN=https://lobe-1251234567.cos.ap-chengdu.myqcloud.com
|
||||
```
|
||||
|
||||
<Callout type={'warning'}>
|
||||
|
||||
@@ -40,8 +40,6 @@ tags:
|
||||
S3_ENDPOINT=https://cos.ap-chengdu.myqcloud.com
|
||||
# 桶的区域
|
||||
S3_REGION=ap-chengdu
|
||||
# 存储桶对外的访问域名
|
||||
S3_PUBLIC_DOMAIN=https://lobe-1251234567.cos.ap-chengdu.myqcloud.com
|
||||
```
|
||||
|
||||
<Callout type={'warning'}>
|
||||
|
||||
@@ -42,11 +42,11 @@ Docker 部署版本的升级非常简单,只需要重新部署 LobeHub 的最
|
||||
<Steps>
|
||||
### 停止并删除当前运行的 LobeHub 容器
|
||||
|
||||
假设 LobeHub 容器的名称是 `lobe-chat`,使用以下指令停止并删除当前运行的 LobeHub 容器:
|
||||
假设 LobeHub 容器的名称是 `lobehub`,使用以下指令停止并删除当前运行的 LobeHub 容器:
|
||||
|
||||
```fish
|
||||
docker stop lobe-chat
|
||||
docker rm lobe-chat
|
||||
docker stop lobehub
|
||||
docker rm lobehub
|
||||
```
|
||||
|
||||
### 拉取最新的 LobeHub 镜像
|
||||
@@ -54,7 +54,7 @@ Docker 部署版本的升级非常简单,只需要重新部署 LobeHub 的最
|
||||
使用以下命令拉取 LobeHub 的最新 Docker 镜像:
|
||||
|
||||
```fish
|
||||
docker pull lobehub/lobe-chat
|
||||
docker pull lobehub/lobehub
|
||||
```
|
||||
|
||||
### 重新启动 Docker 容器
|
||||
@@ -65,7 +65,7 @@ Docker 部署版本的升级非常简单,只需要重新部署 LobeHub 的最
|
||||
docker run -d -p 3210:3210 \
|
||||
-e OPENAI_API_KEY=sk-xxxx \
|
||||
-e OPENAI_PROXY_URL=https://api-proxy.com/v1 \
|
||||
--name lobe-chat \
|
||||
--name lobehub \
|
||||
lobehub/lobe-chat
|
||||
```
|
||||
</Steps>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
title: LobeHub Authentication Service Configuration
|
||||
description: >-
|
||||
Learn how to configure external authentication services using Better Auth,
|
||||
Clerk, or Next Auth for centralized user authorization management. Supported
|
||||
Learn how to configure external authentication services using Better Auth
|
||||
for centralized user authorization management. Supported
|
||||
authentication services include Auth0, Azure ID, etc.
|
||||
tags:
|
||||
- Authentication Service
|
||||
@@ -12,17 +12,7 @@ tags:
|
||||
|
||||
# Authentication Service
|
||||
|
||||
LobeHub supports the configuration of external authentication services using Better Auth, Clerk, or Next Auth for internal use within enterprises/organizations to centrally manage user authorization.
|
||||
|
||||
<Callout type={'info'}>
|
||||
Looking for legacy authentication methods? See [Legacy Authentication](/docs/self-hosting/advanced/auth/legacy) for NextAuth and Clerk documentation.
|
||||
</Callout>
|
||||
|
||||
Clerk is a comprehensive identity verification solution that has recently gained popularity. It provides a simple yet powerful API and services to handle user authentication and session management. Clerk's design philosophy is to offer a concise and modern authentication solution that enables developers to easily integrate and use it.
|
||||
|
||||
LobeHub has deeply integrated with Clerk to provide users with a more secure and convenient login and registration experience. It also relieves developers from the burden of managing authentication logic. Clerk's concise and modern design philosophy aligns perfectly with LobeHub's goals, making user management on the entire platform more efficient and reliable.
|
||||
|
||||
By setting the environment variables `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` in LobeHub's environment, you can enable and use Clerk.
|
||||
LobeHub supports the configuration of external authentication services using Better Auth for internal use within enterprises/organizations to centrally manage user authorization.
|
||||
|
||||
## Better Auth
|
||||
|
||||
@@ -40,12 +30,11 @@ By setting the environment variables `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CL
|
||||
|
||||
To enable Better Auth in LobeHub, set the following environment variables:
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| -------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `NEXT_PUBLIC_ENABLE_BETTER_AUTH` | Required | Set to `1` to enable Better Auth service |
|
||||
| `AUTH_SECRET` | Required | Key used to encrypt session tokens. Generate using: `openssl rand -base64 32` |
|
||||
| `NEXT_PUBLIC_AUTH_URL` | Required | The browser-accessible base URL for Better Auth (e.g., `http://localhost:3010`, `https://LobeHub.com`). Optional for Vercel deployments (auto-detected from `VERCEL_URL`) |
|
||||
| `AUTH_SSO_PROVIDERS` | Optional | Comma-separated list of enabled SSO providers, e.g., `google,github,microsoft` |
|
||||
| Environment Variable | Type | Description |
|
||||
| ---------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `AUTH_SECRET` | Required | Key used to encrypt session tokens. Generate using: `openssl rand -base64 32` |
|
||||
| `NEXT_PUBLIC_AUTH_URL` | Required | The browser-accessible base URL for Better Auth (e.g., `http://localhost:3010`, `https://LobeHub.com`). Optional for Vercel deployments (auto-detected from `VERCEL_URL`) |
|
||||
| `AUTH_SSO_PROVIDERS` | Optional | Comma-separated list of enabled SSO providers, e.g., `google,github,microsoft` |
|
||||
|
||||
## Supported SSO Providers
|
||||
|
||||
@@ -72,6 +61,8 @@ To enable Better Auth in LobeHub, set the following environment variables:
|
||||
Click on a provider below for detailed configuration guides:
|
||||
|
||||
<Cards>
|
||||
<Card href={'/docs/self-hosting/advanced/auth/providers/password'} title={'Email/Password'} />
|
||||
|
||||
<Card href={'/docs/self-hosting/advanced/auth/providers/github'} title={'GitHub'} />
|
||||
|
||||
<Card href={'/docs/self-hosting/advanced/auth/providers/google'} title={'Google'} />
|
||||
@@ -116,63 +107,7 @@ When configuring OAuth providers, use the following callback URL format:
|
||||
|
||||
## Email Service Configuration
|
||||
|
||||
Used by email verification, password reset, and magic-link delivery. Two providers are supported:
|
||||
|
||||
### Option 1: Nodemailer (SMTP)
|
||||
|
||||
Send emails via SMTP protocol, suitable for users with existing email services. See [Nodemailer SMTP docs](https://nodemailer.com/smtp/).
|
||||
|
||||
| Environment Variable | Type | Description | Example |
|
||||
| ------------------------ | -------- | -------------------------------------------------------------- | --------------------- |
|
||||
| `EMAIL_SERVICE_PROVIDER` | Optional | Set to `nodemailer` (default) | `nodemailer` |
|
||||
| `SMTP_HOST` | Required | SMTP server hostname | `smtp.gmail.com` |
|
||||
| `SMTP_PORT` | Required | SMTP server port (`587` for TLS, `465` for SSL) | `587` |
|
||||
| `SMTP_SECURE` | Optional | `true` for SSL (port 465), `false` for TLS (port 587) | `false` |
|
||||
| `SMTP_USER` | Required | SMTP auth username | `user@gmail.com` |
|
||||
| `SMTP_PASS` | Required | SMTP auth password | `your-app-password` |
|
||||
| `SMTP_FROM` | Optional | Sender address (required for AWS SES), defaults to `SMTP_USER` | `noreply@example.com` |
|
||||
|
||||
<Callout type={'warning'}>
|
||||
When using Gmail, you must use an App Password instead of your account password. Generate one at [Google App Passwords](https://myaccount.google.com/apppasswords).
|
||||
</Callout>
|
||||
|
||||
### Option 2: Resend
|
||||
|
||||
[Resend](https://resend.com/) is a modern email API service with simple setup, recommended for new users.
|
||||
|
||||
| Environment Variable | Type | Description | Example |
|
||||
| ------------------------ | ----------- | ----------------------------------------- | --------------------------- |
|
||||
| `EMAIL_SERVICE_PROVIDER` | Required | Set to `resend` | `resend` |
|
||||
| `RESEND_API_KEY` | Required | Resend API Key | `re_xxxxxxxxxxxxxxxxxxxxxx` |
|
||||
| `RESEND_FROM` | Recommended | Sender address, must be a verified domain | `noreply@your-domain.com` |
|
||||
|
||||
<Callout type={'info'}>
|
||||
Before using Resend, you need to [verify your sending domain](https://resend.com/docs/dashboard/domains/introduction), otherwise emails can only be sent to your own address.
|
||||
</Callout>
|
||||
|
||||
### Common Configuration
|
||||
|
||||
Before using Better Auth, please set the following variables in LobeHub's environment variables:
|
||||
|
||||
## Email Verification
|
||||
|
||||
Enable email verification to ensure users own the email addresses they register with (off by default):
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| ------------------------- | -------- | ----------------------------------------------------------- |
|
||||
| `AUTH_EMAIL_VERIFICATION` | Optional | Set to `1` to require email verification after registration |
|
||||
|
||||
<Callout type={'info'}>
|
||||
Email verification requires a working email service (SMTP or Resend) configured above. When enabled, users must verify their email address before they can sign in.
|
||||
</Callout>
|
||||
|
||||
## Magic Link (Passwordless) Login
|
||||
|
||||
Enable magic-link login (depends on a working email provider above, off by default):
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| ------------------------ | -------- | ------------------------------------------------------------------- |
|
||||
| `AUTH_ENABLE_MAGIC_LINK` | Optional | Set to `1` to enable passwordless magic-link login (off by default) |
|
||||
Email service is used for email verification, password reset, and magic link delivery. For detailed configuration, see [Email Service Configuration](/docs/self-hosting/auth/email).
|
||||
|
||||
<Callout type={'tip'}>
|
||||
Go to [Environment Variables](/docs/self-hosting/environment-variables/auth#better-auth) for detailed information on all Better Auth variables.
|
||||
@@ -216,6 +151,16 @@ The current authentication system requires email. Please configure a valid email
|
||||
|
||||
This applies to all authentication methods, including SSO providers like Casdoor. Always ensure users have valid email addresses configured.
|
||||
|
||||
### How do I enable SSO-only mode (disable email/password login)?
|
||||
|
||||
Set `AUTH_DISABLE_EMAIL_PASSWORD=1` to disable email/password authentication. When enabled:
|
||||
|
||||
- The email input will be hidden on the login page, only SSO buttons are displayed
|
||||
- The signup page will redirect to the login page
|
||||
- Users can only log in via configured SSO providers
|
||||
|
||||
Make sure you have at least one SSO provider configured via `AUTH_SSO_PROVIDERS` before enabling this option.
|
||||
|
||||
### How do I restrict registration to specific emails or domains?
|
||||
|
||||
Set the `AUTH_ALLOWED_EMAILS` environment variable with a comma-separated list of allowed emails or domains. For example:
|
||||
@@ -233,10 +178,8 @@ Set the `AUTH_ALLOWED_EMAILS` environment variable with a comma-separated list o
|
||||
|
||||
Allow LobeHub to receive notifications when user information is updated in the identity provider. Supported providers include Casdoor and Logto. Please refer to the specific provider documentation for configuration details.
|
||||
|
||||
### Database Session
|
||||
### Other SSO Providers
|
||||
|
||||
Allow the session store in database, see also the [Auth.js Session Documentation](https://authjs.dev/concepts/session-strategies#database-session).
|
||||
If you need to use an SSO provider not included in the list above, you can use [Generic OIDC](/docs/self-hosting/auth/providers/generic-oidc) to configure any OpenID Connect or OAuth 2.0 compliant provider.
|
||||
|
||||
## Other SSO Providers
|
||||
|
||||
Please refer to the [Auth.js](https://authjs.dev/getting-started/authentication/oauth) documentation and feel free to submit a Pull Request.
|
||||
Feel free to submit a Pull Request to add more built-in SSO provider support. For details, see the [Better Auth documentation](https://www.better-auth.com/docs/concepts/oauth).
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: LobeHub 身份验证服务配置
|
||||
description: >-
|
||||
了解如何使用 Better Auth、Clerk 或 Next Auth 配置外部身份验证服务,以统一管理用户授权。支持的身份验证服务包括 Auth0、
|
||||
了解如何使用 Better Auth 配置外部身份验证服务,以统一管理用户授权。支持的身份验证服务包括 Auth0、
|
||||
Azure ID 等。
|
||||
tags:
|
||||
- 身份验证服务
|
||||
@@ -12,17 +12,7 @@ tags:
|
||||
|
||||
# 身份验证服务
|
||||
|
||||
LobeHub 支持使用 Better Auth、Clerk 或者 Next Auth 配置外部身份验证服务,供企业 / 组织内部使用,统一管理用户授权。
|
||||
|
||||
<Callout type={'info'}>
|
||||
需要使用旧版身份验证方案?请参阅 [旧版身份验证](/zh/docs/self-hosting/advanced/auth/legacy) 了解 NextAuth 和 Clerk 的文档。
|
||||
</Callout>
|
||||
|
||||
Clerk 是一个近期流行起来的全面的身份验证解决方案,它提供了简单而强大的 API 和服务来处理用户认证和会话管理。Clerk 的设计哲学是提供一套简洁、现代的认证解决方案,使得开发者可以轻松集成和使用。
|
||||
|
||||
LobeHub 与 Clerk 做了深度集成,能够为用户提供一个更加安全、便捷的登录和注册体验,同时也为开发者减轻了管理身份验证逻辑的负担。Clerk 的简洁和现代的设计理念与 LobeHub 的目标非常契合,使得整个平台的用户管理更加高效和可靠。
|
||||
|
||||
在 LobeHub 的环境变量中设置 `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` 和 `CLERK_SECRET_KEY`,即可开启和使用 Clerk。
|
||||
LobeHub 支持使用 Better Auth 配置外部身份验证服务,供企业 / 组织内部使用,统一管理用户授权。
|
||||
|
||||
## Better Auth
|
||||
|
||||
@@ -40,12 +30,11 @@ LobeHub 与 Clerk 做了深度集成,能够为用户提供一个更加安全
|
||||
|
||||
要在 LobeHub 中启用 Better Auth,请设置以下环境变量:
|
||||
|
||||
| 环境变量 | 类型 | 描述 |
|
||||
| -------------------------------- | -- | --------------------------------------------------------------------------------------------------------------- |
|
||||
| `NEXT_PUBLIC_ENABLE_BETTER_AUTH` | 必选 | 设置为 `1` 以启用 Better Auth 服务 |
|
||||
| `AUTH_SECRET` | 必选 | 用于加密会话令牌的密钥。使用以下命令生成:`openssl rand -base64 32` |
|
||||
| `NEXT_PUBLIC_AUTH_URL` | 必选 | 浏览器可访问的 Better Auth 基础 URL(例如 `http://localhost:3010`、`https://LobeHub.com`)。Vercel 部署时可选(会自动从 `VERCEL_URL` 获取) |
|
||||
| `AUTH_SSO_PROVIDERS` | 可选 | 启用的 SSO 提供商列表,以逗号分隔,例如 `google,github,microsoft` |
|
||||
| 环境变量 | 类型 | 描述 |
|
||||
| ---------------------- | -- | --------------------------------------------------------------------------------------------------------------- |
|
||||
| `AUTH_SECRET` | 必选 | 用于加密会话令牌的密钥。使用以下命令生成:`openssl rand -base64 32` |
|
||||
| `NEXT_PUBLIC_AUTH_URL` | 必选 | 浏览器可访问的 Better Auth 基础 URL(例如 `http://localhost:3010`、`https://LobeHub.com`)。Vercel 部署时可选(会自动从 `VERCEL_URL` 获取) |
|
||||
| `AUTH_SSO_PROVIDERS` | 可选 | 启用的 SSO 提供商列表,以逗号分隔,例如 `google,github,microsoft` |
|
||||
|
||||
## 支持的 SSO 提供商
|
||||
|
||||
@@ -72,6 +61,8 @@ LobeHub 与 Clerk 做了深度集成,能够为用户提供一个更加安全
|
||||
点击下方提供商查看详细配置指南:
|
||||
|
||||
<Cards>
|
||||
<Card href={'/zh/docs/self-hosting/advanced/auth/providers/password'} title={'邮箱密码'} />
|
||||
|
||||
<Card href={'/zh/docs/self-hosting/advanced/auth/providers/github'} title={'GitHub'} />
|
||||
|
||||
<Card href={'/zh/docs/self-hosting/advanced/auth/providers/google'} title={'Google'} />
|
||||
@@ -116,63 +107,7 @@ LobeHub 与 Clerk 做了深度集成,能够为用户提供一个更加安全
|
||||
|
||||
## 邮件服务配置
|
||||
|
||||
用于邮箱验证、密码重置和魔法链接发送。支持两种邮件服务:
|
||||
|
||||
### 方式一:Nodemailer(SMTP)
|
||||
|
||||
使用 SMTP 协议发送邮件,适合已有邮箱服务的用户。参考 [Nodemailer SMTP 文档](https://nodemailer.com/smtp/)。
|
||||
|
||||
| 环境变量 | 类型 | 描述 | 示例 |
|
||||
| ------------------------ | -- | ---------------------------------------------- | --------------------- |
|
||||
| `EMAIL_SERVICE_PROVIDER` | 可选 | 设置为 `nodemailer`(默认值) | `nodemailer` |
|
||||
| `SMTP_HOST` | 必选 | SMTP 服务器主机名 | `smtp.gmail.com` |
|
||||
| `SMTP_PORT` | 必选 | SMTP 服务器端口(TLS 通常为 `587`,SSL 为 `465`) | `587` |
|
||||
| `SMTP_SECURE` | 可选 | SSL 设置为 `true`(端口 465),TLS 设置为 `false`(端口 587) | `false` |
|
||||
| `SMTP_USER` | 必选 | SMTP 认证用户名 | `user@gmail.com` |
|
||||
| `SMTP_PASS` | 必选 | SMTP 认证密码 | `your-app-password` |
|
||||
| `SMTP_FROM` | 可选 | 发件人地址(AWS SES 必填),默认为 `SMTP_USER` | `noreply@example.com` |
|
||||
|
||||
<Callout type={'warning'}>
|
||||
使用 Gmail 时,需使用应用专用密码而非账户密码。前往 [Google 应用专用密码](https://myaccount.google.com/apppasswords) 生成。
|
||||
</Callout>
|
||||
|
||||
### 方式二:Resend
|
||||
|
||||
[Resend](https://resend.com/) 是一个现代邮件 API 服务,配置简单,推荐新用户使用。
|
||||
|
||||
| 环境变量 | 类型 | 描述 | 示例 |
|
||||
| ------------------------ | -- | ------------------------- | --------------------------- |
|
||||
| `EMAIL_SERVICE_PROVIDER` | 必选 | 设置为 `resend` | `resend` |
|
||||
| `RESEND_API_KEY` | 必选 | Resend API Key | `re_xxxxxxxxxxxxxxxxxxxxxx` |
|
||||
| `RESEND_FROM` | 推荐 | 发件人地址,需为 Resend 已验证域名下的邮箱 | `noreply@your-domain.com` |
|
||||
|
||||
<Callout type={'info'}>
|
||||
使用 Resend 前需先 [验证发件域名](https://resend.com/docs/dashboard/domains/introduction),否则只能发送到自己的邮箱。
|
||||
</Callout>
|
||||
|
||||
### 通用配置
|
||||
|
||||
在使用 Better Auth 之前,请先在 LobeHub 的环境变量中设置以下变量:
|
||||
|
||||
## 邮箱验证
|
||||
|
||||
启用邮箱验证以确保用户拥有其注册的邮箱地址(默认关闭):
|
||||
|
||||
| 环境变量 | 类型 | 描述 |
|
||||
| ------------------------- | -- | -------------------- |
|
||||
| `AUTH_EMAIL_VERIFICATION` | 可选 | 设置为 `1` 以要求注册后进行邮箱验证 |
|
||||
|
||||
<Callout type={'info'}>
|
||||
邮箱验证需要上方已配置好的邮件服务(SMTP 或 Resend)。启用后,用户必须验证其邮箱地址才能登录。
|
||||
</Callout>
|
||||
|
||||
## 魔法链接(免密)登录
|
||||
|
||||
启用魔法链接登录(依赖上方已配置好的邮件服务,默认关闭):
|
||||
|
||||
| 环境变量 | 类型 | 描述 |
|
||||
| ------------------------ | -- | ----------------------- |
|
||||
| `AUTH_ENABLE_MAGIC_LINK` | 可选 | 设置为 `1` 以启用魔法链接登录(默认关闭) |
|
||||
邮件服务用于邮箱验证、密码重置和魔法链接发送。详细配置请参阅 [邮件服务配置](/zh/docs/self-hosting/auth/email)。
|
||||
|
||||
<Callout type={'tip'}>
|
||||
前往 [环境变量](/zh/docs/self-hosting/environment-variables/auth#better-auth) 可查阅所有 Better Auth 相关变量详情。
|
||||
@@ -217,6 +152,16 @@ Better Auth 支持内置提供商(Google、GitHub、Microsoft、Apple、AWS Co
|
||||
|
||||
这适用于所有身份验证方式,包括 Casdoor 等 SSO 提供商。请确保用户配置了有效的邮箱地址。
|
||||
|
||||
### 如何启用仅 SSO 模式(禁用邮箱密码登录)?
|
||||
|
||||
设置 `AUTH_DISABLE_EMAIL_PASSWORD=1` 可禁用邮箱密码登录。启用后:
|
||||
|
||||
- 登录页面将隐藏邮箱输入框,仅显示 SSO 登录按钮
|
||||
- 注册页面将重定向到登录页面
|
||||
- 用户只能通过配置的 SSO 提供商登录
|
||||
|
||||
启用此选项前,请确保已通过 `AUTH_SSO_PROVIDERS` 配置了至少一个 SSO 提供商。
|
||||
|
||||
### 如何限制只允许特定邮箱或域名注册?
|
||||
|
||||
设置 `AUTH_ALLOWED_EMAILS` 环境变量,支持完整邮箱地址或域名,以逗号分隔。例如:
|
||||
@@ -232,10 +177,8 @@ Better Auth 支持内置提供商(Google、GitHub、Microsoft、Apple、AWS Co
|
||||
|
||||
允许 LobeHub 在身份提供商中用户信息更新时接收通知。支持的提供商包括 Casdoor 和 Logto。请参考具体提供商文档进行配置。
|
||||
|
||||
### 数据库会话
|
||||
### 其他 SSO 提供商
|
||||
|
||||
允许会话存储在数据库中,详情请参阅 [Auth.js 会话文档](https://authjs.dev/concepts/session-strategies#database-session)。
|
||||
如果你需要使用上述列表中未包含的 SSO 提供商,可以使用 [Generic OIDC](/zh/docs/self-hosting/auth/providers/generic-oidc) 来配置任何符合 OpenID Connect 或 OAuth 2.0 标准的提供商。
|
||||
|
||||
## 其他 SSO 提供商
|
||||
|
||||
请参考 [Auth.js](https://authjs.dev/getting-started/authentication/oauth) 文档,欢迎提交 Pull Request。
|
||||
欢迎提交 Pull Request 来添加更多内置 SSO 提供商支持。详情请参考 [Better Auth 文档](https://www.better-auth.com/docs/concepts/oauth)。
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
title: Email Service Configuration
|
||||
description: Configure LobeHub email service for email verification, password reset, and magic link login.
|
||||
tags:
|
||||
- Email Service
|
||||
- SMTP
|
||||
- Resend
|
||||
- Email Verification
|
||||
- Magic Link
|
||||
---
|
||||
|
||||
# Email Service Configuration
|
||||
|
||||
Email service is used for email verification, password reset, and magic link delivery. LobeHub supports two email service providers.
|
||||
|
||||
## Nodemailer (SMTP)
|
||||
|
||||
Send emails via SMTP protocol, suitable for users with existing email services. See [Nodemailer SMTP docs](https://nodemailer.com/smtp/).
|
||||
|
||||
| Environment Variable | Type | Description | Example |
|
||||
| ------------------------ | -------- | -------------------------------------------------------------- | --------------------- |
|
||||
| `EMAIL_SERVICE_PROVIDER` | Optional | Set to `nodemailer` (default) | `nodemailer` |
|
||||
| `SMTP_HOST` | Required | SMTP server hostname | `smtp.gmail.com` |
|
||||
| `SMTP_PORT` | Required | SMTP server port (`587` for TLS, `465` for SSL) | `587` |
|
||||
| `SMTP_SECURE` | Optional | `true` for SSL (port 465), `false` for TLS (port 587) | `false` |
|
||||
| `SMTP_USER` | Required | SMTP auth username | `user@gmail.com` |
|
||||
| `SMTP_PASS` | Required | SMTP auth password | `your-app-password` |
|
||||
| `SMTP_FROM` | Optional | Sender address (required for AWS SES), defaults to `SMTP_USER` | `noreply@example.com` |
|
||||
|
||||
<Callout type={'warning'}>
|
||||
When using Gmail, you must use an App Password instead of your account password. Generate one at [Google App Passwords](https://myaccount.google.com/apppasswords).
|
||||
</Callout>
|
||||
|
||||
## Resend
|
||||
|
||||
[Resend](https://resend.com/) is a modern email API service with simple setup, recommended for new users.
|
||||
|
||||
| Environment Variable | Type | Description | Example |
|
||||
| ------------------------ | ----------- | ----------------------------------------- | --------------------------- |
|
||||
| `EMAIL_SERVICE_PROVIDER` | Required | Set to `resend` | `resend` |
|
||||
| `RESEND_API_KEY` | Required | Resend API Key | `re_xxxxxxxxxxxxxxxxxxxxxx` |
|
||||
| `RESEND_FROM` | Recommended | Sender address, must be a verified domain | `noreply@your-domain.com` |
|
||||
|
||||
<Callout type={'info'}>
|
||||
Before using Resend, you need to [verify your sending domain](https://resend.com/docs/dashboard/domains/introduction), otherwise emails can only be sent to your own address.
|
||||
</Callout>
|
||||
|
||||
## Email Verification
|
||||
|
||||
Enable email verification to ensure users own the email addresses they register with (off by default):
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| ------------------------- | -------- | ----------------------------------------------------------- |
|
||||
| `AUTH_EMAIL_VERIFICATION` | Optional | Set to `1` to require email verification after registration |
|
||||
|
||||
<Callout type={'info'}>
|
||||
Email verification requires a working email service (SMTP or Resend) configured above. When enabled, users must verify their email address before they can sign in.
|
||||
</Callout>
|
||||
|
||||
## Magic Link (Passwordless) Login
|
||||
|
||||
Enable magic-link login (depends on a working email provider above, off by default):
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| ------------------------ | -------- | ------------------------------------------------------------------- |
|
||||
| `AUTH_ENABLE_MAGIC_LINK` | Optional | Set to `1` to enable passwordless magic-link login (off by default) |
|
||||
|
||||
<Callout type={'tip'}>
|
||||
Go to [Environment Variables](/docs/self-hosting/environment-variables/auth#better-auth) for detailed information on all Better Auth variables.
|
||||
</Callout>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user