mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-20 06:15:58 +00:00
Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e036ccee86 | |||
| 3f1a1983e3 | |||
| 151261d0c5 | |||
| 0f63781876 | |||
| 71064fdede | |||
| 20928ac466 | |||
| 347d0ce70f | |||
| 28887c77e8 | |||
| 1cc9034c7c | |||
| 37609e42d6 | |||
| 3063ceef8c | |||
| f61ab26081 | |||
| 79712bd38c | |||
| 66caf30e7e | |||
| 0c855e44fc | |||
| e18b7a92c7 | |||
| 3f1fd102c5 | |||
| ccfaec2fdb | |||
| 8aba59bffd | |||
| 13e0652c59 | |||
| 4a6be92604 | |||
| c576a13a43 | |||
| 63a0464a83 | |||
| b1c6bdb192 | |||
| 74b9bd0bed | |||
| 6977c570e6 | |||
| 4efe60e9f7 | |||
| 336d10663c | |||
| 5f21aaf048 | |||
| e2fd28eece | |||
| a6a1fecae0 | |||
| fdee6b9aac | |||
| 98f93ef2f0 | |||
| df7e2800a7 | |||
| 4aac694364 | |||
| c7a06a4b62 | |||
| 2f21c15172 | |||
| de0ce799c7 | |||
| 3423ad1b15 | |||
| 5db07efe6b | |||
| f5d67a7385 | |||
| 99d4c02b9d | |||
| 182030f404 | |||
| 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 |
@@ -5,10 +5,11 @@ You are a support assistant for LobeChat authentication migration issues. Your j
|
||||
**IMPORTANT**: The official documentation website is `https://lobehub.com`. When providing documentation links, always use `https://lobehub.com/docs/...` format. Never use `lobechat.com` - that domain is incorrect.
|
||||
|
||||
Examples of correct documentation URLs:
|
||||
- `https://lobehub.com/docs/self-hosting/advanced/auth/nextauth-to-betterauth`
|
||||
- `https://lobehub.com/docs/self-hosting/advanced/auth/clerk-to-betterauth`
|
||||
- `https://lobehub.com/docs/self-hosting/advanced/auth`
|
||||
- `https://lobehub.com/docs/self-hosting/advanced/auth/providers/casdoor`
|
||||
|
||||
- `https://lobehub.com/docs/self-hosting/migration/v2/auth/nextauth-to-betterauth`
|
||||
- `https://lobehub.com/docs/self-hosting/migration/v2/auth/clerk-to-betterauth`
|
||||
- `https://lobehub.com/docs/self-hosting/auth`
|
||||
- `https://lobehub.com/docs/self-hosting/auth/providers/casdoor`
|
||||
|
||||
## Target Issues
|
||||
|
||||
|
||||
+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
|
||||
|
||||
|
||||
@@ -24,6 +24,17 @@ runs:
|
||||
shell: bash
|
||||
run: pnpm install --node-linker=hoisted
|
||||
|
||||
# 移除国内 electron 镜像配置,GitHub Actions 使用官方源更快
|
||||
- name: Remove China electron mirror from .npmrc
|
||||
shell: bash
|
||||
run: |
|
||||
NPMRC_FILE="./apps/desktop/.npmrc"
|
||||
if [ -f "$NPMRC_FILE" ]; then
|
||||
sed -i.bak '/^electron_mirror=/d; /^electron_builder_binaries_mirror=/d' "$NPMRC_FILE"
|
||||
rm -f "${NPMRC_FILE}.bak"
|
||||
echo "✅ Removed electron mirror config from .npmrc"
|
||||
fi
|
||||
|
||||
- name: Install deps on Desktop
|
||||
shell: bash
|
||||
run: npm run install-isolated --prefix=./apps/desktop
|
||||
|
||||
@@ -70,12 +70,12 @@ jobs:
|
||||
```
|
||||
|
||||
2. Read the latest migration documentation based on the issue:
|
||||
- If issue #11757 (NextAuth): `cat docs/self-hosting/advanced/auth/nextauth-to-betterauth.mdx`
|
||||
- If issue #11707 (Clerk): `cat docs/self-hosting/advanced/auth/clerk-to-betterauth.mdx`
|
||||
- If issue #11757 (NextAuth): `cat docs/self-hosting/migration/v2/auth/nextauth-to-betterauth.mdx`
|
||||
- If issue #11707 (Clerk): `cat docs/self-hosting/migration/v2/auth/clerk-to-betterauth.mdx`
|
||||
|
||||
3. Read additional reference files:
|
||||
- Main auth documentation: `cat docs/self-hosting/advanced/auth.mdx`
|
||||
- Migration internals: `cat docs/self-hosting/advanced/auth/migration-internals.mdx`
|
||||
- Main auth documentation: `cat docs/self-hosting/auth.mdx`
|
||||
- Migration internals: `cat docs/self-hosting/migration/v2/auth/migration-internals.mdx`
|
||||
- Deprecated env vars checker: `cat scripts/_shared/checkDeprecatedAuth.js`
|
||||
|
||||
4. Analyze the user's comment and determine:
|
||||
|
||||
@@ -109,6 +109,17 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install --node-linker=hoisted
|
||||
|
||||
# 移除国内 electron 镜像配置,GitHub Actions 使用官方源更快
|
||||
- name: Remove China electron mirror from .npmrc
|
||||
shell: bash
|
||||
run: |
|
||||
NPMRC_FILE="./apps/desktop/.npmrc"
|
||||
if [ -f "$NPMRC_FILE" ]; then
|
||||
sed -i.bak '/^electron_mirror=/d; /^electron_builder_binaries_mirror=/d' "$NPMRC_FILE"
|
||||
rm -f "${NPMRC_FILE}.bak"
|
||||
echo "✅ Removed electron mirror config from .npmrc"
|
||||
fi
|
||||
|
||||
- name: Install deps on Desktop
|
||||
run: npm run install-isolated --prefix=./apps/desktop
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+559
@@ -2,6 +2,565 @@
|
||||
|
||||
# Changelog
|
||||
|
||||
### [Version 2.1.18](https://github.com/lobehub/lobe-chat/compare/v2.1.17...v2.1.18)
|
||||
|
||||
<sup>Released on **2026-02-04**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **model-runtime**: Fix moonshot interleaved thinking and circular dependency.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **model-runtime**: Fix moonshot interleaved thinking and circular dependency, closes [#12112](https://github.com/lobehub/lobe-chat/issues/12112) ([3f1a198](https://github.com/lobehub/lobe-chat/commit/3f1a198))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.17](https://github.com/lobehub/lobe-chat/compare/v2.1.16...v2.1.17)
|
||||
|
||||
<sup>Released on **2026-02-04**</sup>
|
||||
|
||||
#### ♻ Code Refactoring
|
||||
|
||||
- **model-runtime**: Extract Anthropic factory and convert Moonshot to RouterRuntime.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### Code refactoring
|
||||
|
||||
- **model-runtime**: Extract Anthropic factory and convert Moonshot to RouterRuntime, closes [#12109](https://github.com/lobehub/lobe-chat/issues/12109) ([71064fd](https://github.com/lobehub/lobe-chat/commit/71064fd))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.16](https://github.com/lobehub/lobe-chat/compare/v2.1.15...v2.1.16)
|
||||
|
||||
<sup>Released on **2026-02-04**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **misc**: Add the preview publish to market button preview check.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **misc**: Add the preview publish to market button preview check, closes [#12105](https://github.com/lobehub/lobe-chat/issues/12105) ([28887c7](https://github.com/lobehub/lobe-chat/commit/28887c7))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.15](https://github.com/lobehub/lobe-chat/compare/v2.1.14...v2.1.15)
|
||||
|
||||
<sup>Released on **2026-02-04**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **misc**: Fixed the agents list the show updateAt time error.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **misc**: Fixed the agents list the show updateAt time error, closes [#12103](https://github.com/lobehub/lobe-chat/issues/12103) ([3063cee](https://github.com/lobehub/lobe-chat/commit/3063cee))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.14](https://github.com/lobehub/lobe-chat/compare/v2.1.13...v2.1.14)
|
||||
|
||||
<sup>Released on **2026-02-04**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **misc**: Fix cannot uncompressed messages.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **misc**: Fix cannot uncompressed messages, closes [#12086](https://github.com/lobehub/lobe-chat/issues/12086) ([ccfaec2](https://github.com/lobehub/lobe-chat/commit/ccfaec2))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.13](https://github.com/lobehub/lobe-chat/compare/v2.1.12...v2.1.13)
|
||||
|
||||
<sup>Released on **2026-02-03**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **docker**: Add librt.so.1 to fix PDF parsing.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **docker**: Add librt.so.1 to fix PDF parsing, closes [#12039](https://github.com/lobehub/lobe-chat/issues/12039) ([4a6be92](https://github.com/lobehub/lobe-chat/commit/4a6be92))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.12](https://github.com/lobehub/lobe-chat/compare/v2.1.11...v2.1.12)
|
||||
|
||||
<sup>Released on **2026-02-03**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **changelog**: Normalize versionRange to valid semver.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **changelog**: Normalize versionRange to valid semver, closes [#12049](https://github.com/lobehub/lobe-chat/issues/12049) ([74b9bd0](https://github.com/lobehub/lobe-chat/commit/74b9bd0))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.11](https://github.com/lobehub/lobe-chat/compare/v2.1.10...v2.1.11)
|
||||
|
||||
<sup>Released on **2026-02-02**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **misc**: Hide password features when AUTH_DISABLE_EMAIL_PASSWORD is set.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **misc**: Hide password features when AUTH_DISABLE_EMAIL_PASSWORD is set, closes [#12023](https://github.com/lobehub/lobe-chat/issues/12023) ([e2fd28e](https://github.com/lobehub/lobe-chat/commit/e2fd28e))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.10](https://github.com/lobehub/lobe-chat/compare/v2.1.9...v2.1.10)
|
||||
|
||||
<sup>Released on **2026-02-02**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **auth**: Revert authority URL and tenant ID for Microsoft authentication..
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **auth**: Revert authority URL and tenant ID for Microsoft authentication., closes [#11930](https://github.com/lobehub/lobe-chat/issues/11930) ([98f93ef](https://github.com/lobehub/lobe-chat/commit/98f93ef))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.9](https://github.com/lobehub/lobe-chat/compare/v2.1.8...v2.1.9)
|
||||
|
||||
<sup>Released on **2026-02-02**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **misc**: Use oauth2.link for generic OIDC provider account linking.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **misc**: Use oauth2.link for generic OIDC provider account linking, closes [#12024](https://github.com/lobehub/lobe-chat/issues/12024) ([c7a06a4](https://github.com/lobehub/lobe-chat/commit/c7a06a4))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.8](https://github.com/lobehub/lobe-chat/compare/v2.1.7...v2.1.8)
|
||||
|
||||
<sup>Released on **2026-02-01**</sup>
|
||||
|
||||
#### 💄 Styles
|
||||
|
||||
- **misc**: Improve tasks display.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### Styles
|
||||
|
||||
- **misc**: Improve tasks display, closes [#12032](https://github.com/lobehub/lobe-chat/issues/12032) ([3423ad1](https://github.com/lobehub/lobe-chat/commit/3423ad1))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.7](https://github.com/lobehub/lobe-chat/compare/v2.1.6...v2.1.7)
|
||||
|
||||
<sup>Released on **2026-02-01**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **misc**: Add missing description parameter docs in Notebook system prompt.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **misc**: Add missing description parameter docs in Notebook system prompt, closes [#12015](https://github.com/lobehub/lobe-chat/issues/12015) [#11391](https://github.com/lobehub/lobe-chat/issues/11391) ([182030f](https://github.com/lobehub/lobe-chat/commit/182030f))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [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>
|
||||
|
||||
+54
-57
@@ -8,24 +8,23 @@ 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/lib/$(arch)-linux-gnu/librt.so.1 /distroless/lib/librt.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 +76,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 +98,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 +133,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 +159,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 +175,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="" \
|
||||
@@ -192,7 +187,9 @@ ENV AUTH_SECRET="" \
|
||||
AUTH_GITHUB_SECRET="" \
|
||||
# Microsoft
|
||||
AUTH_MICROSOFT_ID="" \
|
||||
AUTH_MICROSOFT_SECRET=""
|
||||
AUTH_MICROSOFT_SECRET="" \
|
||||
AUTH_MICROSOFT_AUTHORITY_URL="" \
|
||||
AUTH_MICROSOFT_TENANT_ID=""
|
||||
|
||||
# Redis
|
||||
ENV REDIS_URL="" \
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -45,7 +45,7 @@ export class LinuxMenu extends BaseMenuPlatform implements IMenuPlatform {
|
||||
this.buildAndSetAppMenu(options);
|
||||
}
|
||||
|
||||
// --- 私有方法:定义菜单模板和逻辑 ---
|
||||
// --- Private methods: define menu templates and logic ---
|
||||
|
||||
private getAppMenuTemplate(options?: MenuOptions): MenuItemConstructorOptions[] {
|
||||
const showDev = isDev || options?.showDevItems;
|
||||
|
||||
@@ -48,23 +48,23 @@ export class MacOSMenu extends BaseMenuPlatform implements IMenuPlatform {
|
||||
}
|
||||
|
||||
refresh(options?: MenuOptions): void {
|
||||
// 重建Application menu
|
||||
// Rebuild Application menu
|
||||
this.buildAndSetAppMenu(options);
|
||||
// 如果托盘菜单存在,也重建它(如果需要动态更新)
|
||||
// If tray menu exists, rebuild it as well (if dynamic update is needed)
|
||||
// this.trayMenu = this.buildTrayMenu();
|
||||
// 需要考虑如何更新现有托盘图标的菜单
|
||||
// Need to consider how to update the menu for existing tray icons
|
||||
}
|
||||
|
||||
// --- 私有方法:定义菜单模板和逻辑 ---
|
||||
// --- Private methods: define menu templates and logic ---
|
||||
|
||||
private getAppMenuTemplate(options?: MenuOptions): MenuItemConstructorOptions[] {
|
||||
const appName = app.getName();
|
||||
const showDev = isDev || options?.showDevItems;
|
||||
// 创建命名空间翻译函数
|
||||
// Create namespaced translation function
|
||||
const t = this.app.i18n.ns('menu');
|
||||
|
||||
// 添加调试日志
|
||||
// console.log('[MacOSMenu] 菜单渲染, i18n实例:', !!this.app.i18n);
|
||||
// Add debug logging
|
||||
// console.log('[MacOSMenu] Menu rendering, i18n instance:', !!this.app.i18n);
|
||||
|
||||
const template: MenuItemConstructorOptions[] = [
|
||||
{
|
||||
@@ -324,7 +324,7 @@ export class MacOSMenu extends BaseMenuPlatform implements IMenuPlatform {
|
||||
},
|
||||
{
|
||||
click: () => {
|
||||
// @ts-expect-error cache 目录好像暂时不在类型定义里
|
||||
// @ts-expect-error cache directory seems to be temporarily missing from type definitions
|
||||
const cachePath = app.getPath('cache');
|
||||
|
||||
const updaterCachePath = path.join(cachePath, `${app.getName()}-updater`);
|
||||
|
||||
@@ -43,7 +43,7 @@ export class WindowsMenu extends BaseMenuPlatform implements IMenuPlatform {
|
||||
|
||||
refresh(options?: MenuOptions): void {
|
||||
this.buildAndSetAppMenu(options);
|
||||
// 如果有必要更新托盘菜单,可以在这里添加逻辑
|
||||
// If it's necessary to update tray menu, logic can be added here
|
||||
}
|
||||
|
||||
private getAppMenuTemplate(options?: MenuOptions): MenuItemConstructorOptions[] {
|
||||
|
||||
@@ -1,4 +1,141 @@
|
||||
[
|
||||
{
|
||||
"children": {},
|
||||
"date": "2026-02-04",
|
||||
"version": "2.1.17"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Add the preview publish to market button preview check."]
|
||||
},
|
||||
"date": "2026-02-04",
|
||||
"version": "2.1.16"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Fixed the agents list the show updateAt time error."]
|
||||
},
|
||||
"date": "2026-02-04",
|
||||
"version": "2.1.15"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Fix cannot uncompressed messages."]
|
||||
},
|
||||
"date": "2026-02-04",
|
||||
"version": "2.1.14"
|
||||
},
|
||||
{
|
||||
"children": {},
|
||||
"date": "2026-02-03",
|
||||
"version": "2.1.13"
|
||||
},
|
||||
{
|
||||
"children": {},
|
||||
"date": "2026-02-03",
|
||||
"version": "2.1.12"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Hide password features when AUTH_DISABLE_EMAIL_PASSWORD is set."]
|
||||
},
|
||||
"date": "2026-02-02",
|
||||
"version": "2.1.11"
|
||||
},
|
||||
{
|
||||
"children": {},
|
||||
"date": "2026-02-02",
|
||||
"version": "2.1.10"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Use oauth2.link for generic OIDC provider account linking."]
|
||||
},
|
||||
"date": "2026-02-02",
|
||||
"version": "2.1.9"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"improvements": ["Improve tasks display."]
|
||||
},
|
||||
"date": "2026-02-01",
|
||||
"version": "2.1.8"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Add missing description parameter docs in Notebook system prompt."]
|
||||
},
|
||||
"date": "2026-02-01",
|
||||
"version": "2.1.7"
|
||||
},
|
||||
{
|
||||
"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."]
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
## chore(i18n): Adjust Latin language locales for terminology consistency
|
||||
|
||||
This comprehensive update ensures all Latin language locales (de-DE, fr-FR, es-ES, it-IT, pt-BR, nl-NL, pl-PL) follow the microcopy style guide's terminology requirements.
|
||||
|
||||
### Changes Made
|
||||
|
||||
**Total: 557 changes across 7 Latin locales**
|
||||
|
||||
#### Primary Terminology Updates
|
||||
1. **"Plugin" → "Skill"**
|
||||
- Fixed terminology inconsistency across all Latin languages
|
||||
- UI elements now consistently use "Skill" instead of localized equivalents
|
||||
- Includes both singular and plural forms: `plugin/Skill`, `plugins/Skills`
|
||||
|
||||
2. **"LobeChat" → "LobeHub"**
|
||||
- Updated brand name references to current branding
|
||||
|
||||
3. **"Agent" Terminology Consistency**
|
||||
- French: Fixed inconsistent "Assistant" → "Agent" usage in UI elements
|
||||
- Ensured consistent terminology across all languages
|
||||
|
||||
#### Per-Locale Breakdown
|
||||
- **de-DE (German)**: 267 changes
|
||||
- **fr-FR (French)**: 94 changes (including 7 Agent→Assistant fixes)
|
||||
- **es-ES (Spanish)**: 39 changes
|
||||
- **it-IT (Italian)**: 59 changes (including 18 plugin→skill fixes)
|
||||
- **pt-BR (Portuguese)**: 58 changes
|
||||
- **nl-NL (Dutch)**: 62 changes
|
||||
- **pl-PL (Polish)**: 28 changes
|
||||
|
||||
#### Files Modified
|
||||
- All 37 locale JSON files for each language (259 total files)
|
||||
- Includes: auth.json, chat.json, common.json, discover.json, plugin.json, setting.json, etc.
|
||||
|
||||
#### Key Improvements
|
||||
1. **Fixed Terminology**: Following microcopy guide's fixed terminology rules
|
||||
2. **Brand Consistency**: Changed all brand references to "LobeHub"
|
||||
3. **Natural Localization**: Maintained natural language patterns while ensuring consistency
|
||||
4. **User Experience**: Improved consistency across all Latin language interfaces
|
||||
|
||||
### Scripts Created
|
||||
Two utility scripts for future locale maintenance:
|
||||
- `scripts/adjust-latin-locales.py` - For common.json specific adjustments
|
||||
- `scripts/adjust-latin-locales-full.py` - For comprehensive adjustments across all files
|
||||
|
||||
### Review Notes
|
||||
- All changes maintain backward compatibility
|
||||
- No breaking changes to functionality
|
||||
- JSON files validated and remain syntactically correct
|
||||
- Changes reviewed against English base for consistency
|
||||
@@ -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'
|
||||
|
||||
@@ -12,7 +12,7 @@ DATABASE_URL=postgresql://postgres:uWNZugjBqixf8dxC@postgresql:5432/lobechat
|
||||
AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
|
||||
AUTH_SSO_PROVIDERS=zitadel
|
||||
# ZiTADEL provider configuration
|
||||
# Please refer to:https://lobehub.com/zh/docs/self-hosting/advanced/auth/providers/zitadel
|
||||
# Please refer to: https://lobehub.com/docs/self-hosting/auth/providers/zitadel
|
||||
AUTH_ZITADEL_ID=285945938244075523
|
||||
AUTH_ZITADEL_SECRET=hkbtzHLaCEIeHeFThym14UcydpmQiEB5JtAX08HSqSoJxhAlVVkyovTuNUZ5TNrT
|
||||
AUTH_ZITADEL_ISSUER=http://localhost:8080
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ DATABASE_URL=postgresql://postgres:uWNZugjBqixf8dxC@postgresql:5432/lobechat
|
||||
AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
|
||||
AUTH_SSO_PROVIDERS=zitadel
|
||||
# ZiTADEL 鉴权服务提供商部分
|
||||
# 请参考:https://lobehub.com/zh/docs/self-hosting/advanced/auth/next-auth/zitadel
|
||||
# 请参考:https://lobehub.com/zh/docs/self-hosting/auth/providers/zitadel
|
||||
AUTH_ZITADEL_ID=285945938244075523
|
||||
AUTH_ZITADEL_SECRET=hkbtzHLaCEIeHeFThym14UcydpmQiEB5JtAX08HSqSoJxhAlVVkyovTuNUZ5TNrT
|
||||
AUTH_ZITADEL_ISSUER=http://localhost:8080
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ DATABASE_URL=postgresql://postgres:uWNZugjBqixf8dxC@postgresql:5432/lobe
|
||||
|
||||
# Authentication related environment variables
|
||||
# Supports Auth0, Azure AD, GitHub, Authentik, Zitadel, Logto, etc.
|
||||
# For supported providers, see: https://lobehub.com/docs/self-hosting/advanced/auth
|
||||
# For supported providers, see: https://lobehub.com/docs/self-hosting/auth
|
||||
# If you have ACCESS_CODE, please remove it. We use Better Auth as the sole authentication source
|
||||
# Required: Auth secret key. Generate with: openssl rand -base64 32
|
||||
AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
|
||||
@@ -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
|
||||
|
||||
@@ -11,7 +11,7 @@ DATABASE_URL=postgresql://postgres:uWNZugjBqixf8dxC@postgresql:5432/lobe
|
||||
|
||||
# 鉴权服务必需的环境变量
|
||||
# 可以使用 Auth0、Azure AD、GitHub、Authentik、Zitadel、Logto 等,如有其他接入诉求欢迎提 PR
|
||||
# 目前支持的鉴权服务提供商请参考:https://lobehub.com/zh/docs/self-hosting/advanced/auth
|
||||
# 目前支持的鉴权服务提供商请参考:https://lobehub.com/zh/docs/self-hosting/auth
|
||||
# 如果你有 ACCESS_CODE,请务必清空,我们以 Better Auth 作为唯一鉴权来源
|
||||
# 必填,用于鉴权的密钥,可以使用 openssl rand -base64 32 生成
|
||||
AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
|
||||
@@ -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
|
||||
|
||||
@@ -17,7 +17,7 @@ AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
|
||||
AUTH_SSO_PROVIDERS=zitadel
|
||||
|
||||
# ZiTADEL provider configuration
|
||||
# Please refer to:https://lobehub.com/zh/docs/self-hosting/advanced/auth/providers/zitadel
|
||||
# Please refer to: https://lobehub.com/docs/self-hosting/auth/providers/zitadel
|
||||
AUTH_ZITADEL_ID=285934220675723622
|
||||
AUTH_ZITADEL_SECRET=pe7Nh3lopXkZkfqh5YEDYI2xsbIz08eZKqInOUZxssd3refRia518Apbv3DZ
|
||||
AUTH_ZITADEL_ISSUER=https://zitadel.example.com
|
||||
@@ -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
|
||||
|
||||
@@ -16,7 +16,7 @@ AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
|
||||
AUTH_SSO_PROVIDERS=zitadel
|
||||
|
||||
# ZiTADEL 鉴权服务提供商部分
|
||||
# 请参考:https://lobehub.com/zh/docs/self-hosting/advanced/auth/next-auth/zitadel
|
||||
# 请参考:https://lobehub.com/zh/docs/self-hosting/auth/providers/zitadel
|
||||
AUTH_ZITADEL_ID=285934220675723622
|
||||
AUTH_ZITADEL_SECRET=pe7Nh3lopXkZkfqh5YEDYI2xsbIz08eZKqInOUZxssd3refRia518Apbv3DZ
|
||||
AUTH_ZITADEL_ISSUER=https://zitadel.example.com
|
||||
@@ -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 服务商,并改进知识库功能。
|
||||
|
||||
## 🌟 重要更新
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"image": "/blog/assets7f3b38c1d76cceb91edb29d6b1eb60db.webp",
|
||||
"id": "2025-12-20-mcp",
|
||||
"date": "2025-12-20",
|
||||
"versionRange": ["1.142.8", "1.143"]
|
||||
"versionRange": ["1.142.8", "1.143.0"]
|
||||
},
|
||||
{
|
||||
"image": "/blog/assets3a7f0b29839603336e39e923b423409b.webp",
|
||||
|
||||
@@ -114,7 +114,7 @@ AUTH_OKTA_ISSUER: process.env.AUTH_OKTA_ISSUER,
|
||||
|
||||
### Step 4: Update Documentation (Optional)
|
||||
|
||||
Add provider documentation in `docs/self-hosting/advanced/auth.mdx` and `docs/self-hosting/advanced/auth.zh-CN.mdx`.
|
||||
Add provider documentation in `docs/self-hosting/auth.mdx` and `docs/self-hosting/auth.zh-CN.mdx`.
|
||||
|
||||
## Adding a Built-in Provider
|
||||
|
||||
|
||||
@@ -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),你需要完成以下步骤:
|
||||
|
||||
@@ -115,7 +115,7 @@ AUTH_OKTA_ISSUER: process.env.AUTH_OKTA_ISSUER,
|
||||
|
||||
### 步骤 4: 更新文档(可选)
|
||||
|
||||
在 `docs/self-hosting/advanced/auth.mdx` 和 `docs/self-hosting/advanced/auth.zh-CN.mdx` 中添加提供商文档。
|
||||
在 `docs/self-hosting/auth.mdx` 和 `docs/self-hosting/auth.zh-CN.mdx` 中添加提供商文档。
|
||||
|
||||
## 添加内置提供商
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,7 +10,8 @@ tags:
|
||||
- PNPM
|
||||
- Bun
|
||||
- Git
|
||||
- VSCode
|
||||
- Docker
|
||||
- PostgreSQL
|
||||
---
|
||||
|
||||
# Environment Setup Guide
|
||||
@@ -35,30 +36,83 @@ First, you need to install the following software:
|
||||
- PNPM: We use PNPM as the preferred package manager. You can download and install it from the [PNPM official website](https://pnpm.io/installation).
|
||||
- Bun: We use Bun as the npm scripts runner. You can download and install it from the [Bun official website](https://bun.com/docs/installation).
|
||||
- Git: We use Git for version control. You can download and install it from the Git official website.
|
||||
- Docker: Required for running PostgreSQL, MinIO, and other services. You can download and install it from the [Docker official website](https://www.docker.com/get-started).
|
||||
- IDE: You can choose your preferred integrated development environment (IDE). We recommend using WebStorm/VSCode.
|
||||
|
||||
### 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
|
||||
|
||||
After installing the above software, you can start setting up the LobeHub project.
|
||||
|
||||
1. **Get the code**: First, you need to clone the LobeHub codebase from GitHub. Run the following command in the terminal:
|
||||
#### 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
|
||||
cd lobehub
|
||||
```
|
||||
|
||||
2. **Install dependencies**: Then, navigate to the project directory and use PNPM to install the project's dependencies:
|
||||
#### 2. Install Dependencies
|
||||
|
||||
Use PNPM to install the project's dependencies:
|
||||
|
||||
```bash
|
||||
cd lobe-chat
|
||||
pnpm i
|
||||
```
|
||||
|
||||
3. **Start the development server**: After installing the dependencies, you can start the development server:
|
||||
#### 3. Configure Environment
|
||||
|
||||
Copy the example environment file to create your Docker Compose configuration:
|
||||
|
||||
```bash
|
||||
cp docker-compose/local/.env.example docker-compose/local/.env
|
||||
```
|
||||
|
||||
Edit `docker-compose/local/.env` as needed for your development setup. This file contains all necessary environment variables for the Docker services and configures:
|
||||
|
||||
- **Database**: PostgreSQL with connection string
|
||||
- **Authentication**: Better Auth with Casdoor SSO
|
||||
- **Storage**: MinIO S3-compatible storage
|
||||
- **Search**: SearXNG search engine
|
||||
|
||||
#### 4. Start Docker Services
|
||||
|
||||
Start all required services using Docker Compose:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.development.yml up -d
|
||||
```
|
||||
|
||||
This will start the following services:
|
||||
|
||||
- PostgreSQL database (port 5432)
|
||||
- MinIO storage (port 9000)
|
||||
- Casdoor authentication (port 8000)
|
||||
- SearXNG search (port 8080)
|
||||
|
||||
You can check all Docker services are running by running:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.development.yml ps
|
||||
```
|
||||
|
||||
#### 5. Run Database Migrations
|
||||
|
||||
Execute the database migration script to create all necessary tables:
|
||||
|
||||
```bash
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
You should see: `✅ database migration pass.`
|
||||
|
||||
#### 6. Start Development Server
|
||||
|
||||
Launch the LobeHub development server:
|
||||
|
||||
```bash
|
||||
bun run dev
|
||||
@@ -68,19 +122,127 @@ Now, you can open `http://localhost:3010` in your browser, and you should see th
|
||||
|
||||

|
||||
|
||||
## Working with Server-Side Features
|
||||
## Image Generation Development
|
||||
|
||||
The basic setup above uses LobeHub's client-side database mode. If you need to work with server-side features such as:
|
||||
When working with image generation features (text-to-image, image-to-image), the Docker Compose setup already includes all necessary storage services for handling generated images and user uploads.
|
||||
|
||||
- Database persistence
|
||||
- File uploads and storage
|
||||
- Image generation
|
||||
- Multi-user authentication
|
||||
- Advanced server-side integrations
|
||||
### Image Generation Configuration
|
||||
|
||||
Please refer to the [Work with Server-Side Database](/docs/development/basic/work-with-server-side-database) guide for complete setup instructions.
|
||||
The existing Docker Compose configuration already includes MinIO storage service and all necessary environment variables in `docker-compose/local/.env.example`. No additional setup is required.
|
||||
|
||||
### Image Generation Architecture
|
||||
|
||||
The image generation feature requires:
|
||||
|
||||
- **PostgreSQL**: Stores metadata about generated images
|
||||
- **MinIO/S3**: Stores the actual image files
|
||||
|
||||
### Storage Configuration
|
||||
|
||||
The `docker-compose/local/.env.example` file includes all necessary S3 environment variables:
|
||||
|
||||
```bash
|
||||
# S3 Storage Configuration (MinIO for local development)
|
||||
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_ENABLE_PATH_STYLE=1 # Required for MinIO
|
||||
S3_SET_ACL=0 # MinIO compatibility
|
||||
```
|
||||
|
||||
### File Storage Structure
|
||||
|
||||
Generated images and user uploads are organized in the MinIO bucket:
|
||||
|
||||
```
|
||||
lobe/ # S3 Bucket (MINIO_LOBE_BUCKET)
|
||||
├── generated/ # Generated images
|
||||
│ └── {userId}/
|
||||
│ └── {sessionId}/
|
||||
│ └── {imageId}.png
|
||||
└── uploads/ # User uploads for image-to-image
|
||||
└── {userId}/
|
||||
└── {fileId}.{ext}
|
||||
```
|
||||
|
||||
### Development Workflow for Images
|
||||
|
||||
When developing image generation features, generated images will be:
|
||||
|
||||
1. Created by the AI model
|
||||
2. Uploaded to S3/MinIO via presigned URLs
|
||||
3. Metadata stored in PostgreSQL
|
||||
4. Served via the public S3 URL
|
||||
|
||||
Example code for testing image upload:
|
||||
|
||||
```typescript
|
||||
// Example: Upload generated image
|
||||
const uploadUrl = await trpc.upload.createPresignedUrl.mutate({
|
||||
filename: 'generated-image.png',
|
||||
contentType: 'image/png',
|
||||
});
|
||||
|
||||
// Upload to S3
|
||||
await fetch(uploadUrl, {
|
||||
method: 'PUT',
|
||||
body: imageBlob,
|
||||
headers: { 'Content-Type': 'image/png' },
|
||||
});
|
||||
```
|
||||
|
||||
### Service URLs
|
||||
|
||||
When running with Docker Compose development setup:
|
||||
|
||||
- **PostgreSQL**: `postgres://postgres@localhost:5432/LobeHub`
|
||||
- **MinIO API**: `http://localhost:9000`
|
||||
- **MinIO Console**: `http://localhost:9001` (admin/CHANGE\_THIS\_PASSWORD\_IN\_PRODUCTION)
|
||||
- **Application**: `http://localhost:3010`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Reset Services
|
||||
|
||||
If you encounter issues, you can reset the entire stack:
|
||||
|
||||
```bash
|
||||
# Stop and remove all containers
|
||||
docker-compose -f docker-compose.development.yml down
|
||||
|
||||
# Remove volumes (this will delete all data)
|
||||
docker-compose -f docker-compose.development.yml down -v
|
||||
|
||||
# Start fresh
|
||||
docker-compose -f docker-compose.development.yml up -d
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
### Port Conflicts
|
||||
|
||||
If ports are already in use:
|
||||
|
||||
```bash
|
||||
# Check what's using the ports
|
||||
lsof -i :5432 # PostgreSQL
|
||||
lsof -i :9000 # MinIO API
|
||||
lsof -i :9001 # MinIO Console
|
||||
```
|
||||
|
||||
### Database Migrations
|
||||
|
||||
The setup script runs migrations automatically. If you need to run them manually:
|
||||
|
||||
```bash
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
Note: In development mode with `pnpm dev:desktop`, migrations also run automatically on startup.
|
||||
|
||||
---
|
||||
|
||||
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
|
||||
|
||||
@@ -7,6 +7,8 @@ tags:
|
||||
- Node.js
|
||||
- PNPM
|
||||
- Git
|
||||
- Docker
|
||||
- PostgreSQL
|
||||
---
|
||||
|
||||
# 环境设置指南
|
||||
@@ -29,32 +31,85 @@ tags:
|
||||
|
||||
- Node.js:LobeHub 是基于 Node.js 构建的,因此你需要安装 Node.js。我们建议安装最新的稳定版。
|
||||
- PNPM:我们使用 PNPM 作为管理器。你可以从 [pnpm 的官方网站](https://pnpm.io/installation) 上下载并安装。
|
||||
- Bun:我们使用 Bun 作为 npm scripts runner, 你可以从 [Bun 的官方网站](https://bun.com/docs/installation) 上下载并安装。
|
||||
- Bun:我们使用 Bun 作为 npm scripts runner,你可以从 [Bun 的官方网站](https://bun.com/docs/installation) 上下载并安装。
|
||||
- Git:我们使用 Git 进行版本控制。你可以从 Git 的官方网站上下载并安装。
|
||||
- Docker:用于运行 PostgreSQL、MinIO 等服务。你可以从 [Docker 官方网站](https://www.docker.com/get-started) 下载并安装。
|
||||
- IDE:你可以选择你喜欢的集成开发环境(IDE),我们推荐使用 WebStorm/VSCode。
|
||||
|
||||
### 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) 中推荐安装的扩展获得最佳开发体验。
|
||||
|
||||
### 项目设置
|
||||
|
||||
完成上述软件的安装后,你可以开始设置 LobeHub 项目了。
|
||||
|
||||
1. **获取代码**:首先,你需要从 GitHub 上克隆 LobeHub 的代码库。在终端中运行以下命令:
|
||||
#### 1. 获取代码
|
||||
|
||||
首先,你需要从 GitHub 上克隆 LobeHub 的代码库。在终端中运行以下命令:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/lobehub/lobe-chat.git
|
||||
git clone https://github.com/lobehub/lobehub.git
|
||||
cd lobehub
|
||||
```
|
||||
|
||||
2. **安装依赖**:然后,进入项目目录,并使用 `pnpm` 安装项目的依赖包:
|
||||
#### 2. 安装依赖
|
||||
|
||||
使用 PNPM 安装项目的依赖包:
|
||||
|
||||
```bash
|
||||
cd lobe-chat
|
||||
pnpm i
|
||||
```
|
||||
|
||||
3. **启动开发服务器**:安装完依赖后,你可以启动开发服务器:
|
||||
#### 3. 配置环境
|
||||
|
||||
复制示例环境文件来创建你的 Docker Compose 配置:
|
||||
|
||||
```bash
|
||||
cp docker-compose/local/.env.example docker-compose/local/.env
|
||||
```
|
||||
|
||||
根据需要编辑 `docker-compose/local/.env` 文件以适应你的开发设置。此文件包含 Docker 服务所需的所有环境变量,配置了:
|
||||
|
||||
- **数据库**:带连接字符串的 PostgreSQL
|
||||
- **身份验证**:带 Casdoor SSO 的 Better Auth
|
||||
- **存储**:MinIO S3 兼容存储
|
||||
- **搜索**:SearXNG 搜索引擎
|
||||
|
||||
#### 4. 启动 Docker 服务
|
||||
|
||||
使用 Docker Compose 启动所有必需的服务:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.development.yml up -d
|
||||
```
|
||||
|
||||
这将启动以下服务:
|
||||
|
||||
- PostgreSQL 数据库(端口 5432)
|
||||
- MinIO 存储(端口 9000)
|
||||
- Casdoor 身份验证(端口 8000)
|
||||
- SearXNG 搜索(端口 8080)
|
||||
|
||||
可以通过运行以下命令检查所有 Docker 服务运行状态:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.development.yml ps
|
||||
```
|
||||
|
||||
#### 5. 运行数据库迁移
|
||||
|
||||
执行数据库迁移脚本以创建所有必要的表:
|
||||
|
||||
```bash
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
预期输出:`✅ database migration pass.`
|
||||
|
||||
#### 6. 启动开发服务器
|
||||
|
||||
启动 LobeHub 开发服务器:
|
||||
|
||||
```bash
|
||||
bun run dev
|
||||
@@ -64,19 +119,127 @@ bun run dev
|
||||
|
||||

|
||||
|
||||
## 使用服务端功能
|
||||
## 图像生成开发
|
||||
|
||||
上述基础设置使用 LobeHub 的客户端数据库模式。如果你需要开发服务端功能,如:
|
||||
在开发图像生成功能(文生图、图生图)时,Docker Compose 配置已经包含了处理生成图像和用户上传所需的所有存储服务。
|
||||
|
||||
- 数据库持久化
|
||||
- 文件上传和存储
|
||||
- 图像生成
|
||||
- 多用户身份验证
|
||||
- 高级服务端集成
|
||||
### 图像生成配置
|
||||
|
||||
请参考[使用服务端数据库](/docs/development/basic/work-with-server-side-database)指南获得完整的设置说明。
|
||||
现有的 Docker Compose 配置已经包含了 MinIO 存储服务以及 `docker-compose/local/.env.example` 中的所有必要环境变量。无需额外配置。
|
||||
|
||||
### 图像生成架构
|
||||
|
||||
图像生成功能需要:
|
||||
|
||||
- **PostgreSQL**:存储生成图像的元数据
|
||||
- **MinIO/S3**:存储实际的图像文件
|
||||
|
||||
### 存储配置
|
||||
|
||||
`docker-compose/local/.env.example` 文件包含所有必要的 S3 环境变量:
|
||||
|
||||
```bash
|
||||
# S3 存储配置(本地开发使用 MinIO)
|
||||
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_ENABLE_PATH_STYLE=1 # MinIO 必需
|
||||
S3_SET_ACL=0 # MinIO 兼容性
|
||||
```
|
||||
|
||||
### 文件存储结构
|
||||
|
||||
生成的图像和用户上传在 MinIO 存储桶中按以下方式组织:
|
||||
|
||||
```
|
||||
lobe/ # S3 存储桶 (MINIO_LOBE_BUCKET)
|
||||
├── generated/ # 生成的图像
|
||||
│ └── {userId}/
|
||||
│ └── {sessionId}/
|
||||
│ └── {imageId}.png
|
||||
└── uploads/ # 用户上传的图像处理文件
|
||||
└── {userId}/
|
||||
└── {fileId}.{ext}
|
||||
```
|
||||
|
||||
### 图像开发工作流
|
||||
|
||||
在开发图像生成功能时,生成的图像将:
|
||||
|
||||
1. 由 AI 模型创建
|
||||
2. 通过预签名 URL 上传到 S3/MinIO
|
||||
3. 元数据存储在 PostgreSQL 中
|
||||
4. 通过公共 S3 URL 提供服务
|
||||
|
||||
测试图像上传的示例代码:
|
||||
|
||||
```typescript
|
||||
// 示例:上传生成的图像
|
||||
const uploadUrl = await trpc.upload.createPresignedUrl.mutate({
|
||||
filename: 'generated-image.png',
|
||||
contentType: 'image/png',
|
||||
});
|
||||
|
||||
// 上传到 S3
|
||||
await fetch(uploadUrl, {
|
||||
method: 'PUT',
|
||||
body: imageBlob,
|
||||
headers: { 'Content-Type': 'image/png' },
|
||||
});
|
||||
```
|
||||
|
||||
### 服务地址
|
||||
|
||||
运行 Docker Compose 开发环境时:
|
||||
|
||||
- **PostgreSQL**:`postgres://postgres@localhost:5432/LobeHub`
|
||||
- **MinIO API**:`http://localhost:9000`
|
||||
- **MinIO 控制台**:`http://localhost:9001` (admin/CHANGE\_THIS\_PASSWORD\_IN\_PRODUCTION)
|
||||
- **应用程序**:`http://localhost:3010`
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 重置服务
|
||||
|
||||
如遇到问题,可以重置整个服务堆栈:
|
||||
|
||||
```bash
|
||||
# 停止并删除所有容器
|
||||
docker-compose -f docker-compose.development.yml down
|
||||
|
||||
# 删除卷(这将删除所有数据)
|
||||
docker-compose -f docker-compose.development.yml down -v
|
||||
|
||||
# 重新启动
|
||||
docker-compose -f docker-compose.development.yml up -d
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
### 端口冲突
|
||||
|
||||
如果端口已被占用:
|
||||
|
||||
```bash
|
||||
# 检查端口使用情况
|
||||
lsof -i :5432 # PostgreSQL
|
||||
lsof -i :9000 # MinIO API
|
||||
lsof -i :9001 # MinIO 控制台
|
||||
```
|
||||
|
||||
### 数据库迁移
|
||||
|
||||
配置脚本会自动运行迁移。如需手动运行:
|
||||
|
||||
```bash
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
注意:在使用 `pnpm dev:desktop` 的开发模式下,迁移也会在启动时自动运行。
|
||||
|
||||
---
|
||||
|
||||
在开发过程中,如果你在环境设置上遇到任何问题,或者有任何关于 LobeHub 开发的问题,欢迎随时向我们提问。我们期待看到你的贡献!
|
||||
|
||||
[codespaces-link]: https://codespaces.new/lobehub/lobe-chat
|
||||
[codespaces-link]: https://codespaces.new/lobehub/lobehub
|
||||
[codespaces-shield]: https://github.com/codespaces/badge.svg
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
---
|
||||
title: Work with Server-Side Database
|
||||
description: Learn how to set up a server-side database for LobeHub with Docker.
|
||||
tags:
|
||||
- LobeHub
|
||||
- Server-Side Database
|
||||
- Docker
|
||||
- PostgreSQL
|
||||
- MinIO
|
||||
---
|
||||
|
||||
# Work with Server-Side Database
|
||||
|
||||
LobeHub provides a battery-included experience with its client-side database.
|
||||
While some features you really care about is only available at a server-side development.
|
||||
|
||||
In order to work with the aspect of server-side database,
|
||||
you can setup all the prerequisites by following the [Deploying Server-Side Database](https://lobehub.com/docs/self-hosting/server-database) story.
|
||||
But here is the easier approach that can reduce your pain.
|
||||
|
||||
## Quick Setup
|
||||
|
||||
### Environment Configuration
|
||||
|
||||
First, copy the example environment file to create your Docker Compose configuration:
|
||||
|
||||
```bash
|
||||
cp docker-compose/local/.env.example docker-compose/local/.env
|
||||
```
|
||||
|
||||
Edit `docker-compose/local/.env` as needed for your development setup. This file contains all necessary environment variables for the Docker services and configures:
|
||||
|
||||
- **Database**: PostgreSQL with connection string
|
||||
- **Authentication**: NextAuth with Casdoor SSO
|
||||
- **Storage**: MinIO S3-compatible storage
|
||||
- **Search**: SearXNG search engine
|
||||
|
||||
### Start Docker Services
|
||||
|
||||
Start all required services using Docker Compose:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.development.yml up -d
|
||||
```
|
||||
|
||||
This will start the following services:
|
||||
|
||||
- PostgreSQL database (port 5432)
|
||||
- MinIO storage (port 9000)
|
||||
- Casdoor authentication (port 8000)
|
||||
- SearXNG search (port 8080)
|
||||
|
||||
### Run Database Migrations
|
||||
|
||||
Execute the database migration script to create all necessary tables:
|
||||
|
||||
```bash
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
You should see: `✅ database migration pass.`
|
||||
|
||||
### Start Development Server
|
||||
|
||||
Launch the LobeHub development server:
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
The server will start on `http://localhost:3010`
|
||||
|
||||
And you can check all Docker services are running by running:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.development.yml ps
|
||||
```
|
||||
|
||||
## Image Generation Development
|
||||
|
||||
When working with image generation features (text-to-image, image-to-image), the Docker Compose setup already includes all necessary storage services for handling generated images and user uploads.
|
||||
|
||||
### Image Generation Configuration
|
||||
|
||||
The existing Docker Compose configuration already includes MinIO storage service and all necessary environment variables in `docker-compose/local/.env.example`. No additional setup is required.
|
||||
|
||||
### Image Generation Architecture
|
||||
|
||||
The image generation feature requires:
|
||||
|
||||
- **PostgreSQL**: Stores metadata about generated images
|
||||
- **MinIO/S3**: Stores the actual image files
|
||||
|
||||
### Storage Configuration
|
||||
|
||||
The `docker-compose/local/.env.example` file includes all necessary S3 environment variables:
|
||||
|
||||
```bash
|
||||
# S3 Storage Configuration (MinIO for local development)
|
||||
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
|
||||
```
|
||||
|
||||
### File Storage Structure
|
||||
|
||||
Generated images and user uploads are organized in the MinIO bucket:
|
||||
|
||||
```
|
||||
lobe/ # S3 Bucket (MINIO_LOBE_BUCKET)
|
||||
├── generated/ # Generated images
|
||||
│ └── {userId}/
|
||||
│ └── {sessionId}/
|
||||
│ └── {imageId}.png
|
||||
└── uploads/ # User uploads for image-to-image
|
||||
└── {userId}/
|
||||
└── {fileId}.{ext}
|
||||
```
|
||||
|
||||
### Development Workflow for Images
|
||||
|
||||
When developing image generation features, generated images will be:
|
||||
|
||||
1. Created by the AI model
|
||||
2. Uploaded to S3/MinIO via presigned URLs
|
||||
3. Metadata stored in PostgreSQL
|
||||
4. Served via the public S3 URL
|
||||
|
||||
Example code for testing image upload:
|
||||
|
||||
```typescript
|
||||
// Example: Upload generated image
|
||||
const uploadUrl = await trpc.upload.createPresignedUrl.mutate({
|
||||
filename: 'generated-image.png',
|
||||
contentType: 'image/png',
|
||||
});
|
||||
|
||||
// Upload to S3
|
||||
await fetch(uploadUrl, {
|
||||
method: 'PUT',
|
||||
body: imageBlob,
|
||||
headers: { 'Content-Type': 'image/png' },
|
||||
});
|
||||
```
|
||||
|
||||
### Service URLs
|
||||
|
||||
When running with Docker Compose development setup:
|
||||
|
||||
- **PostgreSQL**: `postgres://postgres@localhost:5432/LobeHub`
|
||||
- **MinIO API**: `http://localhost:9000`
|
||||
- **MinIO Console**: `http://localhost:9001` (admin/CHANGE\_THIS\_PASSWORD\_IN\_PRODUCTION)
|
||||
- **Application**: `http://localhost:3010`
|
||||
|
||||
### Reset Services
|
||||
|
||||
If you encounter issues, you can reset the entire stack:
|
||||
|
||||
```bash
|
||||
# Stop and remove all containers
|
||||
docker-compose -f docker-compose.development.yml down
|
||||
|
||||
# Remove volumes (this will delete all data)
|
||||
docker-compose -f docker-compose.development.yml down -v
|
||||
|
||||
# Start fresh
|
||||
docker-compose -f docker-compose.development.yml up -d
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
#### Port Conflicts
|
||||
|
||||
If ports are already in use:
|
||||
|
||||
```bash
|
||||
# Check what's using the ports
|
||||
lsof -i :5432 # PostgreSQL
|
||||
lsof -i :9000 # MinIO API
|
||||
lsof -i :9001 # MinIO Console
|
||||
```
|
||||
|
||||
#### Database Migrations
|
||||
|
||||
The setup script runs migrations automatically. If you need to run them manually:
|
||||
|
||||
```bash
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
Note: In development mode with `pnpm dev:desktop`, migrations also run automatically on startup.
|
||||
@@ -1,196 +0,0 @@
|
||||
---
|
||||
title: 使用服务端数据库
|
||||
description: 快速设置 LobeHub 服务端数据库,支持 Docker 和图像生成。
|
||||
tags:
|
||||
- 服务端数据库
|
||||
- LobeHub
|
||||
- Docker
|
||||
- 图像生成
|
||||
- PostgreSQL
|
||||
---
|
||||
|
||||
# 使用服务端数据库
|
||||
|
||||
LobeHub 提供了内置的客户端数据库体验。
|
||||
但某些重要功能仅在服务端开发中可用。
|
||||
|
||||
为了使用服务端数据库功能,
|
||||
需要参考 [部署服务端数据库](https://lobehub.com/docs/self-hosting/server-database) 的说明来配置所有前置条件。
|
||||
本文档提供了一个更简化的配置方法,能够在本地开发时快速启动简化的服务端环境。
|
||||
|
||||
## 快速设置
|
||||
|
||||
### 环境配置
|
||||
|
||||
首先,复制示例环境文件来创建你的 Docker Compose 配置:
|
||||
|
||||
```bash
|
||||
cp docker-compose/local/.env.example docker-compose/local/.env
|
||||
```
|
||||
|
||||
根据需要编辑 `docker-compose/local/.env` 文件以适应你的开发设置。此文件包含 Docker 服务所需的所有环境变量,配置了:
|
||||
|
||||
- **数据库**: 带连接字符串的 PostgreSQL
|
||||
- **身份验证**: 带 Casdoor SSO 的 NextAuth
|
||||
- **存储**: MinIO S3 兼容存储
|
||||
- **搜索**: SearXNG 搜索引擎
|
||||
|
||||
### 启动 Docker 服务
|
||||
|
||||
使用 Docker Compose 启动所有必需的服务:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.development.yml up -d
|
||||
```
|
||||
|
||||
这将启动以下服务:
|
||||
|
||||
- PostgreSQL 数据库(端口 5432)
|
||||
- MinIO 存储(端口 9000)
|
||||
- Casdoor 身份验证(端口 8000)
|
||||
- SearXNG 搜索(端口 8080)
|
||||
|
||||
### 运行数据库迁移
|
||||
|
||||
执行数据库迁移脚本以创建所有必要的表:
|
||||
|
||||
```bash
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
预期输出:`✅ database migration pass.`
|
||||
|
||||
### 启动开发服务器
|
||||
|
||||
启动 LobeHub 开发服务器:
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
服务器将在 `http://localhost:3010` 上启动
|
||||
|
||||
可以通过运行以下命令检查所有 Docker 服务运行状态:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.development.yml ps
|
||||
```
|
||||
|
||||
## 图像生成开发
|
||||
|
||||
在开发图像生成功能(文生图、图生图)时,Docker Compose 配置已经包含了处理生成图像和用户上传所需的所有存储服务。
|
||||
|
||||
### 图像生成配置
|
||||
|
||||
现有的 Docker Compose 配置已经包含了 MinIO 存储服务以及 `docker-compose/local/.env.example` 中的所有必要环境变量。无需额外配置。
|
||||
|
||||
### 图像生成架构
|
||||
|
||||
图像生成功能需要:
|
||||
|
||||
- **PostgreSQL**:存储生成图像的元数据
|
||||
- **MinIO/S3**:存储实际的图像文件
|
||||
|
||||
### 存储配置
|
||||
|
||||
`docker-compose/local/.env.example` 文件包含所有必要的 S3 环境变量:
|
||||
|
||||
```bash
|
||||
# S3 存储配置(本地开发使用 MinIO)
|
||||
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 兼容性
|
||||
```
|
||||
|
||||
### 文件存储结构
|
||||
|
||||
生成的图像和用户上传在 MinIO 存储桶中按以下方式组织:
|
||||
|
||||
```
|
||||
lobe/ # S3 存储桶 (MINIO_LOBE_BUCKET)
|
||||
├── generated/ # 生成的图像
|
||||
│ └── {userId}/
|
||||
│ └── {sessionId}/
|
||||
│ └── {imageId}.png
|
||||
└── uploads/ # 用户上传的图像处理文件
|
||||
└── {userId}/
|
||||
└── {fileId}.{ext}
|
||||
```
|
||||
|
||||
### 图像开发工作流
|
||||
|
||||
在开发图像生成功能时,生成的图像将:
|
||||
|
||||
1. 由 AI 模型创建
|
||||
2. 通过预签名 URL 上传到 S3/MinIO
|
||||
3. 元数据存储在 PostgreSQL 中
|
||||
4. 通过公共 S3 URL 提供服务
|
||||
|
||||
测试图像上传的示例代码:
|
||||
|
||||
```typescript
|
||||
// 示例:上传生成的图像
|
||||
const uploadUrl = await trpc.upload.createPresignedUrl.mutate({
|
||||
filename: 'generated-image.png',
|
||||
contentType: 'image/png',
|
||||
});
|
||||
|
||||
// 上传到 S3
|
||||
await fetch(uploadUrl, {
|
||||
method: 'PUT',
|
||||
body: imageBlob,
|
||||
headers: { 'Content-Type': 'image/png' },
|
||||
});
|
||||
```
|
||||
|
||||
### 服务地址
|
||||
|
||||
运行 Docker Compose 开发环境时:
|
||||
|
||||
- **PostgreSQL**:`postgres://postgres@localhost:5432/LobeHub`
|
||||
- **MinIO API**:`http://localhost:9000`
|
||||
- **MinIO 控制台**:`http://localhost:9001` (admin/CHANGE\_THIS\_PASSWORD\_IN\_PRODUCTION)
|
||||
- **应用程序**:`http://localhost:3010`
|
||||
|
||||
### 重置服务
|
||||
|
||||
如遇到问题,可以重置整个服务堆栈:
|
||||
|
||||
```bash
|
||||
# 停止并删除所有容器
|
||||
docker-compose -f docker-compose.development.yml down
|
||||
|
||||
# 删除卷(这将删除所有数据)
|
||||
docker-compose -f docker-compose.development.yml down -v
|
||||
|
||||
# 重新启动
|
||||
docker-compose -f docker-compose.development.yml up -d
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
### 故障排除
|
||||
|
||||
#### 端口冲突
|
||||
|
||||
如果端口已被占用:
|
||||
|
||||
```bash
|
||||
# 检查端口使用情况
|
||||
lsof -i :5432 # PostgreSQL
|
||||
lsof -i :9000 # MinIO API
|
||||
lsof -i :9001 # MinIO 控制台
|
||||
```
|
||||
|
||||
#### 数据库迁移
|
||||
|
||||
配置脚本会自动运行迁移。如需手动运行:
|
||||
|
||||
```bash
|
||||
pnpm db:migrate
|
||||
```
|
||||
|
||||
注意:在使用 `pnpm dev:desktop` 的开发模式下,迁移也会在启动时自动运行。
|
||||
@@ -643,6 +643,7 @@ table messages {
|
||||
thread_id [name: 'messages_thread_id_idx']
|
||||
agent_id [name: 'messages_agent_id_idx']
|
||||
group_id [name: 'messages_group_id_idx']
|
||||
message_group_id [name: 'messages_message_group_id_idx']
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user