前端代码初始化
parent
c4b3f8f8b8
commit
93107afa10
@ -0,0 +1,3 @@
|
||||
[install.lockfile]
|
||||
|
||||
save = false
|
@ -0,0 +1 @@
|
||||
module.exports = require('@lobehub/lint').changelog;
|
@ -0,0 +1 @@
|
||||
module.exports = require('@lobehub/lint').commitlint;
|
@ -0,0 +1,9 @@
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
node_modules
|
||||
npm-debug.log
|
||||
.next
|
||||
.git
|
||||
.github
|
||||
*.md
|
||||
.env.example
|
@ -0,0 +1,16 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
@ -0,0 +1,195 @@
|
||||
# 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
|
||||
|
||||
|
||||
########################################
|
||||
######## Model Provider Service ########
|
||||
########################################
|
||||
|
||||
### OpenAI ###
|
||||
|
||||
# you openai api key
|
||||
OPENAI_API_KEY=sk-xxxxxxxxx
|
||||
|
||||
# use a proxy to connect to the OpenAI API
|
||||
# OPENAI_PROXY_URL=https://api.openai.com/v1
|
||||
|
||||
# add your custom model name, multi model separate by comma. for example gpt-3.5-1106,gpt-4-1106
|
||||
# OPENAI_MODEL_LIST=gpt-3.5-turbo
|
||||
|
||||
|
||||
### Azure OpenAI ###
|
||||
|
||||
# you can learn azure OpenAI Service on https://learn.microsoft.com/en-us/azure/ai-services/openai/overview
|
||||
# use Azure OpenAI Service by uncomment the following line
|
||||
|
||||
# The API key you applied for on the Azure OpenAI account page, which can be found in the "Keys and Endpoints" section.
|
||||
# AZURE_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
# The endpoint you applied for on the Azure OpenAI account page, which can be found in the "Keys and Endpoints" section.
|
||||
# AZURE_ENDPOINT=https://docs-test-001.openai.azure.com
|
||||
|
||||
# Azure's API version, follows the YYYY-MM-DD format
|
||||
# AZURE_API_VERSION=2024-06-01
|
||||
|
||||
|
||||
### Anthropic Service ####
|
||||
|
||||
# ANTHROPIC_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
# use a proxy to connect to the Anthropic API
|
||||
# ANTHROPIC_PROXY_URL=https://api.anthropic.com
|
||||
|
||||
|
||||
### Google AI ####
|
||||
|
||||
# GOOGLE_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
|
||||
### AWS Bedrock ###
|
||||
|
||||
# AWS_REGION=us-east-1
|
||||
# AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxxx
|
||||
# AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
|
||||
### Ollama AI ####
|
||||
|
||||
# You can use ollama to get and run LLM locally, learn more about it via https://github.com/ollama/ollama
|
||||
|
||||
# The local/remote ollama service url
|
||||
# OLLAMA_PROXY_URL=http://127.0.0.1:11434
|
||||
|
||||
# OLLAMA_MODEL_LIST=your_ollama_model_names
|
||||
|
||||
|
||||
### OpenRouter Service ###
|
||||
|
||||
# OPENROUTER_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
# OPENROUTER_MODEL_LIST=model1,model2,model3
|
||||
|
||||
|
||||
### Mistral AI ###
|
||||
|
||||
# MISTRAL_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
### Perplexity Service ###
|
||||
|
||||
# PERPLEXITY_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
### Groq Service ####
|
||||
|
||||
# GROQ_API_KEY=gsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
#### 01.AI Service ####
|
||||
|
||||
# ZEROONE_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
### TogetherAI Service ###
|
||||
|
||||
# TOGETHERAI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
### ZhiPu AI ###
|
||||
|
||||
# ZHIPU_API_KEY=xxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxx
|
||||
|
||||
### Moonshot AI ####
|
||||
|
||||
# MOONSHOT_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
### Minimax AI ####
|
||||
|
||||
# MINIMAX_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
### DeepSeek AI ####
|
||||
|
||||
# DEEPSEEK_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
### Qwen AI ####
|
||||
|
||||
# QWEN_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
### SiliconCloud AI ####
|
||||
|
||||
# SILICONCLOUD_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
########################################
|
||||
############ Market Service ############
|
||||
########################################
|
||||
|
||||
# The LobeChat agents market index url
|
||||
# AGENTS_INDEX_URL=https://chat-agents.lobehub.com
|
||||
|
||||
########################################
|
||||
############ Plugin Service ############
|
||||
########################################
|
||||
|
||||
# The LobeChat plugins store index url
|
||||
# PLUGINS_INDEX_URL=https://chat-plugins.lobehub.com
|
||||
|
||||
# set the plugin settings
|
||||
# the format is `plugin-identifier:key1=value1;key2=value2`, multiple settings fields are separated by semicolons `;`, multiple plugin settings are separated by commas `,`.
|
||||
# PLUGIN_SETTINGS=search-engine:SERPAPI_API_KEY=xxxxx
|
||||
|
||||
|
||||
########################################
|
||||
##### S3 Object Storage Service ########
|
||||
########################################
|
||||
|
||||
# S3 keys
|
||||
#S3_ACCESS_KEY_ID=9998d6757e276cf9f1edbd325b7083a6
|
||||
#S3_SECRET_ACCESS_KEY=55af75d8eb6b99f189f6a35f855336ea62cd9c4751a5cf4337c53c1d3f497ac2
|
||||
|
||||
# Bucket name
|
||||
#S3_BUCKET=lobechat
|
||||
|
||||
# Bucket request endpoint
|
||||
#S3_ENDPOINT=https://0b33a03b5c993fd2f453379dc36558e5.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
|
||||
|
||||
|
||||
########################################
|
||||
############ Auth Service ##############
|
||||
########################################
|
||||
|
||||
|
||||
# Clerk related configurations
|
||||
|
||||
# Clerk public key and secret key
|
||||
#NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxx
|
||||
#CLERK_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
# you need to config the clerk webhook secret key if you want to use the clerk with database
|
||||
#CLERK_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
|
||||
# NextAuth related configurations
|
||||
# NEXT_AUTH_SECRET=
|
||||
|
||||
# Auth0 configurations
|
||||
# AUTH0_CLIENT_ID=
|
||||
# AUTH0_CLIENT_SECRET=
|
||||
# AUTH0_ISSUER=https://your-domain.auth0.com
|
||||
|
||||
########################################
|
||||
########## Server Database #############
|
||||
########################################
|
||||
|
||||
# Specify the service mode as server if you want to use the server database
|
||||
#NEXT_PUBLIC_SERVICE_MODE=server
|
||||
|
||||
# Postgres database URL
|
||||
#DATABASE_URL=postgres://username:password@host:port/database
|
||||
|
||||
# use `openssl rand -base64 32` to generate a key for the encryption of the database
|
||||
# we use this key to encrypt the user api key
|
||||
#KEY_VAULTS_SECRET=xxxxx/xxxxxxxxxxxxxx=
|
@ -0,0 +1,31 @@
|
||||
# Eslintignore for LobeHub
|
||||
################################################################
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
|
||||
# ci
|
||||
coverage
|
||||
.coverage
|
||||
|
||||
# test
|
||||
jest*
|
||||
*.test.ts
|
||||
*.test.tsx
|
||||
|
||||
# umi
|
||||
.umi
|
||||
.umi-production
|
||||
.umi-test
|
||||
.dumi/tmp*
|
||||
!.dumirc.ts
|
||||
|
||||
# production
|
||||
dist
|
||||
es
|
||||
lib
|
||||
logs
|
||||
|
||||
# misc
|
||||
# add other ignore file below
|
||||
.next
|
@ -0,0 +1,37 @@
|
||||
const config = require('@lobehub/lint').eslint;
|
||||
|
||||
config.extends.push('plugin:@next/next/recommended');
|
||||
|
||||
config.rules['unicorn/no-negated-condition'] = 0;
|
||||
config.rules['unicorn/prefer-type-error'] = 0;
|
||||
config.rules['unicorn/prefer-logical-operator-over-ternary'] = 0;
|
||||
config.rules['unicorn/no-null'] = 0;
|
||||
config.rules['unicorn/no-typeof-undefined'] = 0;
|
||||
config.rules['unicorn/explicit-length-check'] = 0;
|
||||
config.rules['unicorn/prefer-code-point'] = 0;
|
||||
config.rules['no-extra-boolean-cast'] = 0;
|
||||
config.rules['unicorn/no-useless-undefined'] = 0;
|
||||
config.rules['react/no-unknown-property'] = 0;
|
||||
config.rules['unicorn/prefer-ternary'] = 0;
|
||||
config.rules['unicorn/prefer-spread'] = 0;
|
||||
config.rules['unicorn/catch-error-name'] = 0;
|
||||
config.rules['unicorn/no-array-for-each'] = 0;
|
||||
config.rules['unicorn/prefer-number-properties'] = 0;
|
||||
|
||||
config.overrides = [
|
||||
{
|
||||
extends: ['plugin:mdx/recommended'],
|
||||
files: ['*.mdx'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-unused-vars': 1,
|
||||
'no-undef': 0,
|
||||
'react/jsx-no-undef': 0,
|
||||
'react/no-unescaped-entities': 0,
|
||||
},
|
||||
settings: {
|
||||
'mdx/code-blocks': false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
module.exports = config;
|
@ -0,0 +1,69 @@
|
||||
# Gitignore for LobeHub
|
||||
################################################################
|
||||
|
||||
# general
|
||||
.DS_Store
|
||||
.idea
|
||||
.vscode
|
||||
.history
|
||||
.temp
|
||||
.env.local
|
||||
venv
|
||||
temp
|
||||
tmp
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
*.log
|
||||
*.lock
|
||||
package-lock.json
|
||||
|
||||
# ci
|
||||
coverage
|
||||
.coverage
|
||||
.eslintcache
|
||||
.stylelintcache
|
||||
|
||||
# production
|
||||
dist
|
||||
es
|
||||
lib
|
||||
logs
|
||||
test-output
|
||||
|
||||
# umi
|
||||
.umi
|
||||
.umi-production
|
||||
.umi-test
|
||||
.dumi/tmp*
|
||||
|
||||
# husky
|
||||
.husky/prepare-commit-msg
|
||||
|
||||
# misc
|
||||
# add other ignore file below
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
.next
|
||||
.env
|
||||
public/*.js
|
||||
public/sitemap.xml
|
||||
public/sitemap-index.xml
|
||||
bun.lockb
|
||||
sitemap*.xml
|
||||
robots.txt
|
||||
|
||||
# Serwist
|
||||
public/sw*
|
||||
public/swe-worker*
|
||||
|
||||
*.patch
|
||||
*.pdf
|
@ -0,0 +1 @@
|
||||
|
@ -0,0 +1,46 @@
|
||||
const { defineConfig } = require('@lobehub/i18n-cli');
|
||||
|
||||
module.exports = defineConfig({
|
||||
entry: 'locales/zh-CN',
|
||||
entryLocale: 'zh-CN',
|
||||
output: 'locales',
|
||||
outputLocales: [
|
||||
'ar',
|
||||
'bg-BG',
|
||||
'zh-TW',
|
||||
'en-US',
|
||||
'ru-RU',
|
||||
'ja-JP',
|
||||
'ko-KR',
|
||||
'fr-FR',
|
||||
'tr-TR',
|
||||
'es-ES',
|
||||
'pt-BR',
|
||||
'de-DE',
|
||||
'it-IT',
|
||||
'nl-NL',
|
||||
'pl-PL',
|
||||
'vi-VN',
|
||||
],
|
||||
temperature: 0,
|
||||
modelName: 'gpt-4o-mini',
|
||||
experimental: {
|
||||
jsonMode: true,
|
||||
},
|
||||
markdown: {
|
||||
// reference: '你需要保持 mdx 的组件格式,输出文本不需要在最外层包裹任何代码块语法',
|
||||
entry: ['./README.zh-CN.md', './contributing/**/*.zh-CN.md', './docs/**/*.zh-CN.mdx'],
|
||||
entryLocale: 'zh-CN',
|
||||
outputLocales: ['en-US'],
|
||||
exclude: ['./contributing/_Sidebar.md', './contributing/_Footer.md', './contributing/Home.md'],
|
||||
outputExtensions: (locale, { filePath }) => {
|
||||
if (filePath.includes('.mdx')) {
|
||||
if (locale === 'en-US') return '.mdx';
|
||||
return `.${locale}.mdx`;
|
||||
} else {
|
||||
if (locale === 'en-US') return '.md';
|
||||
return `.${locale}.md`;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -0,0 +1,19 @@
|
||||
lockfile=false
|
||||
resolution-mode=highest
|
||||
|
||||
enable-pre-post-scripts=true
|
||||
|
||||
public-hoist-pattern[]=*@umijs/lint*
|
||||
public-hoist-pattern[]=*changelog*
|
||||
public-hoist-pattern[]=*commitlint*
|
||||
public-hoist-pattern[]=*eslint*
|
||||
public-hoist-pattern[]=*postcss*
|
||||
public-hoist-pattern[]=*prettier*
|
||||
public-hoist-pattern[]=*remark*
|
||||
public-hoist-pattern[]=*semantic-release*
|
||||
public-hoist-pattern[]=*stylelint*
|
||||
|
||||
public-hoist-pattern[]=@auth/core
|
||||
public-hoist-pattern[]=@clerk/backend
|
||||
public-hoist-pattern[]=@clerk/types
|
||||
public-hoist-pattern[]=pdfjs-dist
|
@ -0,0 +1 @@
|
||||
lts/iron
|
@ -0,0 +1,63 @@
|
||||
# Prettierignore for LobeHub
|
||||
################################################################
|
||||
|
||||
# general
|
||||
.DS_Store
|
||||
.editorconfig
|
||||
.idea
|
||||
.vscode
|
||||
.history
|
||||
.temp
|
||||
.env.local
|
||||
.husky
|
||||
.npmrc
|
||||
.gitkeep
|
||||
venv
|
||||
temp
|
||||
tmp
|
||||
LICENSE
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
*.log
|
||||
*.lock
|
||||
package-lock.json
|
||||
|
||||
# ci
|
||||
coverage
|
||||
.coverage
|
||||
.eslintcache
|
||||
.stylelintcache
|
||||
test-output
|
||||
__snapshots__
|
||||
*.snap
|
||||
|
||||
# production
|
||||
dist
|
||||
es
|
||||
lib
|
||||
logs
|
||||
|
||||
# umi
|
||||
.umi
|
||||
.umi-production
|
||||
.umi-test
|
||||
.dumi/tmp*
|
||||
|
||||
# ignore files
|
||||
.*ignore
|
||||
|
||||
# docker
|
||||
docker
|
||||
Dockerfile*
|
||||
|
||||
# image
|
||||
*.webp
|
||||
*.gif
|
||||
*.png
|
||||
*.jpg
|
||||
*.svg
|
||||
|
||||
# misc
|
||||
# add other ignore file below
|
||||
.next
|
@ -0,0 +1 @@
|
||||
module.exports = require('@lobehub/lint').prettier;
|
@ -0,0 +1 @@
|
||||
module.exports = require('@lobehub/lint').semanticRelease;
|
@ -0,0 +1 @@
|
||||
module.exports = require('@lobehub/lint').remarklint;
|
@ -0,0 +1,9 @@
|
||||
const { defineConfig } = require('@lobehub/seo-cli');
|
||||
|
||||
module.exports = defineConfig({
|
||||
entry: ['./docs/**/*.mdx'],
|
||||
modelName: 'gpt-4o-mini',
|
||||
experimental: {
|
||||
jsonMode: true,
|
||||
},
|
||||
});
|
@ -0,0 +1,9 @@
|
||||
const config = require('@lobehub/lint').stylelint;
|
||||
|
||||
module.exports = {
|
||||
...config,
|
||||
rules: {
|
||||
'selector-id-pattern': null,
|
||||
...config.rules,
|
||||
},
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,128 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to participate in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community includes:
|
||||
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
## Examples of unacceptable behavior include:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
- Other conduct that could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
<https://www.contributor-covenant.org/version/2/0/code_of_conduct.html>.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
<https://www.contributor-covenant.org/faq>. Translations are available at
|
||||
<https://www.contributor-covenant.org/translations>.
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
@ -0,0 +1,88 @@
|
||||
# Lobe Chat - Contributing Guide 🌟
|
||||
|
||||
We're thrilled that you want to contribute to Lobe Chat, the future of communication! 😄
|
||||
|
||||
Lobe Chat is an open-source project, and we welcome your collaboration. Before you jump in, let's make sure you're all set to contribute effectively and have loads of fun along the way!
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Fork the Repository](#fork-the-repository)
|
||||
- [Clone Your Fork](#clone-your-fork)
|
||||
- [Create a New Branch](#create-a-new-branch)
|
||||
- [Code Like a Wizard](#code-like-a-wizard)
|
||||
- [Committing Your Work](#committing-your-work)
|
||||
- [Sync with Upstream](#sync-with-upstream)
|
||||
- [Open a Pull Request](#open-a-pull-request)
|
||||
- [Review and Collaboration](#review-and-collaboration)
|
||||
- [Celebrate 🎉](#celebrate-)
|
||||
|
||||
## Fork the Repository
|
||||
|
||||
🍴 Fork this repository to your GitHub account by clicking the "Fork" button at the top right. This creates a personal copy of the project you can work on.
|
||||
|
||||
## Clone Your Fork
|
||||
|
||||
📦 Clone your forked repository to your local machine using the `git clone` command:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/YourUsername/lobe-chat.git
|
||||
```
|
||||
|
||||
## Create a New Branch
|
||||
|
||||
🌿 Create a new branch for your contribution. This helps keep your work organized and separate from the main codebase.
|
||||
|
||||
```bash
|
||||
git checkout -b your-branch-name
|
||||
```
|
||||
|
||||
Choose a meaningful branch name related to your work. It makes collaboration easier!
|
||||
|
||||
## Code Like a Wizard
|
||||
|
||||
🧙♀️ Time to work your magic! Write your code, fix bugs, or add new features. Be sure to follow our project's coding style. You can check if your code adheres to our style using:
|
||||
|
||||
```bash
|
||||
pnpm lint
|
||||
```
|
||||
|
||||
This adds a bit of enchantment to your coding experience! ✨
|
||||
|
||||
## Committing Your Work
|
||||
|
||||
📝 Ready to save your progress? Commit your changes to your branch.
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Your meaningful commit message"
|
||||
```
|
||||
|
||||
Please keep your commits focused and clear. And remember to be kind to your fellow contributors; keep your commits concise.
|
||||
|
||||
## Sync with Upstream
|
||||
|
||||
⚙️ Periodically, sync your forked repository with the original (upstream) repository to stay up-to-date with the latest changes.
|
||||
|
||||
```bash
|
||||
git remote add upstream https://github.com/lobehub/lobe-chat.git
|
||||
git fetch upstream
|
||||
git merge upstream/main
|
||||
```
|
||||
|
||||
This ensures you're working on the most current version of Lobe Chat. Stay fresh! 💨
|
||||
|
||||
## Open a Pull Request
|
||||
|
||||
🚀 Time to share your contribution! Head over to the original Lobe Chat repository and open a Pull Request (PR). Our maintainers will review your work.
|
||||
|
||||
## Review and Collaboration
|
||||
|
||||
👓 Your PR will undergo thorough review and testing. The maintainers will provide feedback, and you can collaborate to make your contribution even better. We value teamwork!
|
||||
|
||||
## Celebrate 🎉
|
||||
|
||||
🎈 Congratulations! Your contribution is now part of Lobe Chat. 🥳
|
||||
|
||||
Thank you for making Lobe Chat even more magical. We can't wait to see what you create! 🌠
|
||||
|
||||
Happy Coding! 🚀🦄
|
@ -0,0 +1,209 @@
|
||||
## Base image for all the stages
|
||||
FROM node:20-slim AS base
|
||||
|
||||
ARG USE_CN_MIRROR
|
||||
|
||||
ENV DEBIAN_FRONTEND="noninteractive"
|
||||
|
||||
RUN \
|
||||
# If you want to build docker in China, build with --build-arg USE_CN_MIRROR=true
|
||||
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 \
|
||||
# Add required package & update base package
|
||||
&& apt update \
|
||||
&& apt install busybox proxychains-ng -qy \
|
||||
&& apt full-upgrade -qy \
|
||||
&& apt autoremove -qy --purge \
|
||||
&& apt clean -qy \
|
||||
# Configure BusyBox
|
||||
&& busybox --install -s \
|
||||
# Add nextjs:nodejs to run the app
|
||||
&& addgroup --system --gid 1001 nodejs \
|
||||
&& adduser --system --home "/app" --gid 1001 -uid 1001 nextjs \
|
||||
# Set permission for nextjs:nodejs
|
||||
&& chown -R nextjs:nodejs "/etc/proxychains4.conf" \
|
||||
# Cleanup temp files
|
||||
&& rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/*
|
||||
|
||||
## Builder image, install all the dependencies and build the app
|
||||
FROM base AS builder
|
||||
|
||||
ARG USE_CN_MIRROR
|
||||
|
||||
ENV NEXT_PUBLIC_BASE_PATH=""
|
||||
|
||||
# Sentry
|
||||
ENV NEXT_PUBLIC_SENTRY_DSN="" \
|
||||
SENTRY_ORG="" \
|
||||
SENTRY_PROJECT=""
|
||||
|
||||
# Posthog
|
||||
ENV NEXT_PUBLIC_ANALYTICS_POSTHOG="" \
|
||||
NEXT_PUBLIC_POSTHOG_HOST="" \
|
||||
NEXT_PUBLIC_POSTHOG_KEY=""
|
||||
|
||||
# Umami
|
||||
ENV NEXT_PUBLIC_ANALYTICS_UMAMI="" \
|
||||
NEXT_PUBLIC_UMAMI_SCRIPT_URL="" \
|
||||
NEXT_PUBLIC_UMAMI_WEBSITE_ID=""
|
||||
|
||||
# Node
|
||||
ENV NODE_OPTIONS="--max-old-space-size=8192"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json ./
|
||||
COPY .npmrc ./
|
||||
|
||||
RUN \
|
||||
# If you want to build docker in China, build with --build-arg USE_CN_MIRROR=true
|
||||
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then \
|
||||
export SENTRYCLI_CDNURL="https://npmmirror.com/mirrors/sentry-cli"; \
|
||||
npm config set registry "https://registry.npmmirror.com/"; \
|
||||
fi \
|
||||
# Set the registry for corepack
|
||||
&& export COREPACK_NPM_REGISTRY=$(npm config get registry | sed 's/\/$//') \
|
||||
# Enable corepack
|
||||
&& corepack enable \
|
||||
# Use pnpm for corepack
|
||||
&& corepack use pnpm \
|
||||
# Install the dependencies
|
||||
&& pnpm i \
|
||||
# Add sharp dependencies
|
||||
&& mkdir -p /deps \
|
||||
&& pnpm add sharp --prefix /deps
|
||||
|
||||
COPY . .
|
||||
|
||||
# run build standalone for docker version
|
||||
RUN npm run build:docker
|
||||
|
||||
## Application image, copy all the files for production
|
||||
FROM scratch AS app
|
||||
|
||||
COPY --from=builder /app/public /app/public
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=builder /app/.next/standalone /app/
|
||||
COPY --from=builder /app/.next/static /app/.next/static
|
||||
COPY --from=builder /deps/node_modules/.pnpm /app/node_modules/.pnpm
|
||||
|
||||
## Production image, copy all the files and run next
|
||||
FROM base
|
||||
|
||||
# Copy all the files from app, set the correct permission for prerender cache
|
||||
COPY --from=app --chown=nextjs:nodejs /app /app
|
||||
|
||||
ENV NODE_ENV="production" \
|
||||
NODE_TLS_REJECT_UNAUTHORIZED=""
|
||||
|
||||
# set hostname to localhost
|
||||
ENV HOSTNAME="0.0.0.0" \
|
||||
PORT="3210"
|
||||
|
||||
# General Variables
|
||||
ENV ACCESS_CODE="" \
|
||||
API_KEY_SELECT_MODE="" \
|
||||
DEFAULT_AGENT_CONFIG="" \
|
||||
SYSTEM_AGENT="" \
|
||||
FEATURE_FLAGS="" \
|
||||
PROXY_URL=""
|
||||
|
||||
# Model Variables
|
||||
ENV \
|
||||
# AI21
|
||||
AI21_API_KEY="" \
|
||||
# Ai360
|
||||
AI360_API_KEY="" \
|
||||
# Anthropic
|
||||
ANTHROPIC_API_KEY="" ANTHROPIC_PROXY_URL="" \
|
||||
# Amazon Bedrock
|
||||
AWS_ACCESS_KEY_ID="" AWS_SECRET_ACCESS_KEY="" AWS_REGION="" AWS_BEDROCK_MODEL_LIST="" \
|
||||
# Azure OpenAI
|
||||
AZURE_API_KEY="" AZURE_API_VERSION="" AZURE_ENDPOINT="" AZURE_MODEL_LIST="" \
|
||||
# Baichuan
|
||||
BAICHUAN_API_KEY="" \
|
||||
# DeepSeek
|
||||
DEEPSEEK_API_KEY="" \
|
||||
# Fireworks AI
|
||||
FIREWORKSAI_API_KEY="" FIREWORKSAI_MODEL_LIST="" \
|
||||
# GitHub
|
||||
GITHUB_TOKEN="" GITHUB_MODEL_LIST="" \
|
||||
# Google
|
||||
GOOGLE_API_KEY="" GOOGLE_PROXY_URL="" \
|
||||
# Groq
|
||||
GROQ_API_KEY="" GROQ_MODEL_LIST="" GROQ_PROXY_URL="" \
|
||||
# Minimax
|
||||
MINIMAX_API_KEY="" \
|
||||
# Mistral
|
||||
MISTRAL_API_KEY="" \
|
||||
# Moonshot
|
||||
MOONSHOT_API_KEY="" MOONSHOT_PROXY_URL="" \
|
||||
# Novita
|
||||
NOVITA_API_KEY="" NOVITA_MODEL_LIST="" \
|
||||
# Ollama
|
||||
OLLAMA_MODEL_LIST="" OLLAMA_PROXY_URL="" \
|
||||
# OpenAI
|
||||
OPENAI_API_KEY="" OPENAI_MODEL_LIST="" OPENAI_PROXY_URL="" \
|
||||
# OpenRouter
|
||||
OPENROUTER_API_KEY="" OPENROUTER_MODEL_LIST="" \
|
||||
# Perplexity
|
||||
PERPLEXITY_API_KEY="" PERPLEXITY_PROXY_URL="" \
|
||||
# Qwen
|
||||
QWEN_API_KEY="" QWEN_MODEL_LIST="" \
|
||||
# SiliconCloud
|
||||
SILICONCLOUD_API_KEY="" SILICONCLOUD_MODEL_LIST="" SILICONCLOUD_PROXY_URL="" \
|
||||
# Spark
|
||||
SPARK_API_KEY="" \
|
||||
# Stepfun
|
||||
STEPFUN_API_KEY="" \
|
||||
# Taichu
|
||||
TAICHU_API_KEY="" \
|
||||
# TogetherAI
|
||||
TOGETHERAI_API_KEY="" TOGETHERAI_MODEL_LIST="" \
|
||||
# Upstage
|
||||
UPSTAGE_API_KEY="" \
|
||||
# 01.AI
|
||||
ZEROONE_API_KEY="" ZEROONE_MODEL_LIST="" \
|
||||
# Zhipu
|
||||
ZHIPU_API_KEY="" ZHIPU_MODEL_LIST=""
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3210/tcp
|
||||
|
||||
CMD \
|
||||
if [ -n "$PROXY_URL" ]; then \
|
||||
# Set regex for IPv4
|
||||
IP_REGEX="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$"; \
|
||||
# Set proxychains command
|
||||
PROXYCHAINS="proxychains -q"; \
|
||||
# Parse the proxy URL
|
||||
host_with_port="${PROXY_URL#*//}"; \
|
||||
host="${host_with_port%%:*}"; \
|
||||
port="${PROXY_URL##*:}"; \
|
||||
protocol="${PROXY_URL%%://*}"; \
|
||||
# Resolve to IP address if the host is a domain
|
||||
if ! [[ "$host" =~ "$IP_REGEX" ]]; then \
|
||||
nslookup=$(nslookup -q="A" "$host" | tail -n +3 | grep 'Address:'); \
|
||||
if [ -n "$nslookup" ]; then \
|
||||
host=$(echo "$nslookup" | tail -n 1 | awk '{print $2}'); \
|
||||
fi; \
|
||||
fi; \
|
||||
# Generate proxychains configuration file
|
||||
printf "%s\n" \
|
||||
'localnet 127.0.0.0/255.0.0.0' \
|
||||
'localnet ::1/128' \
|
||||
'proxy_dns' \
|
||||
'remote_dns_subnet 224' \
|
||||
'strict_chain' \
|
||||
'tcp_connect_time_out 8000' \
|
||||
'tcp_read_time_out 15000' \
|
||||
'[ProxyList]' \
|
||||
"$protocol $host $port" \
|
||||
> "/etc/proxychains4.conf"; \
|
||||
fi; \
|
||||
# Run the server
|
||||
${PROXYCHAINS} node "/app/server.js";
|
@ -0,0 +1,245 @@
|
||||
## Base image for all the stages
|
||||
FROM node:20-slim AS base
|
||||
|
||||
ARG USE_CN_MIRROR
|
||||
|
||||
ENV DEBIAN_FRONTEND="noninteractive"
|
||||
|
||||
RUN \
|
||||
# If you want to build docker in China, build with --build-arg USE_CN_MIRROR=true
|
||||
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 \
|
||||
# Add required package & update base package
|
||||
&& apt update \
|
||||
&& apt install busybox proxychains-ng -qy \
|
||||
&& apt full-upgrade -qy \
|
||||
&& apt autoremove -qy --purge \
|
||||
&& apt clean -qy \
|
||||
# Configure BusyBox
|
||||
&& busybox --install -s \
|
||||
# Add nextjs:nodejs to run the app
|
||||
&& addgroup --system --gid 1001 nodejs \
|
||||
&& adduser --system --home "/app" --gid 1001 -uid 1001 nextjs \
|
||||
# Set permission for nextjs:nodejs
|
||||
&& chown -R nextjs:nodejs "/etc/proxychains4.conf" \
|
||||
# Cleanup temp files
|
||||
&& rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/*
|
||||
|
||||
## Builder image, install all the dependencies and build the app
|
||||
FROM base AS builder
|
||||
|
||||
ARG USE_CN_MIRROR
|
||||
|
||||
ENV NEXT_PUBLIC_SERVICE_MODE="server" \
|
||||
APP_URL="http://app.com" \
|
||||
DATABASE_DRIVER="node" \
|
||||
DATABASE_URL="postgres://postgres:password@localhost:5432/postgres" \
|
||||
KEY_VAULTS_SECRET="use-for-build"
|
||||
|
||||
# Sentry
|
||||
ENV NEXT_PUBLIC_SENTRY_DSN="" \
|
||||
SENTRY_ORG="" \
|
||||
SENTRY_PROJECT=""
|
||||
|
||||
# Posthog
|
||||
ENV NEXT_PUBLIC_ANALYTICS_POSTHOG="" \
|
||||
NEXT_PUBLIC_POSTHOG_HOST="" \
|
||||
NEXT_PUBLIC_POSTHOG_KEY=""
|
||||
|
||||
# Umami
|
||||
ENV NEXT_PUBLIC_ANALYTICS_UMAMI="" \
|
||||
NEXT_PUBLIC_UMAMI_SCRIPT_URL="" \
|
||||
NEXT_PUBLIC_UMAMI_WEBSITE_ID=""
|
||||
|
||||
# Node
|
||||
ENV NODE_OPTIONS="--max-old-space-size=8192"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json ./
|
||||
COPY .npmrc ./
|
||||
|
||||
RUN \
|
||||
# If you want to build docker in China, build with --build-arg USE_CN_MIRROR=true
|
||||
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then \
|
||||
export SENTRYCLI_CDNURL="https://npmmirror.com/mirrors/sentry-cli"; \
|
||||
npm config set registry "https://registry.npmmirror.com/"; \
|
||||
fi \
|
||||
# Set the registry for corepack
|
||||
&& export COREPACK_NPM_REGISTRY=$(npm config get registry | sed 's/\/$//') \
|
||||
# Enable corepack
|
||||
&& corepack enable \
|
||||
# Use pnpm for corepack
|
||||
&& corepack use pnpm \
|
||||
# Install the dependencies
|
||||
&& pnpm i \
|
||||
# Add sharp and db migration dependencies
|
||||
&& mkdir -p /deps \
|
||||
&& pnpm add sharp pg drizzle-orm --prefix /deps
|
||||
|
||||
COPY . .
|
||||
|
||||
# run build standalone for docker version
|
||||
RUN npm run build:docker
|
||||
|
||||
## Application image, copy all the files for production
|
||||
FROM scratch AS app
|
||||
|
||||
COPY --from=builder /app/public /app/public
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=builder /app/.next/standalone /app/
|
||||
COPY --from=builder /app/.next/static /app/.next/static
|
||||
|
||||
# copy dependencies
|
||||
COPY --from=builder /deps/node_modules/.pnpm /app/node_modules/.pnpm
|
||||
COPY --from=builder /deps/node_modules/pg /app/node_modules/pg
|
||||
COPY --from=builder /deps/node_modules/drizzle-orm /app/node_modules/drizzle-orm
|
||||
|
||||
# Copy database migrations
|
||||
COPY --from=builder /app/src/database/server/migrations /app/migrations
|
||||
COPY --from=builder /app/scripts/migrateServerDB/docker.cjs /app/docker.cjs
|
||||
COPY --from=builder /app/scripts/migrateServerDB/errorHint.js /app/errorHint.js
|
||||
|
||||
## Production image, copy all the files and run next
|
||||
FROM base
|
||||
|
||||
# Copy all the files from app, set the correct permission for prerender cache
|
||||
COPY --from=app --chown=nextjs:nodejs /app /app
|
||||
|
||||
ENV NODE_ENV="production" \
|
||||
NODE_TLS_REJECT_UNAUTHORIZED=""
|
||||
|
||||
# set hostname to localhost
|
||||
ENV HOSTNAME="0.0.0.0" \
|
||||
PORT="3210"
|
||||
|
||||
# General Variables
|
||||
ENV ACCESS_CODE="" \
|
||||
APP_URL="" \
|
||||
API_KEY_SELECT_MODE="" \
|
||||
DEFAULT_AGENT_CONFIG="" \
|
||||
SYSTEM_AGENT="" \
|
||||
FEATURE_FLAGS="" \
|
||||
PROXY_URL=""
|
||||
|
||||
# Database
|
||||
ENV KEY_VAULTS_SECRET="" \
|
||||
DATABASE_DRIVER="node" \
|
||||
DATABASE_URL=""
|
||||
|
||||
# Next Auth
|
||||
ENV NEXT_AUTH_SECRET="" \
|
||||
NEXT_AUTH_SSO_PROVIDERS="" \
|
||||
NEXTAUTH_URL=""
|
||||
|
||||
# S3
|
||||
ENV NEXT_PUBLIC_S3_DOMAIN="" \
|
||||
S3_PUBLIC_DOMAIN="" \
|
||||
S3_ACCESS_KEY_ID="" \
|
||||
S3_BUCKET="" \
|
||||
S3_ENDPOINT="" \
|
||||
S3_SECRET_ACCESS_KEY=""
|
||||
|
||||
# Model Variables
|
||||
ENV \
|
||||
# AI21
|
||||
AI21_API_KEY="" \
|
||||
# Ai360
|
||||
AI360_API_KEY="" \
|
||||
# Anthropic
|
||||
ANTHROPIC_API_KEY="" ANTHROPIC_PROXY_URL="" \
|
||||
# Amazon Bedrock
|
||||
AWS_ACCESS_KEY_ID="" AWS_SECRET_ACCESS_KEY="" AWS_REGION="" AWS_BEDROCK_MODEL_LIST="" \
|
||||
# Azure OpenAI
|
||||
AZURE_API_KEY="" AZURE_API_VERSION="" AZURE_ENDPOINT="" AZURE_MODEL_LIST="" \
|
||||
# Baichuan
|
||||
BAICHUAN_API_KEY="" \
|
||||
# DeepSeek
|
||||
DEEPSEEK_API_KEY="" \
|
||||
# Fireworks AI
|
||||
FIREWORKSAI_API_KEY="" FIREWORKSAI_MODEL_LIST="" \
|
||||
# GitHub
|
||||
GITHUB_TOKEN="" GITHUB_MODEL_LIST="" \
|
||||
# Google
|
||||
GOOGLE_API_KEY="" GOOGLE_PROXY_URL="" \
|
||||
# Groq
|
||||
GROQ_API_KEY="" GROQ_MODEL_LIST="" GROQ_PROXY_URL="" \
|
||||
# Minimax
|
||||
MINIMAX_API_KEY="" \
|
||||
# Mistral
|
||||
MISTRAL_API_KEY="" \
|
||||
# Moonshot
|
||||
MOONSHOT_API_KEY="" MOONSHOT_PROXY_URL="" \
|
||||
# Novita
|
||||
NOVITA_API_KEY="" NOVITA_MODEL_LIST="" \
|
||||
# Ollama
|
||||
OLLAMA_MODEL_LIST="" OLLAMA_PROXY_URL="" \
|
||||
# OpenAI
|
||||
OPENAI_API_KEY="" OPENAI_MODEL_LIST="" OPENAI_PROXY_URL="" \
|
||||
# OpenRouter
|
||||
OPENROUTER_API_KEY="" OPENROUTER_MODEL_LIST="" \
|
||||
# Perplexity
|
||||
PERPLEXITY_API_KEY="" PERPLEXITY_PROXY_URL="" \
|
||||
# Qwen
|
||||
QWEN_API_KEY="" QWEN_MODEL_LIST="" \
|
||||
# SiliconCloud
|
||||
SILICONCLOUD_API_KEY="" SILICONCLOUD_MODEL_LIST="" SILICONCLOUD_PROXY_URL="" \
|
||||
# Spark
|
||||
SPARK_API_KEY="" \
|
||||
# Stepfun
|
||||
STEPFUN_API_KEY="" \
|
||||
# Taichu
|
||||
TAICHU_API_KEY="" \
|
||||
# TogetherAI
|
||||
TOGETHERAI_API_KEY="" TOGETHERAI_MODEL_LIST="" \
|
||||
# Upstage
|
||||
UPSTAGE_API_KEY="" \
|
||||
# 01.AI
|
||||
ZEROONE_API_KEY="" ZEROONE_MODEL_LIST="" \
|
||||
# Zhipu
|
||||
ZHIPU_API_KEY=""
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3210/tcp
|
||||
|
||||
CMD \
|
||||
if [ -n "$PROXY_URL" ]; then \
|
||||
# Set regex for IPv4
|
||||
IP_REGEX="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$"; \
|
||||
# Set proxychains command
|
||||
PROXYCHAINS="proxychains -q"; \
|
||||
# Parse the proxy URL
|
||||
host_with_port="${PROXY_URL#*//}"; \
|
||||
host="${host_with_port%%:*}"; \
|
||||
port="${PROXY_URL##*:}"; \
|
||||
protocol="${PROXY_URL%%://*}"; \
|
||||
# Resolve to IP address if the host is a domain
|
||||
if ! [[ "$host" =~ "$IP_REGEX" ]]; then \
|
||||
nslookup=$(nslookup -q="A" "$host" | tail -n +3 | grep 'Address:'); \
|
||||
if [ -n "$nslookup" ]; then \
|
||||
host=$(echo "$nslookup" | tail -n 1 | awk '{print $2}'); \
|
||||
fi; \
|
||||
fi; \
|
||||
# Generate proxychains configuration file
|
||||
printf "%s\n" \
|
||||
'localnet 127.0.0.0/255.0.0.0' \
|
||||
'localnet ::1/128' \
|
||||
'proxy_dns' \
|
||||
'remote_dns_subnet 224' \
|
||||
'strict_chain' \
|
||||
'tcp_connect_time_out 8000' \
|
||||
'tcp_read_time_out 15000' \
|
||||
'[ProxyList]' \
|
||||
"$protocol $host $port" \
|
||||
> "/etc/proxychains4.conf"; \
|
||||
fi; \
|
||||
# Run migration
|
||||
node "/app/docker.cjs"; \
|
||||
if [ "$?" -eq "0" ]; then \
|
||||
# Run the server
|
||||
${PROXYCHAINS} node "/app/server.js"; \
|
||||
fi;
|
@ -0,0 +1,38 @@
|
||||
Apache License Version 2.0
|
||||
|
||||
Copyright (c) 2024/06/17 - current LobeHub LLC. All rights reserved.
|
||||
|
||||
----------
|
||||
|
||||
From 1.0, LobeChat is licensed under the Apache License 2.0, with the following additional conditions:
|
||||
|
||||
1. The commercial usage of LobeChat:
|
||||
|
||||
a. LobeChat may be utilized commercially, including as a frontend and backend service without modifying the source code.
|
||||
|
||||
b. a commercial license must be obtained from the producer if you want to develop and distribute a derivative work based on LobeChat.
|
||||
|
||||
Please contact hello@lobehub.com by email to inquire about licensing matters.
|
||||
|
||||
|
||||
2. As a contributor, you should agree that:
|
||||
|
||||
a. The producer can adjust the open-source agreement to be more strict or relaxed as deemed necessary.
|
||||
|
||||
b. Your contributed code may be used for commercial purposes, including but not limited to its cloud edition.
|
||||
|
||||
Apart from the specific conditions mentioned above, all other rights and restrictions follow the Apache License 2.0. Detailed information about the Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
----------
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -0,0 +1,25 @@
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { beforeEach } from 'vitest';
|
||||
import { createWithEqualityFn as actualCreate } from 'zustand/traditional';
|
||||
|
||||
// a variable to hold reset functions for all stores declared in the app
|
||||
const storeResetFns = new Set<() => void>();
|
||||
|
||||
// when creating a store, we get its initial state, create a reset function and add it in the set
|
||||
const createImpl = (createState: any) => {
|
||||
const store = actualCreate(createState, Object.is);
|
||||
const initialState = store.getState();
|
||||
storeResetFns.add(() => store.setState(initialState, true));
|
||||
return store;
|
||||
};
|
||||
|
||||
// Reset all stores after each test run
|
||||
beforeEach(() => {
|
||||
act(() => {
|
||||
for (const resetFn of storeResetFns) {
|
||||
resetFn();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export const createWithEqualityFn = (f: any) => (f === undefined ? createImpl : createImpl(f));
|
@ -0,0 +1,11 @@
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default: off
|
||||
server:
|
||||
flags:
|
||||
- server
|
||||
app:
|
||||
flags:
|
||||
- app
|
||||
patch: off
|
@ -0,0 +1,193 @@
|
||||
# New Authentication Provider Guide
|
||||
|
||||
LobeChat uses [Auth.js v5](https://authjs.dev/) as the external authentication service. Auth.js is an open-source authentication library that provides a simple way to implement authentication and authorization features. This document will introduce how to use Auth.js to implement a new authentication provider.
|
||||
|
||||
### TOC
|
||||
|
||||
- [Add New Authentication Provider](#add-new-authentication-provider)
|
||||
- [Pre-requisites: Check the Official Provider List](#pre-requisites-check-the-official-provider-list)
|
||||
- [Step 1: Add Authenticator Core Code](#step-1-add-authenticator-core-code)
|
||||
- [Step 2: Update Server Configuration Code](#step-2-update-server-configuration-code)
|
||||
- [Step 3: Change Frontend Pages](#step-3-change-frontend-pages)
|
||||
- [Step 4: Configure the Environment Variables](#step-4-configure-the-environment-variables)
|
||||
- [Step 5: Modify server-side user information processing logic](#step-5-modify-server-side-user-information-processing-logic)
|
||||
|
||||
## Add New Authentication Provider
|
||||
|
||||
To add a new authentication provider in LobeChat (for example, adding Okta), you need to follow the steps below:
|
||||
|
||||
### Pre-requisites: Check the Official Provider List
|
||||
|
||||
First, you need to check the [Auth.js Provider List](https://authjs.dev/reference/core/providers) to see if your provider is already supported. If yes, you can directly use the SDK provided by Auth.js to implement the authentication feature.
|
||||
|
||||
Next, I will use [Okta](https://authjs.dev/reference/core/providers/okta) as an example to introduce how to add a new authentication provider.
|
||||
|
||||
### Step 1: Add Authenticator Core Code
|
||||
|
||||
Open the `src/app/api/auth/next-auth.ts` file and import `next-auth/providers/okta`.
|
||||
|
||||
```ts
|
||||
import { NextAuth } from 'next-auth';
|
||||
import Auth0 from 'next-auth/providers/auth0';
|
||||
import Okta from 'next-auth/providers/okta';
|
||||
|
||||
// Import Okta provider
|
||||
```
|
||||
|
||||
Add the predefined server configuration.
|
||||
|
||||
```ts
|
||||
// Import server configuration
|
||||
const { OKTA_CLIENT_ID, OKTA_CLIENT_SECRET, OKTA_ISSUER } = getServerConfig();
|
||||
|
||||
const nextAuth = NextAuth({
|
||||
providers: [
|
||||
// ... Other providers
|
||||
|
||||
Okta({
|
||||
clientId: OKTA_CLIENT_ID,
|
||||
clientSecret: OKTA_CLIENT_SECRET,
|
||||
issuer: OKTA_ISSUER,
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
### Step 2: Update Server Configuration Code
|
||||
|
||||
Open the `src/config/server/app.ts` file and add Okta-related environment variables in the `getAppConfig` function.
|
||||
|
||||
```ts
|
||||
export const getAppConfig = () => {
|
||||
// ... Other code
|
||||
|
||||
return {
|
||||
// ... Other environment variables
|
||||
|
||||
OKTA_CLIENT_ID: process.env.OKTA_CLIENT_ID || '',
|
||||
OKTA_CLIENT_SECRET: process.env.OKTA_CLIENT_SECRET || '',
|
||||
OKTA_ISSUER: process.env.OKTA_ISSUER || '',
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Step 3: Change Frontend Pages
|
||||
|
||||
Modify the `signIn` function parameter in `src/Features/Conversation/Error/OAuthForm.tsx` and \`src/app/settings/common/Common.tsx
|
||||
|
||||
The default is `auth0`, which you can change to `okta` to switch to the Okta provider, or remove this parameter to support all added authentication services
|
||||
|
||||
This value is the id of the Auth.js provider, and you can read the source code of the corresponding `next-auth/providers` module to read the default ID.
|
||||
|
||||
### Step 4: Configure the Environment Variables
|
||||
|
||||
Add `OKTA_CLIENT_ID`、`OKTA_CLIENT_SECRET`、`OKTA_ISSUER` environment variables when you deploy.
|
||||
|
||||
### Step 5: Modify server-side user information processing logic
|
||||
|
||||
#### Get user information in the frontend
|
||||
|
||||
Use the `useOAuthSession()` method in the frontend page to get the user information `user` returned by the backend:
|
||||
|
||||
```ts
|
||||
import { useOAuthSession } from '@/hooks/useOAuthSession';
|
||||
|
||||
const { user, isOAuthLoggedIn } = useOAuthSession();
|
||||
```
|
||||
|
||||
The default type of `user` is `User`, and the type definition is:
|
||||
|
||||
```ts
|
||||
interface User {
|
||||
id?: string;
|
||||
name?: string | null;
|
||||
email?: string | null;
|
||||
image?: string | null;
|
||||
}
|
||||
```
|
||||
|
||||
#### Modify user `id` handling logic
|
||||
|
||||
The `user.id` is used to identify users. When introducing a new OAuth identity provider, you need to handle the information carried in the OAuth callback in `src/app/api/auth/next-auth.ts`. You need to select the user's `id` from this information. Before that, we need to understand the data processing sequence of `Auth.js`:
|
||||
|
||||
```txt
|
||||
authorize --> jwt --> session
|
||||
```
|
||||
|
||||
By default, in the `jwt --> session` process, `Auth.js` will [automatically assign the user `id` to `account.providerAccountId` based on the login type](https://authjs.dev/reference/core/types#provideraccountid). If you need to select a different value as the user `id`, you need to implement the following handling logic:
|
||||
|
||||
```ts
|
||||
callbacks: {
|
||||
async jwt({ token, account, profile }) {
|
||||
if (account) {
|
||||
// You can select a different value from `account` or `profile`
|
||||
token.userId = account.providerAccountId;
|
||||
}
|
||||
return token;
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
#### Customize `session` return
|
||||
|
||||
If you want to carry more information about `profile` and `account` in the `session`, according to the data processing order mentioned above in `Auth.js`, you must first copy this information to the `token`. For example, add the user avatar URL `profile.picture` to the `session`:
|
||||
|
||||
```diff
|
||||
callbacks: {
|
||||
async jwt({ token, profile, account }) {
|
||||
if (profile && account) {
|
||||
token.userId = account.providerAccountId;
|
||||
+ token.avatar = profile.picture;
|
||||
}
|
||||
return token;
|
||||
},
|
||||
async session({ session, token }) {
|
||||
if (session.user) {
|
||||
session.user.id = token.userId ?? session.user.id;
|
||||
+ session.user.avatar = token.avatar;
|
||||
}
|
||||
return session;
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
Then supplement the type definition for the new parameters:
|
||||
|
||||
```ts
|
||||
declare module '@auth/core/jwt' {
|
||||
interface JWT {
|
||||
// ...
|
||||
avatar?: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'next-auth' {
|
||||
interface User {
|
||||
avatar?: string;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> [More built-in type extensions in Auth.js](https://authjs.dev/getting-started/typescript#module-augmentation)
|
||||
|
||||
#### Differentiate multiple authentication providers in the processing logic
|
||||
|
||||
If you have configured multiple authentication providers and their `userId` mappings are different, you can use the `account.provider` parameter in the `jwt` method to get the default id of the identity provider and enter different processing logic.
|
||||
|
||||
```ts
|
||||
callbacks: {
|
||||
async jwt({ token, profile, account }) {
|
||||
if (profile && account) {
|
||||
if (account.provider === 'authing')
|
||||
token.userId = account.providerAccountId ?? token.sub;
|
||||
else if (acount.provider === 'auth0')
|
||||
token.userId = profile.sub ?? token.sub;
|
||||
else
|
||||
// other providers
|
||||
}
|
||||
return token;
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Now, you can use Okta as your provider to implement the authentication feature in LobeChat.
|
@ -0,0 +1,47 @@
|
||||
# Architecture Design
|
||||
|
||||
LobeChat is an AI conversation application built on the Next.js framework, aiming to provide an AI productivity platform that enables users to interact with AI through natural language. The following is an overview of the architecture design of LobeChat:
|
||||
|
||||
#### TOC
|
||||
|
||||
- [Application Architecture Overview](#application-architecture-overview)
|
||||
- [Frontend Architecture](#frontend-architecture)
|
||||
- [Edge Runtime API](#edge-runtime-api)
|
||||
- [Agents Market](#agents-market)
|
||||
- [Plugin Market](#plugin-market)
|
||||
- [Security and Performance Optimization](#security-and-performance-optimization)
|
||||
- [Development and Deployment Process](#development-and-deployment-process)
|
||||
|
||||
## Application Architecture Overview
|
||||
|
||||
The overall architecture of LobeChat consists of the frontend, EdgeRuntime API, Agents Market, Plugin Market, and independent plugins. These components collaborate to provide a complete AI experience.
|
||||
|
||||
## Frontend Architecture
|
||||
|
||||
The frontend of LobeChat adopts the Next.js framework, leveraging its powerful server-side rendering (SSR) capability and routing functionality. The frontend utilizes a stack of technologies, including the antd component library, lobe-ui AIGC component library, zustand state management, swr request library, i18next internationalization library, and more. These technologies collectively support the functionality and features of LobeChat.
|
||||
|
||||
The components in the frontend architecture include app, components, config, const, features, helpers, hooks, layout, locales, migrations, prompts, services, store, styles, types, and utils. Each component has specific responsibilities and collaborates with others to achieve different functionalities.
|
||||
|
||||
## Edge Runtime API
|
||||
|
||||
The Edge Runtime API is one of the core components of LobeChat, responsible for handling the core logic of AI conversations. It provides interaction interfaces with the AI engine, including natural language processing, intent recognition, and response generation. The EdgeRuntime API communicates with the frontend, receiving user input and returning corresponding responses.
|
||||
|
||||
## Agents Market
|
||||
|
||||
The Agents Market is a crucial part of LobeChat, providing various AI agents for different scenarios to handle specific tasks and domains. The Agents Market also offers functionality for discovering and uploading agents, allowing users to find agents created by others and easily share their own agents in the market.
|
||||
|
||||
## Plugin Market
|
||||
|
||||
The Plugin Market is another key component of LobeChat, offering various plugins to extend the functionality and features of LobeChat. Plugins can be independent functional modules or integrated with agents from the Agents Market. During conversations, the assistant automatically identifies user input, recognizes suitable plugins, and passes them to the corresponding plugins for processing and returns the results.
|
||||
|
||||
## Security and Performance Optimization
|
||||
|
||||
LobeChat's security strategy includes authentication and permission management. Users need to authenticate before using LobeChat, and operations are restricted based on the user's permissions.
|
||||
|
||||
To optimize performance, LobeChat utilizes Next.js SSR functionality to achieve fast page loading and response times. Additionally, a series of performance optimization measures are implemented, including code splitting, caching, and resource compression.
|
||||
|
||||
## Development and Deployment Process
|
||||
|
||||
LobeChat's development process includes version control, testing, continuous integration, and continuous deployment. The development team uses version control systems for code management and conducts unit and integration testing to ensure code quality. Continuous integration and deployment processes ensure rapid delivery and deployment of code.
|
||||
|
||||
The above is a brief introduction to the architecture design of LobeChat, detailing the responsibilities and collaboration of each component, as well as the impact of design decisions on application functionality and performance.
|
@ -0,0 +1,136 @@
|
||||
# Conversation API Implementation Logic
|
||||
|
||||
The implementation of LobeChat's large model AI mainly relies on OpenAI's API, including the core conversation API on the backend and the integrated API on the frontend. Next, we will introduce the implementation approach and code for the backend and frontend separately.
|
||||
|
||||
#### TOC
|
||||
|
||||
- [Backend Implementation](#backend-implementation)
|
||||
- [Core Conversation API](#core-conversation-api)
|
||||
- [Conversation Result Processing](#conversation-result-processing)
|
||||
- [Frontend Implementation](#frontend-implementation)
|
||||
- [Frontend Integration](#frontend-integration)
|
||||
- [Using Streaming to Get Results](#using-streaming-to-get-results)
|
||||
|
||||
## Backend Implementation
|
||||
|
||||
The following code removes authentication, error handling, and other logic, retaining only the core functionality logic.
|
||||
|
||||
### Core Conversation API
|
||||
|
||||
In the file `src/app/api/openai/chat/handler.ts`, we define a `POST` method, which first parses the payload data from the request (i.e., the conversation content sent by the client), and then retrieves the authorization information from the request. Then, we create an `openai` object and call the `createChatCompletion` method, which is responsible for sending the conversation request to OpenAI and returning the result.
|
||||
|
||||
```ts
|
||||
export const POST = async (req: Request) => {
|
||||
const payload = await req.json();
|
||||
|
||||
const { apiKey, endpoint } = getOpenAIAuthFromRequest(req);
|
||||
|
||||
const openai = createOpenai(apiKey, endpoint);
|
||||
|
||||
return createChatCompletion({ openai, payload });
|
||||
};
|
||||
```
|
||||
|
||||
### Conversation Result Processing
|
||||
|
||||
In the file `src/app/api/openai/chat/createChatCompletion.ts`, we define the `createChatCompletion` method, which first preprocesses the payload data, then calls OpenAI's `chat.completions.create` method to send the request, and uses the `OpenAIStream` from the [Vercel AI SDK](https://sdk.vercel.ai/docs) to convert the returned result into a streaming response.
|
||||
|
||||
```ts
|
||||
import { OpenAIStream, StreamingTextResponse } from 'ai';
|
||||
|
||||
export const createChatCompletion = async ({ payload, openai }: CreateChatCompletionOptions) => {
|
||||
const { messages, ...params } = payload;
|
||||
|
||||
const formatMessages = messages.map((m) => ({
|
||||
content: m.content,
|
||||
name: m.name,
|
||||
role: m.role,
|
||||
}));
|
||||
|
||||
const response = await openai.chat.completions.create(
|
||||
{
|
||||
messages: formatMessages,
|
||||
...params,
|
||||
stream: true,
|
||||
},
|
||||
{ headers: { Accept: '*/*' } },
|
||||
);
|
||||
const stream = OpenAIStream(response);
|
||||
return new StreamingTextResponse(stream);
|
||||
};
|
||||
```
|
||||
|
||||
## Frontend Implementation
|
||||
|
||||
### Frontend Integration
|
||||
|
||||
In the `src/services/chatModel.ts` file, we define the `fetchChatModel` method, which first preprocesses the payload data, then sends a POST request to the `/chat` endpoint on the backend, and returns the request result.
|
||||
|
||||
```ts
|
||||
export const fetchChatModel = (
|
||||
{ plugins: enabledPlugins, ...params }: Partial<OpenAIStreamPayload>,
|
||||
options?: FetchChatModelOptions,
|
||||
) => {
|
||||
const payload = merge(
|
||||
{
|
||||
model: initialLobeAgentConfig.model,
|
||||
stream: true,
|
||||
...initialLobeAgentConfig.params,
|
||||
},
|
||||
params,
|
||||
);
|
||||
|
||||
const filterFunctions: ChatCompletionFunctions[] = pluginSelectors.enabledSchema(enabledPlugins)(
|
||||
usePluginStore.getState(),
|
||||
);
|
||||
|
||||
const functions = filterFunctions.length === 0 ? undefined : filterFunctions;
|
||||
|
||||
return fetch(OPENAI_URLS.chat, {
|
||||
body: JSON.stringify({ ...payload, functions }),
|
||||
headers: createHeaderWithOpenAI({ 'Content-Type': 'application/json' }),
|
||||
method: 'POST',
|
||||
signal: options?.signal,
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
### Using Streaming to Get Results
|
||||
|
||||
In the `src/utils/fetch.ts` file, we define the `fetchSSE` method, which uses a streaming approach to retrieve data. When a new data chunk is read, it calls the `onMessageHandle` callback function to process the data chunk, achieving a typewriter-like output effect.
|
||||
|
||||
```ts
|
||||
export const fetchSSE = async (fetchFn: () => Promise<Response>, options: FetchSSEOptions = {}) => {
|
||||
const response = await fetchFn();
|
||||
|
||||
if (!response.ok) {
|
||||
const chatMessageError = await getMessageError(response);
|
||||
|
||||
options.onErrorHandle?.(chatMessageError);
|
||||
return;
|
||||
}
|
||||
|
||||
const returnRes = response.clone();
|
||||
|
||||
const data = response.body;
|
||||
|
||||
if (!data) return;
|
||||
|
||||
const reader = data.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
let done = false;
|
||||
|
||||
while (!done) {
|
||||
const { value, done: doneReading } = await reader.read();
|
||||
done = doneReading;
|
||||
const chunkValue = decoder.decode(value);
|
||||
|
||||
options.onMessageHandle?.(chunkValue);
|
||||
}
|
||||
|
||||
return returnRes;
|
||||
};
|
||||
```
|
||||
|
||||
The above is the core implementation of the LobeChat session API. With an understanding of these core codes, further expansion and optimization of LobeChat's AI functionality can be achieved.
|
@ -0,0 +1,83 @@
|
||||
# Code Style and Contribution Guidelines
|
||||
|
||||
Welcome to the Code Style and Contribution Guidelines for LobeChat. This guide will help you understand our code standards and contribution process, ensuring code consistency and smooth project progression.
|
||||
|
||||
## TOC
|
||||
|
||||
- [Code Style](#code-style)
|
||||
- [ESLint](#eslint)
|
||||
- [Prettier](#prettier)
|
||||
- [remarklint](#remarklint)
|
||||
- [stylelint](#stylelint)
|
||||
- [Contribution Process](#contribution-process)
|
||||
- [Gitmoji](#gitmoji)
|
||||
- [Semantic Release](#semantic-release)
|
||||
- [Commitlint](#commitlint)
|
||||
- [How to Contribute](#how-to-contribute)
|
||||
|
||||
## Code Style
|
||||
|
||||
In LobeChat, we use the `@lobehub/lint` package to maintain a unified code style. This package incorporates configurations for `ESLint`, `Prettier`, `remarklint`, and `stylelint` to ensure that our JavaScript, Markdown, and CSS files adhere to the same coding standards.
|
||||
|
||||
### ESLint
|
||||
|
||||
We use ESLint to check for issues in our JavaScript code. You can find the `.eslintrc.js` file in the project's root directory, which contains our extensions and custom rules for the ESLint configuration of `@lobehub/lint`.
|
||||
|
||||
To ensure your code aligns with the project's standards, run ESLint before committing your code.
|
||||
|
||||
### Prettier
|
||||
|
||||
Prettier is responsible for code formatting to maintain consistency. Our Prettier configuration can be found in `.prettierrc.js`, imported from `@lobehub/lint`.
|
||||
|
||||
It's recommended to configure your editor to run Prettier automatically upon saving files or manually run it before committing.
|
||||
|
||||
### remarklint
|
||||
|
||||
For Markdown files, we use remarklint to ensure consistent document formatting. You can find the corresponding configuration file in the project.
|
||||
|
||||
### stylelint
|
||||
|
||||
We utilize stylelint to standardize the style of our CSS code. In the configuration file for stylelint, we have made some custom rule adjustments based on `@lobehub/lint` configuration.
|
||||
|
||||
Ensure that your style code passes stylelint checks before committing.
|
||||
|
||||
## Contribution Process
|
||||
|
||||
LobeChat follows the gitmoji and semantic release as our code submission and release process.
|
||||
|
||||
### Gitmoji
|
||||
|
||||
When committing code, please use gitmoji to label your commit messages. This helps other contributors quickly understand the content and purpose of your submission.
|
||||
|
||||
Gitmoji commit messages use specific emojis to represent the type or intent of the commit. Here's an example:
|
||||
|
||||
```
|
||||
📝 Update README with contribution guidelines
|
||||
|
||||
- Added section about code style preferences
|
||||
- Included instructions for running tests
|
||||
- Corrected typos and improved formatting
|
||||
```
|
||||
|
||||
In this example, the 📝 emoji represents a documentation update. The commit message clearly describes the changes and provides specific details.
|
||||
|
||||
### Semantic Release
|
||||
|
||||
We use semantic release to automate version control and release processes. Ensure that your commit messages adhere to the semantic release specifications so that when the code is merged into the main branch, the system can automatically create a new version and release it.
|
||||
|
||||
### Commitlint
|
||||
|
||||
To ensure consistency in commit messages, we use `commitlint` to check the format of commit messages. You can find the relevant rules in the `.commitlintrc.js` configuration file.
|
||||
|
||||
Before committing your code, ensure that your commit messages adhere to our standards.
|
||||
|
||||
### How to Contribute
|
||||
|
||||
1. Fork the project to your account.
|
||||
2. Create a new branch for development.
|
||||
3. After completing the development, ensure that your code passes the aforementioned code style checks.
|
||||
4. Commit your changes and use appropriate gitmoji to label your commit message.
|
||||
5. Create a Pull Request to the main branch of the original project.
|
||||
6. Await code review and make necessary modifications based on feedback.
|
||||
|
||||
Thank you for following these guidelines, as they help us maintain the quality and consistency of the project. We look forward to your contributions!
|
@ -0,0 +1,126 @@
|
||||
# How to Develop a New Feature
|
||||
|
||||
LobeChat is built on the Next.js framework and uses TypeScript as the primary development language. When developing a new feature, we need to follow a certain development process to ensure the quality and stability of the code. The general process can be divided into the following five steps:
|
||||
|
||||
1. Routing: Define routes (`src/app`).
|
||||
2. Data Structure: Define data structures (`src/types`).
|
||||
3. Business Logic Implementation: Zustand store (`src/store`).
|
||||
4. Page Display: Write static components/pages (`src/app/<new-page>/features/<new-feature>.tsx`).
|
||||
5. Function Binding: Bind the store with page triggers (`const [state, function] = useNewStore(s => [s.state, s.function])`).
|
||||
|
||||
Taking the "Chat Messages" feature as an example, here are the brief steps to implement this feature:
|
||||
|
||||
#### TOC
|
||||
|
||||
- [1. Define Routes](#1-define-routes)
|
||||
- [2. Define Data Structure](#2-define-data-structure)
|
||||
- [3. Create Zustand Store](#3-create-zustand-store)
|
||||
- [4. Create Page and Components](#4-create-page-and-components)
|
||||
- [5. Function Binding](#5-function-binding)
|
||||
|
||||
## 1. Define Routes
|
||||
|
||||
In the `src/app` directory, we need to define a new route to host the "Chat Messages" page. Generally, we would create a new folder under `src/app`, for example, `chat`, and create a `page.tsx` file within this folder to export a React component as the main body of the page.
|
||||
|
||||
```tsx
|
||||
// src/app/chat/page.tsx
|
||||
import ChatPage from './features/chat';
|
||||
|
||||
export default ChatPage;
|
||||
```
|
||||
|
||||
## 2. Define Data Structure
|
||||
|
||||
In the `src/types` directory, we need to define the data structure for "Chat Messages". For example, we create a `chat.ts` file and define the `ChatMessage` type within it:
|
||||
|
||||
```ts
|
||||
// src/types/chat.ts
|
||||
|
||||
export type ChatMessage = {
|
||||
id: string;
|
||||
content: string;
|
||||
timestamp: number;
|
||||
sender: 'user' | 'bot';
|
||||
};
|
||||
```
|
||||
|
||||
## 3. Create Zustand Store
|
||||
|
||||
In the `src/store` directory, we need to create a new Zustand Store to manage the state of "Chat Messages". For example, we create a `chatStore.ts` file and define a Zustand Store within it:
|
||||
|
||||
```ts
|
||||
// src/store/chatStore.ts
|
||||
import create from 'zustand';
|
||||
|
||||
type ChatState = {
|
||||
messages: ChatMessage[];
|
||||
addMessage: (message: ChatMessage) => void;
|
||||
};
|
||||
|
||||
export const useChatStore = create<ChatState>((set) => ({
|
||||
messages: [],
|
||||
addMessage: (message) => set((state) => ({ messages: [...state.messages, message] })),
|
||||
}));
|
||||
```
|
||||
|
||||
## 4. Create Page and Components
|
||||
|
||||
In `src/app/<new-page>/features/<new-feature>.tsx`, we need to create a new page or component to display "Chat Messages". In this file, we can use the Zustand Store created earlier and Ant Design components to build the UI:
|
||||
|
||||
```jsx
|
||||
// src/features/chat/index.tsx
|
||||
import { List, Typography } from 'antd';
|
||||
import { useChatStore } from 'src/store/chatStore';
|
||||
|
||||
const ChatPage = () => {
|
||||
const messages = useChatStore((state) => state.messages);
|
||||
|
||||
return (
|
||||
<List
|
||||
dataSource={messages}
|
||||
renderItem={(message) => (
|
||||
<List.Item>
|
||||
<Typography.Text>{message.content}</Typography.Text>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatPage;
|
||||
```
|
||||
|
||||
## 5. Function Binding
|
||||
|
||||
In a page or component, we need to bind the Zustand Store's state and methods to the UI. In the example above, we have already bound the `messages` state to the `dataSource` property of the list. Now, we also need a method to add new messages. We can define this method in the Zustand Store and then use it in the page or component:
|
||||
|
||||
```jsx
|
||||
import { Button } from 'antd';
|
||||
|
||||
const ChatPage = () => {
|
||||
const messages = useChatStore((state) => state.messages);
|
||||
const addMessage = useChatStore((state) => state.addMessage);
|
||||
|
||||
const handleSend = () => {
|
||||
addMessage({ id: '1', content: 'Hello, world!', timestamp: Date.now(), sender: 'user' });
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<List
|
||||
dataSource={messages}
|
||||
renderItem={(message) => (
|
||||
<List.Item>
|
||||
<Typography.Text>{message.content}</Typography.Text>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
<Button onClick={handleSend}>Send</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatPage;
|
||||
```
|
||||
|
||||
The above is the step to implement the "chat message" feature in LobeChat. Of course, in the actual development of LobeChat, the business requirements and scenarios faced in real situations are far more complex than the above demo. Please develop according to the actual situation.
|
@ -0,0 +1,713 @@
|
||||
# Complete Guide to LobeChat Feature Development
|
||||
|
||||
This document aims to guide developers on how to develop a complete feature requirement in LobeChat.
|
||||
|
||||
We will use the implementation of sessionGroup as an example: [✨ feat: add session group manager](https://github.com/lobehub/lobe-chat/pull/1055), and explain the complete implementation process through the following six main sections:
|
||||
|
||||
1. [Data Model / Database Definition](#1-data-model--database-definition)
|
||||
2. [Service Implementation / Model Implementation](#2-service-implementation--model-implementation)
|
||||
3. [Frontend Data Flow Store Implementation](#3-frontend-data-flow-store-implementation)
|
||||
4. [UI Implementation and Action Binding](#4-ui-implementation-and-action-binding)
|
||||
5. [Data Migration](#5-data-migration)
|
||||
6. [Data Import and Export](#6-data-import-and-export)
|
||||
|
||||
## 1. Data Model / Database Definition
|
||||
|
||||
To implement the Session Group feature, it is necessary to define the relevant data model and indexes at the database level.
|
||||
|
||||
Define a new sessionGroup table in 3 steps:
|
||||
|
||||
### 1. Establish Data Model Schema
|
||||
|
||||
Define the data model of `DB_SessionGroup` in `src/database/schema/sessionGroup.ts`:
|
||||
|
||||
```typescript
|
||||
import { z } from 'zod';
|
||||
|
||||
export const DB_SessionGroupSchema = z.object({
|
||||
name: z.string(),
|
||||
sort: z.number().optional(),
|
||||
});
|
||||
|
||||
export type DB_SessionGroup = z.infer<typeof DB_SessionGroupSchema>;
|
||||
```
|
||||
|
||||
### 2. Create Database Indexes
|
||||
|
||||
Since a new table needs to be added, an index needs to be added to the database schema for the `sessionGroup` table.
|
||||
|
||||
Add `dbSchemaV4` in `src/database/core/schema.ts`:
|
||||
|
||||
```diff
|
||||
// ... previous implementations
|
||||
|
||||
// ************************************** //
|
||||
// ******* Version 3 - 2023-12-06 ******* //
|
||||
// ************************************** //
|
||||
// - Added `plugin` table
|
||||
|
||||
export const dbSchemaV3 = {
|
||||
...dbSchemaV2,
|
||||
plugins:
|
||||
'&identifier, type, manifest.type, manifest.meta.title, manifest.meta.description, manifest.meta.author, createdAt, updatedAt',
|
||||
};
|
||||
|
||||
+ // ************************************** //
|
||||
+ // ******* Version 4 - 2024-01-21 ******* //
|
||||
+ // ************************************** //
|
||||
+ // - Added `sessionGroup` table
|
||||
|
||||
+ export const dbSchemaV4 = {
|
||||
+ ...dbSchemaV3,
|
||||
+ sessionGroups: '&id, name, sort, createdAt, updatedAt',
|
||||
+ sessions: '&id, type, group, pinned, meta.title, meta.description, meta.tags, createdAt, updatedAt',
|
||||
};
|
||||
```
|
||||
|
||||
> \[!Note]
|
||||
>
|
||||
> In addition to `sessionGroups`, the definition of `sessions` has also been modified here due to data migration. However, as this section only focuses on schema definition and does not delve into the implementation of data migration, please refer to section five for details.
|
||||
|
||||
> \[!Important]
|
||||
>
|
||||
> If you are unfamiliar with the need to create indexes here and the syntax of schema definition, you may need to familiarize yourself with the basics of Dexie.js. You can refer to the [📘 Local Database](./Local-Database.zh-CN) section for relevant information.
|
||||
|
||||
### 3. Add the sessionGroups Table to the Local DB
|
||||
|
||||
Extend the local database class to include the new `sessionGroups` table:
|
||||
|
||||
```diff
|
||||
|
||||
import { dbSchemaV1, dbSchemaV2, dbSchemaV3, dbSchemaV4 } from './schemas';
|
||||
|
||||
interface LobeDBSchemaMap {
|
||||
files: DB_File;
|
||||
messages: DB_Message;
|
||||
plugins: DB_Plugin;
|
||||
+ sessionGroups: DB_SessionGroup;
|
||||
sessions: DB_Session;
|
||||
topics: DB_Topic;
|
||||
}
|
||||
|
||||
// Define a local DB
|
||||
export class LocalDB extends Dexie {
|
||||
public files: LobeDBTable<'files'>;
|
||||
public sessions: LobeDBTable<'sessions'>;
|
||||
public messages: LobeDBTable<'messages'>;
|
||||
public topics: LobeDBTable<'topics'>;
|
||||
public plugins: LobeDBTable<'plugins'>;
|
||||
+ public sessionGroups: LobeDBTable<'sessionGroups'>;
|
||||
|
||||
constructor() {
|
||||
super(LOBE_CHAT_LOCAL_DB_NAME);
|
||||
this.version(1).stores(dbSchemaV1);
|
||||
this.version(2).stores(dbSchemaV2);
|
||||
this.version(3).stores(dbSchemaV3);
|
||||
+ this.version(4).stores(dbSchemaV4);
|
||||
|
||||
this.files = this.table('files');
|
||||
this.sessions = this.table('sessions');
|
||||
this.messages = this.table('messages');
|
||||
this.topics = this.table('topics');
|
||||
this.plugins = this.table('plugins');
|
||||
+ this.sessionGroups = this.table('sessionGroups');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As a result, you can now view the `sessionGroups` table in the `LOBE_CHAT_DB` in `Application` -> `Storage` -> `IndexedDB`.
|
||||
|
||||

|
||||
|
||||
## 2. Service Implementation / Model Implementation
|
||||
|
||||
### Define Model
|
||||
|
||||
When building the LobeChat application, the Model is responsible for interacting with the database. It defines how to read, insert, update, and delete data from the database, as well as defining specific business logic.
|
||||
|
||||
In `src/database/model/sessionGroup.ts`, the `SessionGroupModel` is defined as follows:
|
||||
|
||||
```typescript
|
||||
import { BaseModel } from '@/database/client/core';
|
||||
import { DB_SessionGroup, DB_SessionGroupSchema } from '@/database/client/schemas/sessionGroup';
|
||||
import { nanoid } from '@/utils/uuid';
|
||||
|
||||
class _SessionGroupModel extends BaseModel {
|
||||
constructor() {
|
||||
super('sessions', DB_SessionGroupSchema);
|
||||
}
|
||||
|
||||
async create(name: string, sort?: number, id = nanoid()) {
|
||||
return this._add({ name, sort }, id);
|
||||
}
|
||||
|
||||
// ... Implementation of other CRUD methods
|
||||
}
|
||||
|
||||
export const SessionGroupModel = new _SessionGroupModel();
|
||||
```
|
||||
|
||||
### Service Implementation
|
||||
|
||||
In LobeChat, the Service layer is mainly responsible for communicating with the backend service, encapsulating business logic, and providing data to other layers in the frontend. `SessionService` is a service class specifically handling business logic related to sessions. It encapsulates operations such as creating sessions, querying sessions, and updating sessions.
|
||||
|
||||
To maintain code maintainability and extensibility, we place the logic related to session grouping in the `SessionService`. This helps to keep the business logic of the session domain cohesive. When business requirements increase or change, it becomes easier to modify and extend within this domain.
|
||||
|
||||
`SessionService` implements session group-related request logic by calling methods from `SessionGroupModel`. The following is the implementation of Session Group-related request logic in `sessionService`:
|
||||
|
||||
```typescript
|
||||
class SessionService {
|
||||
// ... Omitted session business logic
|
||||
|
||||
// ************************************** //
|
||||
// *********** SessionGroup *********** //
|
||||
// ************************************** //
|
||||
|
||||
async createSessionGroup(name: string, sort?: number) {
|
||||
const item = await SessionGroupModel.create(name, sort);
|
||||
if (!item) {
|
||||
throw new Error('session group create Error');
|
||||
}
|
||||
|
||||
return item.id;
|
||||
}
|
||||
|
||||
// ... Other SessionGroup related implementations
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Frontend Data Flow Store Implementation
|
||||
|
||||
In the LobeChat application, the Store module is used to manage the frontend state of the application. The Actions within it are functions that trigger state updates, usually by calling methods in the service layer to perform actual data processing operations and then updating the state in the Store. We use `zustand` as the underlying dependency for the Store module. For a detailed practical introduction to state management, you can refer to [📘 Best Practices for State Management](../State-Management/State-Management-Intro.zh-CN.md).
|
||||
|
||||
### sessionGroup CRUD
|
||||
|
||||
CRUD operations for session groups are the core behaviors for managing session group data. In `src/store/session/slice/sessionGroup`, we will implement the state logic related to session groups, including adding, deleting, updating session groups, and their sorting.
|
||||
|
||||
The following are the methods of the `SessionGroupAction` interface that need to be implemented in the `action.ts` file:
|
||||
|
||||
```ts
|
||||
export interface SessionGroupAction {
|
||||
// Add session group
|
||||
addSessionGroup: (name: string) => Promise<string>;
|
||||
// Remove session group
|
||||
removeSessionGroup: (id: string) => Promise<void>;
|
||||
// Update session group ID for a session
|
||||
updateSessionGroupId: (sessionId: string, groupId: string) => Promise<void>;
|
||||
// Update session group name
|
||||
updateSessionGroupName: (id: string, name: string) => Promise<void>;
|
||||
// Update session group sorting
|
||||
updateSessionGroupSort: (items: SessionGroupItem[]) => Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
Taking the `addSessionGroup` method as an example, we first call the `createSessionGroup` method of `sessionService` to create a new session group, and then use the `refreshSessions` method to refresh the sessions state:
|
||||
|
||||
```ts
|
||||
export const createSessionGroupSlice: StateCreator<
|
||||
SessionStore,
|
||||
[['zustand/devtools', never]],
|
||||
[],
|
||||
SessionGroupAction
|
||||
> = (set, get) => ({
|
||||
// Implement the logic for adding a session group
|
||||
addSessionGroup: async (name) => {
|
||||
// Call the createSessionGroup method in the service layer and pass in the session group name
|
||||
const id = await sessionService.createSessionGroup(name);
|
||||
// Call the get method to get the current Store state and execute the refreshSessions method to refresh the session data
|
||||
await get().refreshSessions();
|
||||
// Return the ID of the newly created session group
|
||||
return id;
|
||||
},
|
||||
// ... Other action implementations
|
||||
});
|
||||
```
|
||||
|
||||
With the above implementation, we can ensure that after adding a new session group, the application's state will be updated in a timely manner, and the relevant components will receive the latest state and re-render. This approach improves the predictability and maintainability of the data flow, while also simplifying communication between components.
|
||||
|
||||
### Sessions Group Logic Refactoring
|
||||
|
||||
This requirement involves upgrading the Sessions feature to transform it from a single list to three different groups: `pinnedSessions` (pinned list), `customSessionGroups` (custom groups), and `defaultSessions` (default list).
|
||||
|
||||
To handle these groups, we need to refactor the implementation logic of `useFetchSessions`. Here are the key changes:
|
||||
|
||||
1. Use the `sessionService.getGroupedSessions` method to call the backend API and retrieve the grouped session data.
|
||||
2. Save the retrieved data into three different state fields: `pinnedSessions`, `customSessionGroups`, and `defaultSessions`.
|
||||
|
||||
#### `useFetchSessions` Method
|
||||
|
||||
This method is defined in `createSessionSlice` as follows:
|
||||
|
||||
```typescript
|
||||
export const createSessionSlice: StateCreator<
|
||||
SessionStore,
|
||||
[['zustand/devtools', never]],
|
||||
[],
|
||||
SessionAction
|
||||
> = (set, get) => ({
|
||||
// ... other methods
|
||||
useFetchSessions: () =>
|
||||
useSWR<ChatSessionList>(FETCH_SESSIONS_KEY, sessionService.getGroupedSessions, {
|
||||
onSuccess: (data) => {
|
||||
set(
|
||||
{
|
||||
customSessionGroups: data.customGroup,
|
||||
defaultSessions: data.default,
|
||||
isSessionsFirstFetchFinished: true,
|
||||
pinnedSessions: data.pinned,
|
||||
sessions: data.all,
|
||||
},
|
||||
false,
|
||||
n('useFetchSessions/onSuccess', data),
|
||||
);
|
||||
},
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
After successfully retrieving the data, we use the `set` method to update the `customSessionGroups`, `defaultSessions`, `pinnedSessions`, and `sessions` states. This ensures that the states are synchronized with the latest session data.
|
||||
|
||||
#### `sessionService.getGroupedSessions` Method
|
||||
|
||||
The `sessionService.getGroupedSessions` method is responsible for calling the backend API `SessionModel.queryWithGroups()`.
|
||||
|
||||
```typescript
|
||||
class SessionService {
|
||||
// ... other SessionGroup related implementations
|
||||
|
||||
async getGroupedSessions(): Promise<ChatSessionList> {
|
||||
return SessionModel.queryWithGroups();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `SessionModel.queryWithGroups` Method
|
||||
|
||||
This method is the core method called by `sessionService.getGroupedSessions`, and it is responsible for querying and organizing session data. The code is as follows:
|
||||
|
||||
```typescript
|
||||
class _SessionModel extends BaseModel {
|
||||
// ... other methods
|
||||
|
||||
/**
|
||||
* Query session data and categorize sessions based on groups.
|
||||
* @returns {Promise<ChatSessionList>} An object containing all sessions and categorized session lists.
|
||||
*/
|
||||
async queryWithGroups(): Promise<ChatSessionList> {
|
||||
// Query session group data
|
||||
const groups = await SessionGroupModel.query();
|
||||
// Query custom session groups based on session group IDs
|
||||
const customGroups = await this.queryByGroupIds(groups.map((item) => item.id));
|
||||
// Query default session list
|
||||
const defaultItems = await this.querySessionsByGroupId(SessionDefaultGroup.Default);
|
||||
// Query pinned sessions
|
||||
const pinnedItems = await this.getPinnedSessions();
|
||||
|
||||
// Query all sessions
|
||||
const all = await this.query();
|
||||
// Combine and return all sessions and their group information
|
||||
return {
|
||||
all, // Array containing all sessions
|
||||
customGroup: groups.map((group) => ({ ...group, children: customGroups[group.id] })), // Custom groups
|
||||
default: defaultItems, // Default session list
|
||||
pinned: pinnedItems, // Pinned session list
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `queryWithGroups` method first queries all session groups, then based on the IDs of these groups, it queries custom session groups, as well as default and pinned sessions. Finally, it returns an object containing all sessions and categorized session lists.
|
||||
|
||||
### Adjusting sessions selectors
|
||||
|
||||
Due to changes in the logic of grouping within sessions, we need to adjust the logic of the `sessions` selectors to ensure they can correctly handle the new data structure.
|
||||
|
||||
Original selectors:
|
||||
|
||||
```ts
|
||||
// Default group
|
||||
const defaultSessions = (s: SessionStore): LobeSessions => s.sessions;
|
||||
|
||||
// Pinned group
|
||||
const pinnedSessionList = (s: SessionStore) =>
|
||||
defaultSessions(s).filter((s) => s.group === SessionGroupDefaultKeys.Pinned);
|
||||
|
||||
// Unpinned group
|
||||
const unpinnedSessionList = (s: SessionStore) =>
|
||||
defaultSessions(s).filter((s) => s.group === SessionGroupDefaultKeys.Default);
|
||||
```
|
||||
|
||||
Revised:
|
||||
|
||||
```ts
|
||||
const defaultSessions = (s: SessionStore): LobeSessions => s.defaultSessions;
|
||||
const pinnedSessions = (s: SessionStore): LobeSessions => s.pinnedSessions;
|
||||
const customSessionGroups = (s: SessionStore): CustomSessionGroup[] => s.customSessionGroups;
|
||||
```
|
||||
|
||||
Since all data retrieval in the UI is implemented using syntax like `useSessionStore(sessionSelectors.defaultSessions)`, we only need to modify the selector implementation of `defaultSessions` to complete the data structure change. The data retrieval code in the UI layer does not need to be changed at all, which can greatly reduce the cost and risk of refactoring.
|
||||
|
||||
> !\[Important]
|
||||
>
|
||||
> If you are not familiar with the concept and functionality of selectors, you can refer to the section [📘 Data Storage and Retrieval Module](./State-Management-Selectors.en-US) for relevant information.
|
||||
|
||||
## 4. UI Implementation and Action Binding
|
||||
|
||||
Bind Store Action in the UI component to implement interactive logic, for example `CreateGroupModal`:
|
||||
|
||||
```tsx
|
||||
const CreateGroupModal = () => {
|
||||
// ... Other logic
|
||||
|
||||
const [updateSessionGroup, addCustomGroup] = useSessionStore((s) => [
|
||||
s.updateSessionGroupId,
|
||||
s.addSessionGroup,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
onOk={async () => {
|
||||
// ... Other logic
|
||||
const groupId = await addCustomGroup(name);
|
||||
await updateSessionGroup(sessionId, groupId);
|
||||
}}
|
||||
>
|
||||
{/* ... */}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## 5. Data Migration
|
||||
|
||||
In the process of software development, data migration is an inevitable issue, especially when the existing data structure cannot meet the new business requirements. For this iteration of SessionGroup, we need to handle the migration of the `group` field in the `session`, which is a typical data migration case.
|
||||
|
||||
### Issues with the Old Data Structure
|
||||
|
||||
In the old data structure, the `group` field was used to mark whether the session was "pinned" or belonged to a "default" group. However, when support for multiple session groups is needed, the original data structure becomes inflexible.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
before pin: group = abc
|
||||
after pin: group = pinned
|
||||
after unpin: group = default
|
||||
```
|
||||
|
||||
From the above example, it can be seen that once a session is unpinned from the "pinned" state, the `group` field cannot be restored to its original `abc` value. This is because we do not have a separate field to maintain the pinned state. Therefore, we have introduced a new field `pinned` to indicate whether the session is pinned, while the `group` field will be used solely to identify the session group.
|
||||
|
||||
### Migration Strategy
|
||||
|
||||
The core logic of this migration is as follows:
|
||||
|
||||
- When the user's `group` field is `pinned`, set their `pinned` field to `true`, and set the group to `default`.
|
||||
|
||||
However, data migration in LobeChat typically involves two parts: **configuration file migration** and **database migration**. Therefore, the above logic will need to be implemented separately in these two areas.
|
||||
|
||||
#### Configuration File Migration
|
||||
|
||||
For configuration file migration, we recommend performing it before database migration, as configuration file migration is usually easier to test and validate. LobeChat's file migration configuration is located in the `src/migrations/index.ts` file, which defines the various versions of configuration file migration and their corresponding migration scripts.
|
||||
|
||||
```diff
|
||||
// Current latest version number
|
||||
- export const CURRENT_CONFIG_VERSION = 2;
|
||||
+ export const CURRENT_CONFIG_VERSION = 3;
|
||||
|
||||
// Historical version upgrade module
|
||||
const ConfigMigrations = [
|
||||
+ /**
|
||||
+ * 2024.01.22
|
||||
+ * from `group = pinned` to `pinned:true`
|
||||
+ */
|
||||
+ MigrationV2ToV3,
|
||||
/**
|
||||
* 2023.11.27
|
||||
* Migrate from single key database to dexie-based relational structure
|
||||
*/
|
||||
MigrationV1ToV2,
|
||||
/**
|
||||
* 2023.07.11
|
||||
* just the first version, Nothing to do
|
||||
*/
|
||||
MigrationV0ToV1,
|
||||
];
|
||||
```
|
||||
|
||||
The logic for this configuration file migration is defined in `src/migrations/FromV2ToV3/index.ts`, simplified as follows:
|
||||
|
||||
```ts
|
||||
export class MigrationV2ToV3 implements Migration {
|
||||
// Specify the version from which to upgrade
|
||||
version = 2;
|
||||
|
||||
migrate(data: MigrationData<V2ConfigState>): MigrationData<V3ConfigState> {
|
||||
const { sessions } = data.state;
|
||||
|
||||
return {
|
||||
...data,
|
||||
state: {
|
||||
...data.state,
|
||||
sessions: sessions.map((s) => this.migrateSession(s)),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
migrateSession = (session: V2Session): V3Session => {
|
||||
return {
|
||||
...session,
|
||||
group: 'default',
|
||||
pinned: session.group === 'pinned',
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
It can be seen that the migration implementation is very simple. However, it is important to ensure the correctness of the migration, so corresponding test cases need to be written in `src/migrations/FromV2ToV3/migrations.test.ts`:
|
||||
|
||||
```ts
|
||||
import { MigrationData, VersionController } from '@/migrations/VersionController';
|
||||
|
||||
import { MigrationV1ToV2 } from '../FromV1ToV2';
|
||||
import inputV1Data from '../FromV1ToV2/fixtures/input-v1-session.json';
|
||||
import inputV2Data from './fixtures/input-v2-session.json';
|
||||
import outputV3DataFromV1 from './fixtures/output-v3-from-v1.json';
|
||||
import outputV3Data from './fixtures/output-v3.json';
|
||||
import { MigrationV2ToV3 } from './index';
|
||||
|
||||
describe('MigrationV2ToV3', () => {
|
||||
let migrations;
|
||||
let versionController: VersionController<any>;
|
||||
|
||||
beforeEach(() => {
|
||||
migrations = [MigrationV2ToV3];
|
||||
versionController = new VersionController(migrations, 3);
|
||||
});
|
||||
|
||||
it('should migrate data correctly through multiple versions', () => {
|
||||
const data: MigrationData = inputV2Data;
|
||||
|
||||
const migratedData = versionController.migrate(data);
|
||||
|
||||
expect(migratedData.version).toEqual(outputV3Data.version);
|
||||
expect(migratedData.state.sessions).toEqual(outputV3Data.state.sessions);
|
||||
expect(migratedData.state.topics).toEqual(outputV3Data.state.topics);
|
||||
expect(migratedData.state.messages).toEqual(outputV3Data.state.messages);
|
||||
});
|
||||
|
||||
it('should work correct from v1 to v3', () => {
|
||||
const data: MigrationData = inputV1Data;
|
||||
|
||||
versionController = new VersionController([MigrationV2ToV3, MigrationV1ToV2], 3);
|
||||
|
||||
const migratedData = versionController.migrate(data);
|
||||
|
||||
expect(migratedData.version).toEqual(outputV3DataFromV1.version);
|
||||
expect(migratedData.state.sessions).toEqual(outputV3DataFromV1.state.sessions);
|
||||
expect(migratedData.state.topics).toEqual(outputV3DataFromV1.state.topics);
|
||||
expect(migratedData.state.messages).toEqual(outputV3DataFromV1.state.messages);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
```markdown
|
||||
|
||||
```
|
||||
|
||||
Unit tests require the use of `fixtures` to fix the test data. The test cases include verification logic for two parts: 1) the correctness of a single migration (v2 -> v3) and 2) the correctness of a complete migration (v1 -> v3).
|
||||
|
||||
> \[!Important]
|
||||
>
|
||||
> The version number in the configuration file may not match the database version number, as database version updates do not always involve changes to the data structure (such as adding tables or fields), while configuration file version updates usually involve data migration.
|
||||
|
||||
````
|
||||
|
||||
#### Database Migration
|
||||
|
||||
Database migration needs to be implemented in the `LocalDB` class, which is defined in the `src/database/core/db.ts` file. The migration process involves adding a new `pinned` field for each record in the `sessions` table and resetting the `group` field:
|
||||
|
||||
```diff
|
||||
export class LocalDB extends Dexie {
|
||||
public files: LobeDBTable<'files'>;
|
||||
public sessions: LobeDBTable<'sessions'>;
|
||||
public messages: LobeDBTable<'messages'>;
|
||||
public topics: LobeDBTable<'topics'>;
|
||||
public plugins: LobeDBTable<'plugins'>;
|
||||
public sessionGroups: LobeDBTable<'sessionGroups'>;
|
||||
|
||||
constructor() {
|
||||
super(LOBE_CHAT_LOCAL_DB_NAME);
|
||||
this.version(1).stores(dbSchemaV1);
|
||||
this.version(2).stores(dbSchemaV2);
|
||||
this.version(3).stores(dbSchemaV3);
|
||||
this.version(4)
|
||||
.stores(dbSchemaV4)
|
||||
+ .upgrade((trans) => this.upgradeToV4(trans));
|
||||
|
||||
this.files = this.table('files');
|
||||
this.sessions = this.table('sessions');
|
||||
this.messages = this.table('messages');
|
||||
this.topics = this.table('topics');
|
||||
this.plugins = this.table('plugins');
|
||||
this.sessionGroups = this.table('sessionGroups');
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * 2024.01.22
|
||||
+ *
|
||||
+ * DB V3 to V4
|
||||
+ * from `group = pinned` to `pinned:true`
|
||||
+ */
|
||||
+ upgradeToV4 = async (trans: Transaction) => {
|
||||
+ const sessions = trans.table('sessions');
|
||||
+ await sessions.toCollection().modify((session) => {
|
||||
+ // translate boolean to number
|
||||
+ session.pinned = session.group === 'pinned' ? 1 : 0;
|
||||
session.group = 'default';
|
||||
});
|
||||
+ };
|
||||
}
|
||||
````
|
||||
|
||||
This is our data migration strategy. When performing the migration, it is essential to ensure the correctness of the migration script and validate the migration results through thorough testing.
|
||||
|
||||
## 6. Data Import and Export
|
||||
|
||||
In LobeChat, the data import and export feature is designed to ensure that users can migrate their data between different devices. This includes session, topic, message, and settings data. In the implementation of the Session Group feature, we also need to handle data import and export to ensure that the complete exported data can be restored exactly the same on other devices.
|
||||
|
||||
The core implementation of data import and export is in the `ConfigService` in `src/service/config.ts`, with key methods as follows:
|
||||
|
||||
| Method Name | Description |
|
||||
| --------------------- | -------------------------- |
|
||||
| `importConfigState` | Import configuration data |
|
||||
| `exportAgents` | Export all agent data |
|
||||
| `exportSessions` | Export all session data |
|
||||
| `exportSingleSession` | Export single session data |
|
||||
| `exportSingleAgent` | Export single agent data |
|
||||
| `exportSettings` | Export settings data |
|
||||
| `exportAll` | Export all data |
|
||||
|
||||
### Data Export
|
||||
|
||||
In LobeChat, when a user chooses to export data, the current session, topic, message, and settings data are packaged into a JSON file and provided for download. The standard structure of this JSON file is as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"exportType": "sessions",
|
||||
"state": {
|
||||
"sessions": [],
|
||||
"topics": [],
|
||||
"messages": []
|
||||
},
|
||||
"version": 3
|
||||
}
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- `exportType`: Identifies the type of data being exported, currently including `sessions`, `agent`, `settings`, and `all`.
|
||||
- `state`: Stores the actual data, with different data types for different `exportType`.
|
||||
- `version`: Indicates the data version.
|
||||
|
||||
In the implementation of the Session Group feature, we need to add `sessionGroups` data to the `state` field. This way, when users export data, their Session Group data will also be included.
|
||||
|
||||
For example, when exporting sessions, the relevant implementation code modification is as follows:
|
||||
|
||||
```diff
|
||||
class ConfigService {
|
||||
// ... Other code omitted
|
||||
|
||||
exportSessions = async () => {
|
||||
const sessions = await sessionService.getAllSessions();
|
||||
+ const sessionGroups = await sessionService.getSessionGroups();
|
||||
const messages = await messageService.getAllMessages();
|
||||
const topics = await topicService.getAllTopics();
|
||||
|
||||
- const config = createConfigFile('sessions', { messages, sessions, topics });
|
||||
+ const config = createConfigFile('sessions', { messages, sessionGroups, sessions, topics });
|
||||
|
||||
exportConfigFile(config, 'sessions');
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Data Import
|
||||
|
||||
The data import functionality is implemented through `ConfigService.importConfigState`. When users choose to import data, they need to provide a JSON file that conforms to the above structure specification. The `importConfigState` method accepts the data of the configuration file and imports it into the application.
|
||||
|
||||
In the implementation of the Session Group feature, we need to handle the `sessionGroups` data during the data import process. This way, when users import data, their Session Group data will also be imported correctly.
|
||||
|
||||
The following is the modified code for the import implementation in `importConfigState`:
|
||||
|
||||
```diff
|
||||
class ConfigService {
|
||||
// ... Other code omitted
|
||||
|
||||
+ importSessionGroups = async (sessionGroups: SessionGroupItem[]) => {
|
||||
+ return sessionService.batchCreateSessionGroups(sessionGroups);
|
||||
+ };
|
||||
|
||||
importConfigState = async (config: ConfigFile): Promise<ImportResults | undefined> => {
|
||||
switch (config.exportType) {
|
||||
case 'settings': {
|
||||
await this.importSettings(config.state.settings);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'agents': {
|
||||
+ const sessionGroups = await this.importSessionGroups(config.state.sessionGroups);
|
||||
|
||||
const data = await this.importSessions(config.state.sessions);
|
||||
return {
|
||||
+ sessionGroups: this.mapImportResult(sessionGroups),
|
||||
sessions: this.mapImportResult(data),
|
||||
};
|
||||
}
|
||||
|
||||
case 'all': {
|
||||
await this.importSettings(config.state.settings);
|
||||
|
||||
+ const sessionGroups = await this.importSessionGroups(config.state.sessionGroups);
|
||||
|
||||
const [sessions, messages, topics] = await Promise.all([
|
||||
this.importSessions(config.state.sessions),
|
||||
this.importMessages(config.state.messages),
|
||||
this.importTopics(config.state.topics),
|
||||
]);
|
||||
|
||||
return {
|
||||
messages: this.mapImportResult(messages),
|
||||
+ sessionGroups: this.mapImportResult(sessionGroups),
|
||||
sessions: this.mapImportResult(sessions),
|
||||
topics: this.mapImportResult(topics),
|
||||
};
|
||||
}
|
||||
|
||||
case 'sessions': {
|
||||
+ const sessionGroups = await this.importSessionGroups(config.state.sessionGroups);
|
||||
|
||||
const [sessions, messages, topics] = await Promise.all([
|
||||
this.importSessions(config.state.sessions),
|
||||
this.importMessages(config.state.messages),
|
||||
this.importTopics(config.state.topics),
|
||||
]);
|
||||
|
||||
return {
|
||||
messages: this.mapImportResult(messages),
|
||||
+ sessionGroups: this.mapImportResult(sessionGroups),
|
||||
sessions: this.mapImportResult(sessions),
|
||||
topics: this.mapImportResult(topics),
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
One key point of the above modification is to import sessionGroup first, because if sessions are imported first and the corresponding SessionGroup Id is not found in the current database, the group of this session will default to be modified to the default value. This will prevent the correct association of the sessionGroup's ID with the session.
|
||||
|
||||
This is the implementation of the LobeChat Session Group feature in the data import and export process. This approach ensures that users' Session Group data is correctly handled during the import and export process.
|
||||
|
||||
## Summary
|
||||
|
||||
The above is the complete implementation process of the LobeChat Session Group feature. Developers can refer to this document for the development and testing of related functionalities.
|
@ -0,0 +1,40 @@
|
||||
# Directory Structure
|
||||
|
||||
The directory structure of LobeChat is as follows:
|
||||
|
||||
```bash
|
||||
src
|
||||
├── app # Main logic and state management related code for the application
|
||||
├── components # Reusable UI components
|
||||
├── config # Application configuration files, including client-side and server-side environment variables
|
||||
├── const # Used to define constants, such as action types, route names, etc.
|
||||
├── 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.
|
||||
├── locales # Internationalization language files
|
||||
├── services # Encapsulated backend service interfaces, such as HTTP requests
|
||||
├── store # Zustand store for state management
|
||||
├── types # TypeScript type definition files
|
||||
└── utils # Common utility functions
|
||||
```
|
||||
|
||||
## app
|
||||
|
||||
In the `app` folder, we organize each route page according to the app router's [Route Groups](https://nextjs.org/docs/app/building-your-application/routing/route-groups) to separately handle the implementation of desktop and mobile code. Taking the file structure of the `welcome` page as an example:
|
||||
|
||||
```bash
|
||||
welcome
|
||||
├── (desktop) # Desktop implementation
|
||||
│ ├── features # Desktop-specific features
|
||||
│ ├── index.tsx # Main entry file for desktop
|
||||
│ └── layout.desktop.tsx # Desktop layout component
|
||||
├── (mobile) # Mobile implementation
|
||||
│ ├── features # Mobile-specific features
|
||||
│ ├── index.tsx # Main entry file for mobile
|
||||
│ └── layout.mobile.tsx # Mobile layout component
|
||||
├── features # This folder contains features code shared by both desktop and mobile, such as the Banner component
|
||||
│ └── Banner
|
||||
└── page.tsx # This is the main entry file for the page, used to load desktop or mobile code based on the device type
|
||||
```
|
||||
|
||||
In this way, we can clearly distinguish and manage desktop and mobile code, while also easily reusing code required on both devices, thereby improving development efficiency and maintaining code cleanliness and maintainability.
|
@ -0,0 +1,40 @@
|
||||
# 目录架构
|
||||
|
||||
LobeChat 的文件夹目录架构如下:
|
||||
|
||||
```bash
|
||||
src
|
||||
├── app # 应用主要逻辑和状态管理相关的代码
|
||||
├── components # 可复用的 UI 组件
|
||||
├── config # 应用的配置文件,包含客户端环境变量与服务端环境变量
|
||||
├── const # 用于定义常量,如 action 类型、路由名等
|
||||
├── features # 与业务功能相关的功能模块,如 Agent 设置、插件开发弹窗等
|
||||
├── hooks # 全应用复用自定义的工具 Hooks
|
||||
├── layout # 应用的布局组件,如导航栏、侧边栏等
|
||||
├── locales # 国际化的语言文件
|
||||
├── services # 封装的后端服务接口,如 HTTP 请求
|
||||
├── store # 用于状态管理的 zustand store
|
||||
├── types # TypeScript 的类型定义文件
|
||||
└── utils # 通用的工具函数
|
||||
```
|
||||
|
||||
## app
|
||||
|
||||
在 `app` 文件夹中,我们将每个路由页面按照 app router 的 [Route Groups](https://nextjs.org/docs/app/building-your-application/routing/route-groups) 进行组织,以此来分别处理桌面端和移动端的代码实现。以 `welcome` 页面的文件结构为例:
|
||||
|
||||
```bash
|
||||
welcome
|
||||
├── (desktop) # 桌面端实现
|
||||
│ ├── features # 桌面端特有的功能
|
||||
│ ├── index.tsx # 桌面端的主入口文件
|
||||
│ └── layout.desktop.tsx # 桌面端的布局组件
|
||||
├── (mobile) # 移动端实现
|
||||
│ ├── features # 移动端特有的功能
|
||||
│ ├── index.tsx # 移动端的主入口文件
|
||||
│ └── layout.mobile.tsx # 移动端的布局组件
|
||||
├── features # 此文件夹包含双端共享的特性代码,如 Banner 组件
|
||||
│ └── Banner
|
||||
└── page.tsx # 此为页面的主入口文件,用于根据设备类型选择加载桌面端或移动端的代码
|
||||
```
|
||||
|
||||
通过这种方式,我们可以清晰地区分和管理桌面端和移动端的代码,同时也能方便地复用在两种设备上都需要的代码,从而提高开发效率并保持代码的整洁和可维护性。
|
@ -0,0 +1,111 @@
|
||||
# Technical Development Getting Started Guide
|
||||
|
||||
Welcome to the LobeChat Technical Development Getting Started Guide. LobeChat is an AI conversation application built on the Next.js framework, incorporating a range of technology stacks to achieve diverse functionalities and features. This guide will detail the main technical components of LobeChat and how to configure and use these technologies in your development environment.
|
||||
|
||||
#### TOC
|
||||
|
||||
- [Basic Technology Stack](#basic-technology-stack)
|
||||
- [Folder Directory Structure](#folder-directory-structure)
|
||||
- [Local Development Environment Setup](#local-development-environment-setup)
|
||||
- [Code Style and Contribution Guide](#code-style-and-contribution-guide)
|
||||
- [Internationalization Implementation Guide](#internationalization-implementation-guide)
|
||||
- [Appendix: Resources and References](#appendix-resources-and-references)
|
||||
|
||||
## Basic Technology Stack
|
||||
|
||||
The core technology stack of LobeChat is as follows:
|
||||
|
||||
- **Framework**: We chose [Next.js](https://nextjs.org/), a powerful React framework that provides key features such as server-side rendering, routing framework, and Router Handler.
|
||||
- **Component Library**: We use [Ant Design (antd)](https://ant.design/) as the basic component library, along with [lobe-ui](https://github.com/lobehub/lobe-ui) as our business component library.
|
||||
- **State Management**: We selected [zustand](https://github.com/pmndrs/zustand), a lightweight and easy-to-use state management library.
|
||||
- **Network Requests**: We use [swr](https://swr.vercel.app/), a React Hooks library for data fetching.
|
||||
- **Routing**: For routing management, we directly use the solution provided by [Next.js](https://nextjs.org/).
|
||||
- **Internationalization**: We use [i18next](https://www.i18next.com/) to support multiple languages in the application.
|
||||
- **Styling**: We use [antd-style](https://github.com/ant-design/antd-style), a CSS-in-JS library that complements Ant Design.
|
||||
- **Unit Testing**: We use [vitest](https://github.com/vitest-dev/vitest) for unit testing.
|
||||
|
||||
## Folder Directory Structure
|
||||
|
||||
The folder directory structure of LobeChat 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
|
||||
```
|
||||
|
||||
For a detailed introduction to the directory structure, see: [Folder Directory Structure](Folder-Structure.zh-CN.md)
|
||||
|
||||
## Local Development Environment Setup
|
||||
|
||||
This section outlines setting up the development environment and local development. Before starting, please ensure that Node.js, Git, and your chosen package manager (Bun or PNPM) are installed in your local environment.
|
||||
|
||||
We recommend using WebStorm as your integrated development environment (IDE).
|
||||
|
||||
1. **Get the code**: Clone the LobeChat code repository locally:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/lobehub/lobe-chat.git
|
||||
```
|
||||
|
||||
2. **Install dependencies**: Enter the project directory and install the required dependencies:
|
||||
|
||||
```bash
|
||||
cd lobe-chat
|
||||
# If you use Bun
|
||||
bun install
|
||||
# If you use PNPM
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. **Run and debug**: Start the local development server and begin your development journey:
|
||||
|
||||
```bash
|
||||
# Start the development server with Bun
|
||||
bun run dev
|
||||
# Visit http://localhost:3010 to view the application
|
||||
```
|
||||
|
||||
> \[!IMPORTANT]\
|
||||
> If you encounter the error "Could not find 'stylelint-config-recommended'" when installing dependencies with `npm`, please reinstall the dependencies using `pnpm` or `bun`.
|
||||
|
||||
Now, you should be able to see the welcome page of LobeChat in your browser. For a detailed environment setup guide, please refer to [Development Environment Setup Guide](Setup-Development.zh-CN.md).
|
||||
|
||||
## Code Style and Contribution Guide
|
||||
|
||||
In the LobeChat project, we place great emphasis on the quality and consistency of the code. For this reason, we have established a series of code style standards and contribution processes to ensure that every developer can smoothly participate in the project. Here are the code style and contribution guidelines you need to follow as a developer.
|
||||
|
||||
- **Code Style**: We use `@lobehub/lint` to unify the code style, including ESLint, Prettier, remarklint, and stylelint configurations. Please adhere to our code standards to maintain code consistency and readability.
|
||||
- **Contribution Process**: We use gitmoji and semantic release for code submission and release processes. Please use gitmoji to annotate your commit messages and ensure compliance with the semantic release standards so that our automation systems can correctly handle version control and releases.
|
||||
|
||||
All contributions will undergo code review. Maintainers may suggest modifications or requirements. Please respond actively to review comments and make timely adjustments. We look forward to your participation and contribution.
|
||||
|
||||
For detailed code style and contribution guidelines, please refer to [Code Style and Contribution Guide](Contributing-Guidelines.zh-CN.md).
|
||||
|
||||
## Internationalization Implementation Guide
|
||||
|
||||
LobeChat uses `i18next` and `lobe-i18n` to implement multilingual support, ensuring a global user experience.
|
||||
|
||||
Internationalization files are located in `src/locales`, containing the default language (Chinese). We generate other language JSON files automatically through `lobe-i18n`.
|
||||
|
||||
If you want to add a new language, follow specific steps detailed in [New Language Addition Guide](../Internationalization/Add-New-Locale.zh-CN.md). We encourage you to participate in our internationalization efforts to provide better services to global users.
|
||||
|
||||
For a detailed guide on internationalization implementation, please refer to [Internationalization Implementation Guide](../Internationalization/Internationalization-Implementation.zh-CN.md).
|
||||
|
||||
## Appendix: Resources and References
|
||||
|
||||
To support developers in better understanding and using the technology stack of LobeChat, we provide a comprehensive list of resources and references — [LobeChat Resources and References](https://github.com/lobehub/lobe-chat/wiki/Resources.zh-CN) - 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 [LobeChat GitHub Discussions](https://github.com/lobehub/lobe-chat/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.
|
@ -0,0 +1,19 @@
|
||||
# Resources and References
|
||||
|
||||
The design and development of LobeChat would not have been possible without the excellent projects in the community and ecosystem. We have used or referred to some outstanding resources and guides in the design and development process. Here are some key reference resources for developers to refer to during the development and learning process:
|
||||
|
||||
1. **OpenAI API Guide**: We use OpenAI's API to access and process AI conversation data. You can check out the [OpenAI API Guide](https://platform.openai.com/docs/api-reference/introduction) for more details.
|
||||
|
||||
2. **OpenAI SDK**: We use OpenAI's Node.js SDK to interact with OpenAI's API. You can view the source code and documentation on the [OpenAI SDK](https://github.com/openai/openai-node) GitHub repository.
|
||||
|
||||
3. **AI SDK**: We use Vercel's AI SDK to access and process AI conversation data. You can refer to the documentation of [AI SDK](https://sdk.vercel.ai/docs) for more details.
|
||||
|
||||
4. **LangChain**: Our early conversation feature was implemented based on LangChain. You can visit [LangChain](https://langchain.com) to learn more about it.
|
||||
|
||||
5. **Chat-Next-Web**: Chat Next Web is an excellent project, and some of LobeChat's features and workflows are referenced from its implementation. You can view the source code and documentation on the [Chat-Next-Web](https://github.com/Yidadaa/ChatGPT-Next-Web) GitHub repository.
|
||||
|
||||
6. **Next.js Documentation**: Our project is built on Next.js, and you can refer to the [Next.js Documentation](https://nextjs.org/docs) for more information about Next.js.
|
||||
|
||||
7. **FlowGPT**: FlowGPT is currently the world's largest Prompt community, and some of the agents in LobeChat come from active authors in FlowGPT. You can visit [FlowGPT](https://flowgpt.com/) to learn more about it.
|
||||
|
||||
We will continue to update and supplement this list to provide developers with more reference resources.
|
@ -0,0 +1,69 @@
|
||||
# Environment Setup Guide
|
||||
|
||||
Welcome to the LobeChat development environment setup guide.
|
||||
|
||||
#### TOC
|
||||
|
||||
- [Online Development](#online-development)
|
||||
- [Local Development](#local-development)
|
||||
- [Development Environment Requirements](#development-environment-requirements)
|
||||
- [Project Setup](#project-setup)
|
||||
|
||||
## Online Development
|
||||
|
||||
If you have access to GitHub Codespaces, you can click the button below to enter the online development environment with just one click:
|
||||
|
||||
[![][codespaces-shield]][codespaces-link]
|
||||
|
||||
## Local Development
|
||||
|
||||
Before starting development on LobeChat, you need to install and configure some necessary software and tools in your local environment. This document will guide you through these steps.
|
||||
|
||||
### Development Environment Requirements
|
||||
|
||||
First, you need to install the following software:
|
||||
|
||||
- Node.js: LobeChat is built on Node.js, so you need to install Node.js. We recommend installing the latest stable version.
|
||||
- Yarn: We use Yarn as the preferred package manager. You can download and install it from the Yarn official website.
|
||||
- PNPM: We use PNPM as an auxiliary package manager. You can download and install it from the PNPM official website.
|
||||
- Git: We use Git for version control. You can download and install it from the Git official website.
|
||||
- IDE: You can choose your preferred integrated development environment (IDE). We recommend using WebStorm, a powerful IDE particularly suitable for TypeScript development.
|
||||
|
||||
### Project Setup
|
||||
|
||||
After installing the above software, you can start setting up the LobeChat project.
|
||||
|
||||
1. **Get the code**: First, you need to clone the LobeChat codebase from GitHub. Run the following command in the terminal:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/lobehub/lobe-chat.git
|
||||
```
|
||||
|
||||
2. **Install dependencies**: Then, navigate to the project directory and use Yarn to install the project's dependencies:
|
||||
|
||||
```bash
|
||||
cd lobe-chat
|
||||
yarn install
|
||||
```
|
||||
|
||||
If you are using PNPM, you can execute:
|
||||
|
||||
```bash
|
||||
cd lobe-chat
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. **Start the development server**: After installing the dependencies, you can start the development server:
|
||||
|
||||
```bash
|
||||
yarn run dev
|
||||
```
|
||||
|
||||
Now, you can open `http://localhost:3010` in your browser, and you should see the welcome page of LobeChat. This indicates that you have successfully set up the development environment.
|
||||
|
||||

|
||||
|
||||
During the development process, if you encounter any issues with environment setup or have any questions about LobeChat 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-shield]: https://github.com/codespaces/badge.svg
|
@ -0,0 +1,87 @@
|
||||
# Testing Guide
|
||||
|
||||
LobeChat's testing strategy includes unit testing and end-to-end (E2E) testing. Below are detailed explanations of each type of testing:
|
||||
|
||||
#### TOC
|
||||
|
||||
- [Unit Testing](#unit-testing)
|
||||
- [🚧 End-to-End Testing](#-end-to-end-testing)
|
||||
- [Development Testing](#development-testing)
|
||||
- [1. Unit Testing](#1-unit-testing)
|
||||
- [Testing Strategy](#testing-strategy)
|
||||
|
||||
## Unit Testing
|
||||
|
||||
Unit testing is used to test the functionality of independent units in the application, such as components, functions, utility functions, etc. We use [vitest][vitest-url] for unit testing.
|
||||
|
||||
To run unit tests, you can use the following command:
|
||||
|
||||
```
|
||||
npm run test
|
||||
```
|
||||
|
||||
This will run all unit tests and generate a test report.
|
||||
|
||||
We encourage developers to write corresponding unit tests while writing code to ensure the quality and stability of the code.
|
||||
|
||||
## 🚧 End-to-End Testing
|
||||
|
||||
End-to-end testing is used to test the functionality and performance of the application in a real environment. It simulates real user operations and verifies the application's performance in different scenarios.
|
||||
|
||||
Currently, there is no integrated end-to-end testing in LobeChat. We will gradually introduce end-to-end testing in subsequent iterations.
|
||||
|
||||
## Development Testing
|
||||
|
||||
### 1. Unit Testing
|
||||
|
||||
Unit testing is conducted on the smallest testable units in the application, usually functions, components, or modules. In LobeChat, we use [vitest][vitest-url] for unit testing.
|
||||
|
||||
#### Writing Test Cases
|
||||
|
||||
Before writing unit tests, you need to create a directory with the same name as the file to be tested and name the test file `<filename>.test.ts`. For example, if you want to test the `src/utils/formatDate.ts` file, the test file should be named `src/utils/formatDate.test.ts`.
|
||||
|
||||
In the test file, you can use the `describe` and `it` functions to organize and write test cases. The `describe` function is used to create a test suite, and the `it` function is used to write specific test cases.
|
||||
|
||||
```typescript
|
||||
import { formatNumber } from './formatNumber';
|
||||
|
||||
describe('formatNumber', () => {
|
||||
it('should format number with comma separator', () => {
|
||||
const result = formatNumber(1000);
|
||||
expect(result).toBe('1,000');
|
||||
});
|
||||
|
||||
it('should return the same number if it is less than 1000', () => {
|
||||
const result = formatNumber(500);
|
||||
expect(result).toBe('500');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
In test cases, you can use the `expect` function to assert whether the test results meet expectations. The `expect` function can be used with various matchers, such as `toBe`, `toEqual`, `toBeTruthy`, etc.
|
||||
|
||||
#### Running Unit Tests
|
||||
|
||||
Execute unit tests by running the following command:
|
||||
|
||||
```
|
||||
npm run test
|
||||
```
|
||||
|
||||
This will run all unit tests and output the test results.
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
To write effective test cases, you can consider the following testing strategies:
|
||||
|
||||
- **Boundary Testing**: Test the boundary conditions of inputs, such as minimum value, maximum value, empty value, etc.
|
||||
- **Exception Testing**: Test the code handling exceptional cases, such as error handling, fallback in exceptional situations, etc.
|
||||
- **Functional Testing**: Test whether various functional modules of the application work properly, including user interaction, data processing, etc.
|
||||
- **Compatibility Testing**: Test the compatibility of the application on different browsers and devices.
|
||||
- **Performance Testing**: Test the performance of the application under different loads, such as response time, resource utilization, etc.
|
||||
|
||||
Also, ensure that your test cases have good coverage, covering critical code and functionality in the application.
|
||||
|
||||
By properly writing and executing unit tests, integration tests, and end-to-end tests, you can improve the quality and stability of the application and promptly identify and fix potential issues.
|
||||
|
||||
[vitest-url]: https://vitest.dev/
|
@ -0,0 +1,87 @@
|
||||
<div align="center">
|
||||
|
||||
<img height="120" src="https://registry.npmmirror.com/@lobehub/assets-logo/1.0.0/files/assets/logo-3d.webp">
|
||||
<img height="120" src="https://gw.alipayobjects.com/zos/kitchen/qJ3l3EPsdW/split.svg">
|
||||
<img height="120" src="https://registry.npmmirror.com/@lobehub/assets-emoji/1.3.0/files/assets/robot.webp">
|
||||
|
||||
<h1>Lobe Chat Contributing Wiki</h1>
|
||||
|
||||
LobeChat is an open-source, extensible ([Function Calling][fc-url]), high-performance chatbot framework. <br/> It supports one-click free deployment of your private ChatGPT/LLM web application.
|
||||
|
||||
[Usage Documents](https://lobehub.com/docs) | [使用指南](https://lobehub.com/docs)
|
||||
|
||||
</div>
|
||||
|
||||

|
||||
|
||||
<!-- DOCS LIST -->
|
||||
|
||||
### 🤯 Basic
|
||||
|
||||
- [Architecture Design](https://github.com/lobehub/lobe-chat/wiki/Architecture) | [架构设计](https://github.com/lobehub/lobe-chat/wiki/Architecture.zh-CN)
|
||||
- [Code Style and Contribution Guidelines](https://github.com/lobehub/lobe-chat/wiki/Contributing-Guidelines) | [代码风格与贡献指南](https://github.com/lobehub/lobe-chat/wiki/Contributing-Guidelines.zh-CN)
|
||||
- [Complete Guide to LobeChat Feature Development](https://github.com/lobehub/lobe-chat/wiki/Feature-Development) | [LobeChat 功能开发完全指南](https://github.com/lobehub/lobe-chat/wiki/Feature-Development.zh-CN)
|
||||
- [Conversation API Implementation Logic](https://github.com/lobehub/lobe-chat/wiki/Chat-API) | [会话 API 实现逻辑](https://github.com/lobehub/lobe-chat/wiki/Chat-API.zh-CN)
|
||||
- [Directory Structure](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure) | [目录架构](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure.zh-CN)
|
||||
- [Environment Setup Guide](https://github.com/lobehub/lobe-chat/wiki/Setup-Development) | [环境设置指南](https://github.com/lobehub/lobe-chat/wiki/Setup-Development.zh-CN)
|
||||
- [How to Develop a New Feature](https://github.com/lobehub/lobe-chat/wiki/Feature-Development-Frontend) | [如何开发一个新功能:前端实现](https://github.com/lobehub/lobe-chat/wiki/Feature-Development-Frontend.zh-CN)
|
||||
- [New Authentication Provider Guide](https://github.com/lobehub/lobe-chat/wiki/Add-New-Authentication-Providers) | [新身份验证方式开发指南](https://github.com/lobehub/lobe-chat/wiki/Add-New-Authentication-Providers.zh-CN)
|
||||
- [Resources and References](https://github.com/lobehub/lobe-chat/wiki/Resources) | [资源与参考](https://github.com/lobehub/lobe-chat/wiki/Resources.zh-CN)
|
||||
- [Technical Development Getting Started Guide](https://github.com/lobehub/lobe-chat/wiki/Intro) | [技术开发上手指南](https://github.com/lobehub/lobe-chat/wiki/Intro.zh-CN)
|
||||
- [Testing Guide](https://github.com/lobehub/lobe-chat/wiki/Test) | [测试指南](https://github.com/lobehub/lobe-chat/wiki/Test.zh-CN)
|
||||
|
||||
<br/>
|
||||
|
||||
### 🌎 Internationalization
|
||||
|
||||
- [Internationalization Implementation Guide](https://github.com/lobehub/lobe-chat/wiki/Internationalization-Implementation) | [国际化实现指南](https://github.com/lobehub/lobe-chat/wiki/Internationalization-Implementation.zh-CN)
|
||||
- [New Locale Guide](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale) | [新语种添加指南](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale.zh-CN)
|
||||
|
||||
<br/>
|
||||
|
||||
### ⌨️ State Management
|
||||
|
||||
- [Best Practices for State Management](https://github.com/lobehub/lobe-chat/wiki/State-Management-Intro) | [状态管理最佳实践](https://github.com/lobehub/lobe-chat/wiki/State-Management-Intro.zh-CN)
|
||||
- [Data Store Selector](https://github.com/lobehub/lobe-chat/wiki/State-Management-Selectors) | [数据存储取数模块](https://github.com/lobehub/lobe-chat/wiki/State-Management-Selectors.zh-CN)
|
||||
|
||||
<br/>
|
||||
|
||||
### 🤖 Agents
|
||||
|
||||
- [Agent Index and Submit](https://github.com/lobehub/lobe-chat-agents) | [助手索引与提交](https://github.com/lobehub/lobe-chat-agents/blob/main/README.zh-CN.md)
|
||||
|
||||
<br/>
|
||||
|
||||
### 🧩 Plugins
|
||||
|
||||
- [Plugin Index and Submit](https://github.com/lobehub/lobe-chat-plugins) | [插件索引与提交](https://github.com/lobehub/lobe-chat-plugins/blob/main/README.zh-CN.md)
|
||||
- [Plugin SDK Docs](https://chat-plugin-sdk.lobehub.com) | [插件 SDK 文档](https://chat-plugin-sdk.lobehub.com)
|
||||
|
||||
<br/>
|
||||
|
||||
### 📊 Others
|
||||
|
||||
- [Lighthouse Reports](https://github.com/lobehub/lobe-chat/wiki/Lighthouse) | [Lighthouse 测试报告](https://github.com/lobehub/lobe-chat/wiki/Lighthouse.zh-CN)
|
||||
|
||||
<br/>
|
||||
|
||||
<!-- DOCS LIST -->
|
||||
|
||||
---
|
||||
|
||||
<details><summary><h4>📝 License</h4></summary>
|
||||
|
||||
[![][fossa-license-shield]][fossa-license-url]
|
||||
|
||||
</details>
|
||||
|
||||
Copyright © 2023 [LobeHub][profile-url]. <br />
|
||||
This project is [MIT][license-url] licensed.
|
||||
|
||||
<!-- LINK GROUP -->
|
||||
|
||||
[fc-url]: https://sspai.com/post/81986
|
||||
[fossa-license-shield]: https://app.fossa.com/api/projects/git%2Bgithub.com%2Flobehub%2Flobe-chat.svg?type=large
|
||||
[fossa-license-url]: https://app.fossa.com/projects/git%2Bgithub.com%2Flobehub%2Flobe-chat
|
||||
[license-url]: https://github.com/lobehub/lobe-chat/blob/main/LICENSE
|
||||
[profile-url]: https://github.com/lobehub
|
@ -0,0 +1,62 @@
|
||||
# New Locale Guide
|
||||
|
||||
LobeChat uses [lobe-i18n](https://github.com/lobehub/lobe-cli-toolbox/tree/master/packages/lobe-i18n) as the i18n solution, which allows for quick addition of new language support in the application.
|
||||
|
||||
## TOC
|
||||
|
||||
- [Adding New Language Support](#adding-new-language-support)
|
||||
- [Step 1: Update the Internationalization Configuration File](#step-1-update-the-internationalization-configuration-file)
|
||||
- [Step 2: Automatically Translate Language Files](#step-2-automatically-translate-language-files)
|
||||
- [Step 3: Submit and Review Your Changes](#step-3-submit-and-review-your-changes)
|
||||
- [Additional Information](#additional-information)
|
||||
|
||||
## Adding New Language Support
|
||||
|
||||
To add new language internationalization support in LobeChat (for example, adding Vietnamese `vi-VN`), please follow the steps below:
|
||||
|
||||
### Step 1: Update the Internationalization Configuration File
|
||||
|
||||
1. Open the `.i18nrc.js` file. You can find this file in the project's root directory.
|
||||
2. Add the new language code to the configuration file. For example, to add Vietnamese, you need to add `'vi-VN'` to the configuration file.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// ... Other configurations
|
||||
|
||||
outputLocales: [
|
||||
'zh-TW',
|
||||
'en-US',
|
||||
'ru-RU',
|
||||
'ja-JP',
|
||||
// ...Other languages
|
||||
|
||||
'vi-VN', // Add 'vi-VN' to the array
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Step 2: Automatically Translate Language Files
|
||||
|
||||
LobeChat uses the `lobe-i18n` tool to automatically translate language files, so manual updating of i18n files is not required.
|
||||
|
||||
Run the following command to automatically translate and generate the Vietnamese language files:
|
||||
|
||||
```bash
|
||||
npm run i18n
|
||||
```
|
||||
|
||||
This will utilize the `lobe-i18n` tool to process the language files.
|
||||
|
||||
### Step 3: Submit and Review Your Changes
|
||||
|
||||
Once you have completed the above steps, you need to submit your changes and create a Pull Request.
|
||||
|
||||
Ensure that you follow LobeChat'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).
|
||||
|
||||
### Additional Information
|
||||
|
||||
- After submitting your Pull Request, please patiently wait for the project maintainers to review it.
|
||||
- If you encounter any issues, you can reach out to the LobeChat community for assistance.
|
||||
- For more accurate results, ensure that your Pull Request is based on the latest main branch and stays in sync with the main branch.
|
||||
|
||||
By following the above steps, you can successfully add new language support to LobeChat and ensure that the application provides a localized experience for more users.
|
@ -0,0 +1,62 @@
|
||||
# 新语种添加指南
|
||||
|
||||
LobeChat 使用 [lobe-i18n](https://github.com/lobehub/lobe-cli-toolbox/tree/master/packages/lobe-i18n) 作为 i18n 解决方案,可以在应用中快速添加新的语言支持。
|
||||
|
||||
## TOC
|
||||
|
||||
- [添加新的语言支持](#添加新的语言支持)
|
||||
- [步骤 1: 更新国际化配置文件](#步骤-1-更新国际化配置文件)
|
||||
- [步骤 2: 自动翻译语言文件](#步骤-2-自动翻译语言文件)
|
||||
- [步骤 3: 提交和审查你的更改](#步骤-3-提交和审查你的更改)
|
||||
- [附加信息](#附加信息)
|
||||
|
||||
## 添加新的语言支持
|
||||
|
||||
为了在 LobeChat 中添加新的语言国际化支持,(例如添加越南语 `vi-VN`),请按照以下步骤操作:
|
||||
|
||||
### 步骤 1: 更新国际化配置文件
|
||||
|
||||
1. 打开 `.i18nrc.js` 文件。你可以在项目的根目录中找到此文件。
|
||||
2. 将新的语言代码添加到配置文件中。例如,为了添加越南语,你需要在配置文件中添加 `'vi-VN'`。
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// ... 其他配置
|
||||
|
||||
outputLocales: [
|
||||
'zh-TW',
|
||||
'en-US',
|
||||
'ru-RU',
|
||||
'ja-JP',
|
||||
// ...其他语言
|
||||
|
||||
'vi-VN', // 在数组中添加 'vi-VN'
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### 步骤 2: 自动翻译语言文件
|
||||
|
||||
LobeChat 使用 `lobe-i18n` 工具来自动翻译语言文件,因此不需要手动更新 i18n 文件。
|
||||
|
||||
运行以下命令来自动翻译并生成越南语的语言文件:
|
||||
|
||||
```bash
|
||||
npm run i18n
|
||||
```
|
||||
|
||||
这将会利用 `lobe-i18n` 工具来处理语言文件。
|
||||
|
||||
### 步骤 3: 提交和审查你的更改
|
||||
|
||||
一旦你完成了上述步骤,你需要提交你的更改并创建一个 Pull Request。
|
||||
|
||||
请确保你遵循了 LobeChat 的贡献指南,并提供必要的描述来说明你的更改。例如,参考之前的类似 Pull Request [#759](https://github.com/lobehub/lobe-chat/pull/759)。
|
||||
|
||||
### 附加信息
|
||||
|
||||
- 提交你的 Pull Request 后,请耐心等待项目维护人员的审查。
|
||||
- 如果遇到任何问题,可以联系 LobeChat 社区寻求帮助。
|
||||
- 为了更精确的结果,确保你的 Pull Request 是基于最新的主分支,并且与主分支保持同步。
|
||||
|
||||
通过遵循上述步骤,你可以成功为 LobeChat 添加新的语言支持,并且确保应用能够为更多用户提供本地化的体验。
|
@ -0,0 +1,125 @@
|
||||
# Internationalization Implementation Guide
|
||||
|
||||
Welcome to the LobeChat Internationalization Implementation Guide. This document will guide you through understanding the internationalization mechanism of LobeChat, including file structure and how to add new languages. LobeChat uses `i18next` and `lobe-i18n` as the internationalization solution, aiming to provide users with seamless multilingual support.
|
||||
|
||||
## TOC
|
||||
|
||||
- [Internationalization Overview](#internationalization-overview)
|
||||
- [File Structure](#file-structure)
|
||||
- [Core Implementation Logic](#core-implementation-logic)
|
||||
- [Adding Support for New Languages](#adding-support-for-new-languages)
|
||||
- [Resources and Further Reading](#resources-and-further-reading)
|
||||
|
||||
## Internationalization Overview
|
||||
|
||||
Internationalization (i18n for short) is the process of enabling an application to adapt to different languages and regions. In LobeChat, we support multiple languages and achieve dynamic language switching and content localization through the `i18next` library. Our goal is to provide a localized experience for global users.
|
||||
|
||||
## File Structure
|
||||
|
||||
In the LobeChat project, internationalization-related files are organized as follows:
|
||||
|
||||
- `src/locales/default`: Contains translation files for the default development language (Chinese), which we use as Chinese.
|
||||
- `locales`: Contains folders for all supported languages, with each language folder containing the respective translation files generated by lobe-i18n.
|
||||
|
||||
In the directory structure of `src/locales`, the `default` folder contains the original translation files (Chinese), while each other language folder contains JSON translation files for the respective language. The files in each language folder correspond to the TypeScript files in the `default` folder, ensuring consistency in the structure of translation files across languages.
|
||||
|
||||
```
|
||||
src/locales
|
||||
├── create.ts
|
||||
├── default
|
||||
│ ├── chat.ts
|
||||
│ ├── common.ts
|
||||
│ ├── error.ts
|
||||
│ ├── index.ts
|
||||
│ ├── market.ts
|
||||
│ ├── migration.ts
|
||||
│ ├── plugin.ts
|
||||
│ ├── setting.ts
|
||||
│ ├── tool.ts
|
||||
│ └── welcome.ts
|
||||
└── resources.ts
|
||||
```
|
||||
|
||||
The file structure generated by lobe-i18n is as follows:
|
||||
|
||||
```
|
||||
locales
|
||||
├── ar
|
||||
│ ├── chat.json
|
||||
│ ├── common.json
|
||||
│ ├── error.json
|
||||
│ └── ... (other translation files)
|
||||
├── de-DE
|
||||
│ ├── chat.json
|
||||
│ ├── common.json
|
||||
│ ├── error.json
|
||||
│ └── ... (other translation files)
|
||||
├── en-US
|
||||
├── ... (other language directories)
|
||||
├── zh-CN
|
||||
└── zh-TW
|
||||
```
|
||||
|
||||
## Core Implementation Logic
|
||||
|
||||
The internationalization core implementation logic of LobeChat is as follows:
|
||||
|
||||
- Initialize and configure using the `i18next` library.
|
||||
- Automatically detect the user's language preference using `i18next-browser-languagedetector`.
|
||||
- Dynamically load translation resources using `i18next-resources-to-backend`.
|
||||
- Set the direction of the HTML document (LTR or RTL) based on the user's language preference.
|
||||
|
||||
Here is a simplified pseudo code example to illustrate the core implementation logic of internationalization in LobeChat:
|
||||
|
||||
```ts
|
||||
import i18n from 'i18next';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import resourcesToBackend from 'i18next-resources-to-backend';
|
||||
import { isRtlLang } from 'rtl-detect';
|
||||
|
||||
// Create i18n instance and configure
|
||||
const createI18nInstance = (lang) => {
|
||||
const i18nInstance = i18n
|
||||
.use(LanguageDetector) // Use language detection
|
||||
.use(
|
||||
resourcesToBackend((language, namespace) => {
|
||||
// Dynamically load translation resources for the corresponding language
|
||||
return import(`path/to/locales/${language}/${namespace}.json`);
|
||||
}),
|
||||
);
|
||||
|
||||
// Listen for language change events and dynamically set document direction
|
||||
i18nInstance.on('languageChanged', (language) => {
|
||||
const direction = isRtlLang(language) ? 'rtl' : 'ltr';
|
||||
document.documentElement.dir = direction; // Set HTML document direction
|
||||
});
|
||||
|
||||
// Initialize i18n instance
|
||||
i18nInstance.init({
|
||||
// Relevant configurations
|
||||
});
|
||||
|
||||
return i18nInstance;
|
||||
};
|
||||
```
|
||||
|
||||
In this example, we demonstrate how to use `i18next` and related plugins to initialize internationalization settings. We dynamically import translation resources and respond to language change events to adjust the text direction of the page. This process provides LobeChat with flexible multilingual support capabilities.
|
||||
|
||||
## Adding Support for New Languages
|
||||
|
||||
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)
|
||||
|
||||
To add support for new languages, please refer to the detailed steps in the [New Locale Addition Guide](Add-New-Locale.en-US).
|
||||
|
||||
## Resources and Further Reading
|
||||
|
||||
- [i18next Official Documentation](https://www.i18next.com/)
|
||||
- [lobe-i18n Tool Description](https://github.com/lobehub/lobe-cli-toolbox/tree/master/packages/lobe-i18n)
|
||||
|
||||
By following this guide, you can better understand and participate in the internationalization work of LobeChat, providing a seamless multilingual experience for global users.
|
@ -0,0 +1,65 @@
|
||||
# Lighthouse Reports
|
||||
|
||||
#### TOC
|
||||
|
||||
- [Welcome Page](#welcome-page)
|
||||
- [Chat Page](#chat-page)
|
||||
- [Market Page](#market-page)
|
||||
- [Settings Page](#settings-page)
|
||||
|
||||
## Welcome Page
|
||||
|
||||
> **Info**\
|
||||
> <https://chat-preview.lobehub.com/welcome>
|
||||
|
||||
| Desktop | Mobile |
|
||||
| :---------------------------------------------: | :--------------------------------------------: |
|
||||
| ![][welcome-desktop] | ![][welcome-mobile] |
|
||||
| [⚡️ Lighthouse Report][welcome-desktop-report] | [⚡️ Lighthouse Report][welcome-mobile-report] |
|
||||
|
||||
## Chat Page
|
||||
|
||||
> **Info**\
|
||||
> <https://chat-preview.lobehub.com/chat>
|
||||
|
||||
| Desktop | Mobile |
|
||||
| :------------------------------------------: | :-----------------------------------------: |
|
||||
| ![][chat-desktop] | ![][chat-mobile] |
|
||||
| [⚡️ Lighthouse Report][chat-desktop-report] | [⚡️ Lighthouse Report][chat-mobile-report] |
|
||||
|
||||
## Market Page
|
||||
|
||||
> **Info**\
|
||||
> <https://chat-preview.lobehub.com/market>
|
||||
|
||||
| Desktop | Mobile |
|
||||
| :--------------------------------------------: | :-------------------------------------------: |
|
||||
| ![][market-desktop] | ![][market-mobile] |
|
||||
| [⚡️ Lighthouse Report][market-desktop-report] | [⚡️ Lighthouse Report][market-mobile-report] |
|
||||
|
||||
## Settings Page
|
||||
|
||||
> **Info**\
|
||||
> <https://chat-preview.lobehub.com/settings>
|
||||
|
||||
| Desktop | Mobile |
|
||||
| :----------------------------------------------: | :---------------------------------------------: |
|
||||
| ![][settings-desktop] | ![][settings-mobile] |
|
||||
| [⚡️ Lighthouse Report][settings-desktop-report] | [⚡️ Lighthouse Report][settings-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/chat_preview_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/chat_preview_lobehub_com_chat.html
|
||||
[market-desktop]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/market/desktop/pagespeed.svg
|
||||
[market-desktop-report]: https://lobehub.github.io/lobe-chat/lighthouse/market/desktop/chat_preview_lobehub_com_market.html
|
||||
[market-mobile]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/market/mobile/pagespeed.svg
|
||||
[market-mobile-report]: https://lobehub.github.io/lobe-chat/lighthouse/market/mobile/chat_preview_lobehub_com_market.html
|
||||
[settings-desktop]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/settings/desktop/pagespeed.svg
|
||||
[settings-desktop-report]: https://lobehub.github.io/lobe-chat/lighthouse/settings/desktop/chat_preview_lobehub_com_settings.html
|
||||
[settings-mobile]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/settings/mobile/pagespeed.svg
|
||||
[settings-mobile-report]: https://lobehub.github.io/lobe-chat/lighthouse/settings/mobile/chat_preview_lobehub_com_settings.html
|
||||
[welcome-desktop]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/welcome/desktop/pagespeed.svg
|
||||
[welcome-desktop-report]: https://lobehub.github.io/lobe-chat/lighthouse/welcome/desktop/chat_preview_lobehub_com_welcome.html
|
||||
[welcome-mobile]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/welcome/mobile/pagespeed.svg
|
||||
[welcome-mobile-report]: https://lobehub.github.io/lobe-chat/lighthouse/welcome/mobile/chat_preview_lobehub_com_welcome.html
|
@ -0,0 +1,65 @@
|
||||
# Lighthouse 测试报告
|
||||
|
||||
#### TOC
|
||||
|
||||
- [Welcome 欢迎页面](#welcome-欢迎页面)
|
||||
- [Chat 聊天页面](#chat-聊天页面)
|
||||
- [Market 市场页面](#market-市场页面)
|
||||
- [Settings 设置页面](#settings-设置页面)
|
||||
|
||||
## Welcome 欢迎页面
|
||||
|
||||
> **Info**\
|
||||
> <https://chat-preview.lobehub.com/welcome>
|
||||
|
||||
| Desktop | Mobile |
|
||||
| :---------------------------------------------: | :--------------------------------------------: |
|
||||
| ![][welcome-desktop] | ![][welcome-mobile] |
|
||||
| [⚡️ Lighthouse Report][welcome-desktop-report] | [⚡️ Lighthouse Report][welcome-mobile-report] |
|
||||
|
||||
## Chat 聊天页面
|
||||
|
||||
> **Info**\
|
||||
> <https://chat-preview.lobehub.com/chat>
|
||||
|
||||
| Desktop | Mobile |
|
||||
| :------------------------------------------: | :-----------------------------------------: |
|
||||
| ![][chat-desktop] | ![][chat-mobile] |
|
||||
| [⚡️ Lighthouse Report][chat-desktop-report] | [⚡️ Lighthouse Report][chat-mobile-report] |
|
||||
|
||||
## Market 市场页面
|
||||
|
||||
> **Info**\
|
||||
> <https://chat-preview.lobehub.com/market>
|
||||
|
||||
| Desktop | Mobile |
|
||||
| :--------------------------------------------: | :-------------------------------------------: |
|
||||
| ![][market-desktop] | ![][market-mobile] |
|
||||
| [⚡️ Lighthouse Report][market-desktop-report] | [⚡️ Lighthouse Report][market-mobile-report] |
|
||||
|
||||
## Settings 设置页面
|
||||
|
||||
> **Info**\
|
||||
> <https://chat-preview.lobehub.com/settings>
|
||||
|
||||
| Desktop | Mobile |
|
||||
| :----------------------------------------------: | :---------------------------------------------: |
|
||||
| ![][settings-desktop] | ![][settings-mobile] |
|
||||
| [⚡️ Lighthouse Report][settings-desktop-report] | [⚡️ Lighthouse Report][settings-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/chat_preview_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/chat_preview_lobehub_com_chat.html
|
||||
[market-desktop]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/market/desktop/pagespeed.svg
|
||||
[market-desktop-report]: https://lobehub.github.io/lobe-chat/lighthouse/market/desktop/chat_preview_lobehub_com_market.html
|
||||
[market-mobile]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/market/mobile/pagespeed.svg
|
||||
[market-mobile-report]: https://lobehub.github.io/lobe-chat/lighthouse/market/mobile/chat_preview_lobehub_com_market.html
|
||||
[settings-desktop]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/settings/desktop/pagespeed.svg
|
||||
[settings-desktop-report]: https://lobehub.github.io/lobe-chat/lighthouse/settings/desktop/chat_preview_lobehub_com_settings.html
|
||||
[settings-mobile]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/settings/mobile/pagespeed.svg
|
||||
[settings-mobile-report]: https://lobehub.github.io/lobe-chat/lighthouse/settings/mobile/chat_preview_lobehub_com_settings.html
|
||||
[welcome-desktop]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/welcome/desktop/pagespeed.svg
|
||||
[welcome-desktop-report]: https://lobehub.github.io/lobe-chat/lighthouse/welcome/desktop/chat_preview_lobehub_com_welcome.html
|
||||
[welcome-mobile]: https://raw.githubusercontent.com/lobehub/lobe-chat/lighthouse/lighthouse/welcome/mobile/pagespeed.svg
|
||||
[welcome-mobile-report]: https://lobehub.github.io/lobe-chat/lighthouse/welcome/mobile/chat_preview_lobehub_com_welcome.html
|
@ -0,0 +1,224 @@
|
||||
# Best Practices for State Management
|
||||
|
||||
LobeChat differs from traditional CRUD web applications in that it involves a large amount of rich interactive capabilities. Therefore, it is crucial to design a data flow architecture that is easy to develop and maintain. This document will introduce the best practices for data flow management in LobeChat.
|
||||
|
||||
## TOC
|
||||
|
||||
- [Key Concepts](#key-concepts)
|
||||
- [Hierarchical Structure](#hierarchical-structure)
|
||||
- [Best Practices for LobeChat SessionStore Directory Structure](#best-practices-for-lobechat-sessionstore-directory-structure)
|
||||
- [Implementation of SessionStore](#implementation-of-sessionstore)
|
||||
|
||||
## Key Concepts
|
||||
|
||||
| Concept | Explanation |
|
||||
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| store | The store contains the application's state and actions. It allows access to and modification of the state during application rendering. |
|
||||
| state | State refers to the data of the application, storing the current state of the application. Any change in the state will **trigger a re-rendering** to reflect the new state. |
|
||||
| action | An action is an operation function that describes the interactive events occurring in the application. Actions are typically triggered by user interactions, network requests, or timers. Actions can be **synchronous** or **asynchronous**. |
|
||||
| reducer | A reducer is a pure function that takes the current state and action as parameters and returns a new state. It is used to update the application's state based on the action type. A reducer is a pure function with no side effects, therefore it is always a **synchronous** function. |
|
||||
| selector | A selector is a function used to retrieve specific data from the application's state. It takes the application's state as a parameter and returns computed or transformed data. Selectors can combine parts of the state or multiple states to generate derived data. Selectors are commonly used to map the application's state to a component's props for the component's use. |
|
||||
| slice | A slice is a concept used to express a part of the data model state. It specifies a state slice and its related state, action, reducer, and selector. Using slices, a large store can be divided into smaller, maintainable subtypes. |
|
||||
|
||||
## Hierarchical Structure
|
||||
|
||||
The structure of the Store can vary greatly depending on the complexity:
|
||||
|
||||
- **Low Complexity**: Generally includes 2 to 5 states and 3 to 4 actions. In this case, the structure usually consists of a `store.ts` and an `initialState.ts`.
|
||||
|
||||
```bash
|
||||
DataFill/store
|
||||
├── index.ts
|
||||
└── initialState.ts
|
||||
```
|
||||
|
||||
- **Moderate Complexity**: Typically involves 5 to 15 states and 5 to 10 actions, with the possibility of selectors for derived states and reducers to simplify data changes. The structure usually includes a `store.ts`, an `initialState.ts`, and a `selectors.ts`/`reducer.ts`.
|
||||
|
||||
```bash
|
||||
IconPicker/store
|
||||
├── index.ts
|
||||
├── initialState.ts
|
||||
├── selectors.ts
|
||||
└── store.ts
|
||||
```
|
||||
|
||||
```bash
|
||||
SortableList/store
|
||||
├── index.ts
|
||||
├── initialState.ts
|
||||
├── listDataReducer.ts
|
||||
└── store.ts
|
||||
```
|
||||
|
||||
- **Medium Complexity**: Involves 15 to 30 states and 10 to 20 actions, often requiring the use of multiple slices to manage different actions. The following code represents the internal data flow of the `SortableTree` component:
|
||||
|
||||
```bash
|
||||
SortableTree/store
|
||||
├── index.ts
|
||||
├── initialState.ts
|
||||
├── selectors.ts
|
||||
├── slices
|
||||
│ ├── crudSlice.ts
|
||||
│ ├── dndSlice.ts
|
||||
│ └── selectionSlice.ts
|
||||
├── store.ts
|
||||
└── treeDataReducer.ts
|
||||
```
|
||||
|
||||
- **High Complexity**: Involves over 30 states and 20 actions, requiring modular cohesion using slices. Each slice declares its own initState, actions, reducers, and selectors.
|
||||
|
||||
The directory structure of the previous version of SessionStore for LobeChat, with high complexity, implements a large amount of business logic. However, with the modularization of slices and the fractal architecture, it is easy to find the corresponding modules, making it easy to maintain and iterate on new features.
|
||||
|
||||
```bash
|
||||
LobeChat SessionStore
|
||||
├── index.ts
|
||||
├── initialState.ts
|
||||
├── selectors.ts
|
||||
├── slices
|
||||
│ ├── agentConfig
|
||||
│ │ ├── action.ts
|
||||
│ │ ├── index.ts
|
||||
│ │ ├── initialState.ts
|
||||
│ │ └── selectors.ts
|
||||
│ ├── chat
|
||||
│ │ ├── actions
|
||||
│ │ │ ├── index.ts
|
||||
│ │ │ ├── message.ts
|
||||
│ │ │ └── topic.ts
|
||||
│ │ ├── index.ts
|
||||
│ │ ├── initialState.ts
|
||||
│ │ ├── reducers
|
||||
│ │ │ ├── message.ts
|
||||
│ │ │ └── topic.ts
|
||||
│ │ ├── selectors
|
||||
│ │ │ ├── chat.ts
|
||||
│ │ │ ├── index.ts
|
||||
│ │ │ ├── token.ts
|
||||
│ │ │ ├── topic.ts
|
||||
│ │ │ └── utils.ts
|
||||
│ │ └── utils.ts
|
||||
│ └── session
|
||||
│ ├── action.ts
|
||||
│ ├── index.ts
|
||||
│ ├── initialState.ts
|
||||
│ ├── reducers
|
||||
│ │ └── session.ts
|
||||
│ └── selectors
|
||||
│ ├── export.ts
|
||||
│ ├── index.ts
|
||||
│ └── list.ts
|
||||
└── store.ts
|
||||
```
|
||||
|
||||
Based on the provided directory structure of LobeChat SessionStore, we can update the previous document and convert the examples to the implementation of LobeChat's SessionStore. The following is a portion of the updated document:
|
||||
|
||||
### Best Practices for LobeChat SessionStore Directory Structure
|
||||
|
||||
In the LobeChat application, session management is a complex functional module, so we use the Slice pattern to organize the data flow. Below is the directory structure of LobeChat SessionStore, where each directory and file has its specific purpose:
|
||||
|
||||
```bash
|
||||
src/store/session
|
||||
├── helpers.ts # Helper functions
|
||||
├── hooks # Custom React hooks
|
||||
│ ├── index.ts # Export file for hooks
|
||||
│ ├── useEffectAfterHydrated.ts # Hook for effects after session hydration
|
||||
│ ├── useOnFinishHydrationSession.ts # Hook for session hydration completion
|
||||
│ ├── useSessionChatInit.ts # Hook for session chat initialization
|
||||
│ └── useSessionHydrated.ts # Hook for session hydration status
|
||||
├── index.ts # Aggregated export file for SessionStore
|
||||
├── initialState.ts # Aggregated initialState for all slices
|
||||
├── selectors.ts # Selectors exported from various slices
|
||||
├── slices # Separated functional modules
|
||||
│ ├── agent # State and operations related to agents
|
||||
│ │ ├── action.ts # Action definitions related to agents
|
||||
│ │ ├── index.ts # Entry file for agent slice
|
||||
│ │ ├── selectors.test.ts # Tests for agent-related selectors
|
||||
│ │ └── selectors.ts # Selector definitions related to agents
|
||||
│ └── session # State and operations related to sessions
|
||||
│ ├── action.test.ts # Tests for session-related actions
|
||||
│ ├── action.ts # Action definitions related to sessions
|
||||
│ ├── helpers.ts # Helper functions related to sessions
|
||||
│ ├── initialState.ts # Initial state for session slice
|
||||
│ └── selectors # Session-related selectors and their tests
|
||||
│ ├── export.ts # Aggregated export for session selectors
|
||||
│ ├── index.ts # Entry file for session selectors
|
||||
│ ├── list.test.ts # Tests for list selectors
|
||||
│ └── list.ts # Definitions for list-related selectors
|
||||
└── store.ts # Creation and usage of SessionStore
|
||||
```
|
||||
|
||||
## Implementation of SessionStore
|
||||
|
||||
In LobeChat, the SessionStore is designed as the core module for managing session state and logic. It consists of multiple Slices, with each Slice managing a relevant portion of state and logic. Below is a simplified example of the SessionStore implementation:
|
||||
|
||||
#### store.ts
|
||||
|
||||
```ts
|
||||
import { PersistOptions, devtools, persist, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { devtools } from 'zustand/middleware';
|
||||
import { createWithEqualityFn } from 'zustand/traditional';
|
||||
|
||||
import { SessionStoreState, initialState } from './initialState';
|
||||
import { AgentAction, createAgentSlice } from './slices/agent/action';
|
||||
import { SessionAction, createSessionSlice } from './slices/session/action';
|
||||
|
||||
// =============== Aggregate createStoreFn ============ //
|
||||
|
||||
export type SessionStore = SessionAction & AgentAction & SessionStoreState;
|
||||
const createStore: StateCreator<SessionStore, [['zustand/devtools', never]]> = (...parameters) => ({
|
||||
...initialState,
|
||||
...createAgentSlice(...parameters),
|
||||
...createSessionSlice(...parameters),
|
||||
});
|
||||
|
||||
|
||||
|
||||
// =============== Implement useStore ============ //
|
||||
|
||||
export const useSessionStore = createWithEqualityFn<SessionStore>()(
|
||||
persist(
|
||||
subscribeWithSelector(
|
||||
devtools(createStore, {
|
||||
name: 'LobeChat_Session' + (isDev ? '_DEV' : ''),
|
||||
}),
|
||||
),
|
||||
persistOptions,
|
||||
),
|
||||
shallow,
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
In this `store.ts` file, we create a `useSessionStore` hook that uses the `zustand` library to create a global state manager. We merge the initialState and the state and actions of each Slice to create a complete SessionStore.
|
||||
|
||||
#### slices/session/action.ts
|
||||
|
||||
```ts
|
||||
import { StateCreator } from 'zustand';
|
||||
|
||||
import { SessionStore } from '@/store/session';
|
||||
|
||||
export interface SessionActions {
|
||||
/**
|
||||
* A custom hook that uses SWR to fetch sessions data.
|
||||
*/
|
||||
useFetchSessions: () => SWRResponse<any>;
|
||||
}
|
||||
|
||||
export const createSessionSlice: StateCreator<
|
||||
SessionStore,
|
||||
[['zustand/devtools', never]],
|
||||
[],
|
||||
SessionAction
|
||||
> = (set, get) => ({
|
||||
useFetchSessions: () => {
|
||||
// ...logic for initializing sessions
|
||||
},
|
||||
// ...implementation of other actions
|
||||
});
|
||||
```
|
||||
|
||||
In the `action.ts` file, we define a `SessionActions` interface to describe session-related actions and implement a `useFetchSessions` function to create these actions. Then, we merge these actions with the initial state to form the session-related Slice.
|
||||
|
||||
Through this layered and modular approach, we can ensure that LobeChat's SessionStore is clear, maintainable, and easy to extend and test.
|
@ -0,0 +1,68 @@
|
||||
# Data Store Selector
|
||||
|
||||
Selectors are data retrieval modules under the LobeChat data flow development framework. Their role is to extract data from the store using specific business logic for consumption by components.
|
||||
|
||||
Taking `src/store/plugin/selectors.ts` as an example:
|
||||
|
||||
This TypeScript code snippet defines an object named `pluginSelectors`, which contains a series of selector functions used to retrieve data from the plugin storage state. Selectors are functions that extract and derive data from a Redux store (or similar state management library). This specific example is for managing the state related to the frontend application's plugin system.
|
||||
|
||||
Here are some key points to note:
|
||||
|
||||
- `enabledSchema`: A function that returns an array of `ChatCompletionFunctions` filtered based on the enabled plugin list `enabledPlugins`. It appends the plugin identifier as a prefix to the API names to ensure uniqueness and uses the `uniqBy` function from the Lodash library to remove duplicates.
|
||||
- `onlinePluginStore`: Returns the current online plugin list.
|
||||
- `pluginList`: Returns the list of plugins, including custom plugins and standard plugins.
|
||||
- `getPluginMetaById`: Returns the plugin metadata based on the plugin ID.
|
||||
- `getDevPluginById`: Returns information about the custom plugins in development.
|
||||
- `getPluginManifestById`: Returns the plugin manifest based on the plugin ID.
|
||||
- `getPluginSettingsById`: Returns the plugin settings based on the plugin ID.
|
||||
- `getPluginManifestLoadingStatus`: Returns the loading status of the plugin manifest (loading, success, or error) based on the plugin ID.
|
||||
- `isCustomPlugin`: Checks if the plugin with the given ID is a custom plugin.
|
||||
- `displayPluginList`: Returns a processed plugin list, including author, avatar, creation time, description, homepage URL, identifier, and title.
|
||||
- `hasPluginUI`: Determines if the plugin has UI components based on the plugin ID.
|
||||
|
||||
Selectors are highly modular and maintainable. By encapsulating complex state selection logic in separate functions, they make the code more concise and intuitive when accessing state data in other parts of the application. Additionally, by using TypeScript, each function can have clear input and output types, which helps improve code reliability and development efficiency.
|
||||
|
||||
Taking the `displayPluginList` method as an example, its code is as follows:
|
||||
|
||||
```ts
|
||||
const pluginList = (s: PluginStoreState) => [...s.pluginList, ...s.customPluginList];
|
||||
|
||||
const displayPluginList = (s: PluginStoreState) =>
|
||||
pluginList(s).map((p) => ({
|
||||
author: p.author,
|
||||
avatar: p.meta?.avatar,
|
||||
createAt: p.createAt,
|
||||
desc: pluginHelpers.getPluginDesc(p.meta),
|
||||
homepage: p.homepage,
|
||||
identifier: p.identifier,
|
||||
title: pluginHelpers.getPluginTitle(p.meta),
|
||||
}));
|
||||
```
|
||||
|
||||
- `pluginList` method: Used to retrieve the list of all plugins from the plugin state storage `PluginStoreState`. It creates a new plugin list by combining two arrays: `pluginList` and `customPluginList`.
|
||||
- `displayPluginList` method: Calls the `pluginList` method to retrieve the merged plugin list and transforms the `title` and `desc` into text displayed on the UI.
|
||||
|
||||
In components, the final consumed data can be directly obtained by importing:
|
||||
|
||||
```tsx | pure
|
||||
import { usePluginStore } from '@/store/plugin';
|
||||
import { pluginSelectors } from '@/store/plugin/selectors';
|
||||
|
||||
const Render = ({ plugins }) => {
|
||||
const list = usePluginStore(pluginSelectors.displayPluginList);
|
||||
|
||||
return <> ... </>;
|
||||
};
|
||||
```
|
||||
|
||||
The benefits of implementing this approach are:
|
||||
|
||||
1. **Decoupling and reusability**: By separating selectors from components, we can reuse these selectors across multiple components without rewriting data retrieval logic. This reduces duplicate code, improves development efficiency, and makes the codebase cleaner and easier to maintain.
|
||||
2. **Performance optimization**: Selectors can be used to compute derived data, avoiding redundant calculations in each component. When the state changes, only the selectors dependent on that part of the state will recalculate, reducing unnecessary rendering and computation.
|
||||
3. **Ease of testing**: Selectors are pure functions, relying only on the passed parameters. This means they can be tested in an isolated environment without the need to simulate the entire store or component tree.
|
||||
4. **Type safety**: As LobeChat uses TypeScript, each selector has explicit input and output type definitions. This provides developers with the advantage of auto-completion and compile-time checks, reducing runtime errors.
|
||||
5. **Maintainability**: Selectors centralize the logic for reading state, making it more intuitive to track state changes and management. If the state structure changes, only the relevant selectors need to be updated, rather than searching and replacing in multiple places throughout the codebase.
|
||||
6. **Composability**: Selectors can be composed with other selectors to create more complex selection logic. This pattern allows developers to build a hierarchy of selectors, making state selection more flexible and powerful.
|
||||
7. **Simplified component logic**: Components do not need to know the structure of the state or how to retrieve and compute the required data. Components only need to call selectors to obtain the data needed for rendering, simplifying and clarifying component logic.
|
||||
|
||||
With this design, LobeChat developers can focus more on building the user interface and business logic without worrying about the details of data retrieval and processing. This pattern also provides better adaptability and scalability for potential future changes in state structure.
|
@ -0,0 +1,58 @@
|
||||
# Upstream Sync
|
||||
|
||||
English | [简体中文](https://github.com/lobehub/lobe-chat/wiki/Upstream-Sync.zh-CN)
|
||||
|
||||
## `A` Vercel / Zeabur Deployment
|
||||
|
||||
If you have deployed your own project following the one-click deployment steps in the README, you might encounter constant prompts indicating "updates available". This is because Vercel defaults to creating a new project instead of forking this one, resulting in an inability to accurately detect updates. We suggest you redeploy using the following steps:
|
||||
|
||||
- Remove the original repository;
|
||||
- Use the <kbd>Fork</kbd> button at the top right corner of the page to fork this project;
|
||||
- Re-select and deploy on `Vercel`.
|
||||
|
||||
## Enabling Automatic Updates
|
||||
|
||||
> \[!NOTE]
|
||||
>
|
||||
> If you encounter an error executing Upstream Sync, manually Sync Fork once
|
||||
|
||||
Once you have forked the project, due to Github restrictions, you will need to manually enable Workflows on the Actions page of your forked project and activate the Upstream Sync Action. Once enabled, you can set up hourly automatic updates.
|
||||
|
||||

|
||||

|
||||
|
||||
## `B` Docker Deployment
|
||||
|
||||
Upgrading the Docker deployment version is very simple, just redeploy the latest image of LobeChat. Here are the instructions to perform these steps:
|
||||
|
||||
1. Stop and delete the currently running LobeChat container (assuming the name of the LobeChat container is `lobe-chat`):
|
||||
|
||||
```fish
|
||||
docker stop lobe-chat
|
||||
docker rm lobe-chat
|
||||
```
|
||||
|
||||
2. Pull the latest Docker image of LobeChat:
|
||||
|
||||
```fish
|
||||
docker pull lobehub/lobe-chat
|
||||
```
|
||||
|
||||
3. Redeploy the LobeChat container using the newly pulled image:
|
||||
|
||||
```fish
|
||||
docker run -d -p 3210:3210 \
|
||||
-e OPENAI_API_KEY=sk-xxxx \
|
||||
-e OPENAI_PROXY_URL=https://api-proxy.com/v1 \
|
||||
-e ACCESS_CODE=lobe66 \
|
||||
--name lobe-chat \
|
||||
lobehub/lobe-chat
|
||||
```
|
||||
|
||||
Make sure you have sufficient permissions to stop and delete the container before executing these commands, and Docker has sufficient permissions to pull the new image.
|
||||
|
||||
> \[!NOTE]
|
||||
>
|
||||
> If I redeploy, will my local chat history be lost?
|
||||
>
|
||||
> Don't worry, all of LobeChat's chat history is stored in your local browser. Therefore, when you redeploy LobeChat using Docker, your chat history will not be lost.
|
@ -0,0 +1 @@
|
||||
This is the **🤯 / 🤖 Lobe Chat** wiki. [Wiki Home](https://github.com/lobehub/lobe-chat/wiki)
|
@ -0,0 +1,48 @@
|
||||
## Lobe Chat Contributing Wiki
|
||||
|
||||
#### 🏠 Home
|
||||
|
||||
- [TOC](Home.md) | [目录](Home.md)
|
||||
|
||||
<!-- DOCS LIST -->
|
||||
|
||||
#### 🤯 Basic
|
||||
|
||||
- [Architecture Design](https://github.com/lobehub/lobe-chat/wiki/Architecture) | [架构设计](https://github.com/lobehub/lobe-chat/wiki/Architecture.zh-CN)
|
||||
- [Code Style and Contribution Guidelines](https://github.com/lobehub/lobe-chat/wiki/Contributing-Guidelines) | [代码风格与贡献指南](https://github.com/lobehub/lobe-chat/wiki/Contributing-Guidelines.zh-CN)
|
||||
- [Complete Guide to LobeChat Feature Development](https://github.com/lobehub/lobe-chat/wiki/Feature-Development) | [LobeChat 功能开发完全指南](https://github.com/lobehub/lobe-chat/wiki/Feature-Development.zh-CN)
|
||||
- [Conversation API Implementation Logic](https://github.com/lobehub/lobe-chat/wiki/Chat-API) | [会话 API 实现逻辑](https://github.com/lobehub/lobe-chat/wiki/Chat-API.zh-CN)
|
||||
- [Directory Structure](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure) | [目录架构](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure.zh-CN)
|
||||
- [Environment Setup Guide](https://github.com/lobehub/lobe-chat/wiki/Setup-Development) | [环境设置指南](https://github.com/lobehub/lobe-chat/wiki/Setup-Development.zh-CN)
|
||||
- [How to Develop a New Feature](https://github.com/lobehub/lobe-chat/wiki/Feature-Development-Frontend) | [如何开发一个新功能:前端实现](https://github.com/lobehub/lobe-chat/wiki/Feature-Development-Frontend.zh-CN)
|
||||
- [New Authentication Provider Guide](https://github.com/lobehub/lobe-chat/wiki/Add-New-Authentication-Providers) | [新身份验证方式开发指南](https://github.com/lobehub/lobe-chat/wiki/Add-New-Authentication-Providers.zh-CN)
|
||||
- [Resources and References](https://github.com/lobehub/lobe-chat/wiki/Resources) | [资源与参考](https://github.com/lobehub/lobe-chat/wiki/Resources.zh-CN)
|
||||
- [Technical Development Getting Started Guide](https://github.com/lobehub/lobe-chat/wiki/Intro) | [技术开发上手指南](https://github.com/lobehub/lobe-chat/wiki/Intro.zh-CN)
|
||||
- [Testing Guide](https://github.com/lobehub/lobe-chat/wiki/Test) | [测试指南](https://github.com/lobehub/lobe-chat/wiki/Test.zh-CN)
|
||||
|
||||
#### 🌎 Internationalization
|
||||
|
||||
- [Internationalization Implementation Guide](https://github.com/lobehub/lobe-chat/wiki/Internationalization-Implementation) | [国际化实现指南](https://github.com/lobehub/lobe-chat/wiki/Internationalization-Implementation.zh-CN)
|
||||
- [New Locale Guide](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale) | [新语种添加指南](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale.zh-CN)
|
||||
|
||||
#### ⌨️ State Management
|
||||
|
||||
- [Best Practices for State Management](https://github.com/lobehub/lobe-chat/wiki/State-Management-Intro) | [状态管理最佳实践](https://github.com/lobehub/lobe-chat/wiki/State-Management-Intro.zh-CN)
|
||||
- [Data Store Selector](https://github.com/lobehub/lobe-chat/wiki/State-Management-Selectors) | [数据存储取数模块](https://github.com/lobehub/lobe-chat/wiki/State-Management-Selectors.zh-CN)
|
||||
|
||||
#### 🤖 Agents
|
||||
|
||||
- [Agent Index and Submit](https://github.com/lobehub/lobe-chat-agents) | [助手索引与提交](https://github.com/lobehub/lobe-chat-agents/blob/main/README.zh-CN.md)
|
||||
|
||||
#### 🧩 Plugins
|
||||
|
||||
- [Plugin Index and Submit](https://github.com/lobehub/lobe-chat-plugins) | [插件索引与提交](https://github.com/lobehub/lobe-chat-plugins/blob/main/README.zh-CN.md)
|
||||
- [Plugin SDK Docs](https://chat-plugin-sdk.lobehub.com) | [插件 SDK 文档](https://chat-plugin-sdk.lobehub.com)
|
||||
|
||||
#### 📊 Others
|
||||
|
||||
- [Lighthouse Reports](https://github.com/lobehub/lobe-chat/wiki/Lighthouse) | [Lighthouse 测试报告](https://github.com/lobehub/lobe-chat/wiki/Lighthouse.zh-CN)
|
||||
|
||||
<!-- DOCS LIST -->
|
||||
|
||||
<!-- LINK GROUP -->
|
@ -0,0 +1,33 @@
|
||||
# Logto secret
|
||||
LOGTO_CLIENT_ID=
|
||||
LOGTO_CLIENT_SECRET=
|
||||
|
||||
# MinIO S3 configuration
|
||||
MINIO_ROOT_USER=YOUR_MINIO_USER
|
||||
MINIO_ROOT_PASSWORD=YOUR_MINIO_PASSWORD
|
||||
|
||||
# Configure the bucket information of MinIO
|
||||
MINIO_LOBE_BUCKET=lobe
|
||||
S3_ACCESS_KEY_ID=
|
||||
S3_SECRET_ACCESS_KEY=
|
||||
|
||||
# Proxy, if you need it
|
||||
# HTTP_PROXY=http://localhost:7890
|
||||
# HTTPS_PROXY=http://localhost:7890
|
||||
|
||||
|
||||
# Other environment variables, as needed. You can refer to the environment variables configuration for the client version, making sure not to have ACCESS_CODE.
|
||||
# OPENAI_API_KEY=sk-xxxx
|
||||
# OPENAI_PROXY_URL=https://api.openai.com/v1
|
||||
# OPENAI_MODEL_LIST=...
|
||||
|
||||
|
||||
# ----- Other config -----
|
||||
# if no special requirements, no need to change
|
||||
LOBE_PORT=3210
|
||||
LOGTO_PORT=3001
|
||||
MINIO_PORT=9000
|
||||
|
||||
# Postgres related, which are the necessary environment variables for DB
|
||||
LOBE_DB_NAME=lobechat
|
||||
POSTGRES_PASSWORD=uWNZugjBqixf8dxC
|
@ -0,0 +1,102 @@
|
||||
services:
|
||||
network-service:
|
||||
image: alpine
|
||||
container_name: lobe-network
|
||||
ports:
|
||||
- '${MINIO_PORT}:${MINIO_PORT}' # MinIO API
|
||||
- '9001:9001' # MinIO Console
|
||||
- '${LOGTO_PORT}:${LOGTO_PORT}' # Logto
|
||||
- '3002:3002' # Logto Admin
|
||||
- '${LOBE_PORT}:3210' # LobeChat
|
||||
command: tail -f /dev/null
|
||||
networks:
|
||||
- lobe-network
|
||||
|
||||
postgresql:
|
||||
image: pgvector/pgvector:pg16
|
||||
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
|
||||
|
||||
minio:
|
||||
image: minio/minio
|
||||
container_name: lobe-minio
|
||||
network_mode: 'service:network-service'
|
||||
volumes:
|
||||
- './s3_data:/etc/minio/data'
|
||||
environment:
|
||||
- 'MINIO_ROOT_USER=${MINIO_ROOT_USER}'
|
||||
- 'MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}'
|
||||
- 'MINIO_API_CORS_ALLOW_ORIGIN=http://localhost:${LOBE_PORT}'
|
||||
restart: always
|
||||
command: >
|
||||
server /etc/minio/data --address ":${MINIO_PORT}" --console-address ":9001"
|
||||
|
||||
logto:
|
||||
image: svhd/logto
|
||||
container_name: lobe-logto
|
||||
network_mode: 'service:network-service'
|
||||
depends_on:
|
||||
postgresql:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- 'TRUST_PROXY_HEADER=1'
|
||||
- 'PORT=${LOGTO_PORT}'
|
||||
- 'DB_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgresql:5432/logto'
|
||||
- 'ENDPOINT=http://localhost:${LOGTO_PORT}'
|
||||
- 'ADMIN_ENDPOINT=http://localhost:3002'
|
||||
entrypoint: ['sh', '-c', 'npm run cli db seed -- --swe && npm start']
|
||||
|
||||
|
||||
lobe:
|
||||
image: lobehub/lobe-chat-database
|
||||
container_name: lobe-database
|
||||
network_mode: 'service:network-service'
|
||||
depends_on:
|
||||
postgresql:
|
||||
condition: service_healthy
|
||||
network-service:
|
||||
condition: service_started
|
||||
minio:
|
||||
condition: service_started
|
||||
logto:
|
||||
condition: service_started
|
||||
|
||||
environment:
|
||||
- 'APP_URL=http://localhost:3210'
|
||||
- 'NEXT_AUTH_SSO_PROVIDERS=logto'
|
||||
- 'KEY_VAULTS_SECRET=Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ='
|
||||
- 'NEXT_AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg'
|
||||
- 'NEXTAUTH_URL=http://localhost:${LOBE_PORT}/api/auth'
|
||||
- 'LOGTO_ISSUER=http://localhost:${LOGTO_PORT}/oidc'
|
||||
- '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'
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
data:
|
||||
driver: local
|
||||
s3_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
lobe-network:
|
||||
driver: bridge
|
@ -0,0 +1,35 @@
|
||||
# Proxy, if you need it
|
||||
# HTTP_PROXY=http://localhost:7890
|
||||
# HTTPS_PROXY=http://localhost:7890
|
||||
|
||||
|
||||
# Other environment variables, as needed. You can refer to the environment variables configuration for the client version, making sure not to have ACCESS_CODE.
|
||||
# OPENAI_API_KEY=sk-xxxx
|
||||
# OPENAI_PROXY_URL=https://api.openai.com/v1
|
||||
# OPENAI_MODEL_LIST=...
|
||||
|
||||
|
||||
# ===========================
|
||||
# ====== Preset config ======
|
||||
# ===========================
|
||||
# if no special requirements, no need to change
|
||||
LOBE_PORT=3210
|
||||
CASDOOR_PORT=8000
|
||||
MINIO_PORT=9000
|
||||
|
||||
# Postgres related, which are the necessary environment variables for DB
|
||||
LOBE_DB_NAME=lobechat
|
||||
POSTGRES_PASSWORD=uWNZugjBqixf8dxC
|
||||
|
||||
# Casdoor secret
|
||||
AUTH_CASDOOR_ID=a387a4892ee19b1a2249
|
||||
AUTH_CASDOOR_SECRET=dbf205949d704de81b0b5b3603174e23fbecc354
|
||||
|
||||
# MinIO S3 configuration
|
||||
MINIO_ROOT_USER=YOUR_MINIO_USER
|
||||
MINIO_ROOT_PASSWORD=YOUR_MINIO_PASSWORD
|
||||
|
||||
# Configure the bucket information of MinIO
|
||||
MINIO_LOBE_BUCKET=lobe
|
||||
S3_ACCESS_KEY_ID=soaucnP8Bip0TDdUjxng
|
||||
S3_SECRET_ACCESS_KEY=ZPUzvY34umfcfxvWKSv0P00vczVMB6YmgJS5J9eO
|
@ -0,0 +1,103 @@
|
||||
services:
|
||||
network-service:
|
||||
image: alpine
|
||||
container_name: lobe-network
|
||||
ports:
|
||||
- '${MINIO_PORT}:${MINIO_PORT}' # MinIO API
|
||||
- '9001:9001' # MinIO Console
|
||||
- '${CASDOOR_PORT}:${CASDOOR_PORT}' # Casdoor
|
||||
- '${LOBE_PORT}:3210' # LobeChat
|
||||
command: tail -f /dev/null
|
||||
networks:
|
||||
- lobe-network
|
||||
|
||||
postgresql:
|
||||
image: pgvector/pgvector:pg16
|
||||
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
|
||||
|
||||
minio:
|
||||
image: minio/minio
|
||||
container_name: lobe-minio
|
||||
network_mode: 'service:network-service'
|
||||
volumes:
|
||||
- './s3_data:/etc/minio/data'
|
||||
environment:
|
||||
- 'MINIO_ROOT_USER=${MINIO_ROOT_USER}'
|
||||
- 'MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}'
|
||||
- 'MINIO_API_CORS_ALLOW_ORIGIN=http://localhost:${LOBE_PORT}'
|
||||
restart: always
|
||||
command: >
|
||||
server /etc/minio/data --address ":${MINIO_PORT}" --console-address ":9001"
|
||||
|
||||
casdoor:
|
||||
image: casbin/casdoor
|
||||
container_name: lobe-casdoor
|
||||
entrypoint: /bin/sh -c './server --createDatabase=true'
|
||||
network_mode: 'service:network-service'
|
||||
depends_on:
|
||||
postgresql:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
RUNNING_IN_DOCKER: "true"
|
||||
driverName: "postgres"
|
||||
dataSourceName: "user=postgres password=${POSTGRES_PASSWORD} host=postgresql port=5432 sslmode=disable dbname=casdoor"
|
||||
origin: "http://localhost:${CASDOOR_PORT}"
|
||||
runmode: "dev"
|
||||
volumes:
|
||||
- ./init_data.json:/init_data.json
|
||||
|
||||
lobe:
|
||||
image: lobehub/lobe-chat-database
|
||||
container_name: lobe-database
|
||||
network_mode: 'service:network-service'
|
||||
depends_on:
|
||||
postgresql:
|
||||
condition: service_healthy
|
||||
network-service:
|
||||
condition: service_started
|
||||
minio:
|
||||
condition: service_started
|
||||
casdoor:
|
||||
condition: service_started
|
||||
|
||||
environment:
|
||||
- 'APP_URL=http://localhost:3210'
|
||||
- 'NEXT_AUTH_SSO_PROVIDERS=casdoor'
|
||||
- 'KEY_VAULTS_SECRET=Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ='
|
||||
- 'NEXT_AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg'
|
||||
- 'AUTH_URL=http://localhost:${LOBE_PORT}/api/auth'
|
||||
- 'AUTH_CASDOOR_ISSUER=http://localhost:${CASDOOR_PORT}'
|
||||
- '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'
|
||||
- 'LLM_VISION_IMAGE_USE_BASE64=1'
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
data:
|
||||
driver: local
|
||||
s3_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
lobe-network:
|
||||
driver: bridge
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,34 @@
|
||||
{
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": ["*"]
|
||||
},
|
||||
"Action": ["s3:GetBucketLocation"],
|
||||
"Resource": ["arn:aws:s3:::lobe"]
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": ["*"]
|
||||
},
|
||||
"Action": ["s3:ListBucket"],
|
||||
"Resource": ["arn:aws:s3:::lobe"],
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"s3:prefix": ["files/*"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": ["*"]
|
||||
},
|
||||
"Action": ["s3:PutObject", "s3:DeleteObject", "s3:GetObject"],
|
||||
"Resource": ["arn:aws:s3:::lobe/files/**"]
|
||||
}
|
||||
],
|
||||
"Version": "2012-10-17"
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
# Required: LobeChat domain for tRPC calls
|
||||
# Ensure this domain is whitelisted in your NextAuth providers and S3 service CORS settings
|
||||
APP_URL=https://lobe.example.com/
|
||||
|
||||
# Postgres related environment variables
|
||||
# Required: Secret key for encrypting sensitive information. Generate with: openssl rand -base64 32
|
||||
KEY_VAULTS_SECRET=Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ=
|
||||
# Required: Postgres database connection string
|
||||
# Format: postgresql://username:password@host:port/dbname
|
||||
# If using Docker, you can use the container name as the host
|
||||
DATABASE_URL=postgresql://postgres:uWNZugjBqixf8dxC@postgresql:5432/lobe
|
||||
|
||||
# NEXT_AUTH related environment variables
|
||||
# Supports auth0, Azure AD, GitHub, Authentik, Zitadel, Logto, etc.
|
||||
# For supported providers, see: https://lobehub.com/docs/self-hosting/advanced/auth#next-auth
|
||||
# If you have ACCESS_CODE, please remove it. We use NEXT_AUTH as the sole authentication source
|
||||
# Required: NextAuth secret key. Generate with: openssl rand -base64 32
|
||||
NEXT_AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
|
||||
# Required: Specify the authentication provider (e.g., Logto)
|
||||
NEXT_AUTH_SSO_PROVIDERS=logto
|
||||
# Required: NextAuth URL for callbacks
|
||||
NEXTAUTH_URL=https://lobe.example.com/api/auth
|
||||
|
||||
# NextAuth providers configuration (example using Logto)
|
||||
# For other providers, see: https://lobehub.com/docs/self-hosting/environment-variables/auth
|
||||
LOGTO_CLIENT_ID=YOUR_LOGTO_CLIENT_ID
|
||||
LOGTO_CLIENT_SECRET=YOUR_LOGTO_CLIENT_SECRET
|
||||
LOGTO_ISSUER=https://lobe-auth-api.example.com/oidc
|
||||
|
||||
# Proxy settings (if needed, e.g., when using GitHub as an auth provider)
|
||||
# HTTP_PROXY=http://localhost:7890
|
||||
# HTTPS_PROXY=http://localhost:7890
|
||||
|
||||
# S3 related environment variables (example using MinIO)
|
||||
# Required: S3 Access Key ID (for MinIO, invalid until manually created in MinIO UI)
|
||||
S3_ACCESS_KEY_ID=YOUR_S3_ACCESS_KEY_ID
|
||||
# Required: S3 Secret Access Key (for MinIO, invalid until manually created in MinIO UI)
|
||||
S3_SECRET_ACCESS_KEY=YOUR_S3_SECRET_ACCESS_KEY
|
||||
# Required: S3 Endpoint for server/client connections to S3 API
|
||||
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
|
||||
S3_ENABLE_PATH_STYLE=1
|
||||
|
||||
# Other basic environment variables (as needed)
|
||||
# See: https://lobehub.com/docs/self-hosting/environment-variables/basic
|
||||
# Note: For server versions, the API must support embedding models (OpenAI text-embedding-3-small) for file processing
|
||||
# You don't need to specify this model in OPENAI_MODEL_LIST
|
||||
# OPENAI_API_KEY=sk-xxxx
|
||||
# OPENAI_PROXY_URL=https://api.openai.com/v1
|
||||
# OPENAI_MODEL_LIST=...
|
@ -0,0 +1,70 @@
|
||||
services:
|
||||
postgresql:
|
||||
image: pgvector/pgvector:pg16
|
||||
container_name: lobe-postgres
|
||||
ports:
|
||||
- '5432:5432'
|
||||
volumes:
|
||||
- './data:/var/lib/postgresql/data'
|
||||
environment:
|
||||
- 'POSTGRES_DB=lobe'
|
||||
- 'POSTGRES_PASSWORD=uWNZugjBqixf8dxC'
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'pg_isready -U postgres']
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
restart: always
|
||||
|
||||
minio:
|
||||
image: minio/minio
|
||||
container_name: lobe-minio
|
||||
ports:
|
||||
- '9000:9000'
|
||||
- '9001:9001'
|
||||
volumes:
|
||||
- './s3_data:/etc/minio/data'
|
||||
environment:
|
||||
- 'MINIO_ROOT_USER=YOUR_MINIO_USER'
|
||||
- 'MINIO_ROOT_PASSWORD=YOUR_MINIO_PASSWORD'
|
||||
- 'MINIO_DOMAIN=lobe-s3-api.example.com'
|
||||
- 'MINIO_API_CORS_ALLOW_ORIGIN=https://lobe.example.com' # Your LobeChat's domain name.
|
||||
restart: always
|
||||
command: >
|
||||
server /etc/minio/data --address ":9000" --console-address ":9001"
|
||||
|
||||
|
||||
logto:
|
||||
image: svhd/logto
|
||||
container_name: lobe-logto
|
||||
ports:
|
||||
- '3001:3001'
|
||||
- '3002:3002'
|
||||
depends_on:
|
||||
postgresql:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- 'TRUST_PROXY_HEADER=1'
|
||||
- 'DB_URL=postgresql://postgres:uWNZugjBqixf8dxC@postgresql:5432/logto'
|
||||
- 'ENDPOINT=https://lobe-auth-api.example.com'
|
||||
- 'ADMIN_ENDPOINT=https://lobe-auth-ui.example.com'
|
||||
entrypoint: ['sh', '-c', 'npm run cli db seed -- --swe && npm start']
|
||||
|
||||
lobe:
|
||||
image: lobehub/lobe-chat-database
|
||||
container_name: lobe-database
|
||||
ports:
|
||||
- '3210:3210'
|
||||
depends_on:
|
||||
- postgresql
|
||||
- minio
|
||||
- logto
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
data:
|
||||
driver: local
|
||||
s3_data:
|
||||
driver: local
|
@ -0,0 +1,31 @@
|
||||
---
|
||||
title: Integrating Data Analytics Services in LobeChat for User Usage Analysis
|
||||
description: >-
|
||||
Learn how to integrate free/open-source data analytics services in LobeChat to
|
||||
collect user usage data efficiently.
|
||||
tags:
|
||||
- LobeChat
|
||||
- data analytics
|
||||
- user usage analysis
|
||||
- Vercel Analytics
|
||||
- web analytics
|
||||
---
|
||||
|
||||
# Data Analysis
|
||||
|
||||
To better help analyze the usage of LobeChat users, we have integrated several free/open-source data analytics services in LobeChat for collecting user usage data, which you can enable as needed.
|
||||
|
||||
<Callout type={'warning'}>
|
||||
Currently, the integrated data analytics platforms only support deployment and usage on
|
||||
Vercel/Zeit platforms and do not support Docker/Docker Compose deployment.
|
||||
</Callout>
|
||||
|
||||
## Vercel Analytics
|
||||
|
||||
[Vercel Analytics](https://vercel.com/analytics) is a data analytics service launched by Vercel, which can help you collect website visit data, including traffic, sources, and devices used for access.
|
||||
|
||||
We have integrated Vercel Analytics into the code, and you can enable it by setting the environment variable `ENABLE_VERCEL_ANALYTICS=1`, and then open the Analytics tab in your Vercel deployment project to view your app's visit data.
|
||||
|
||||
Vercel Analytics provides 2500 free Web Analytics Events per month (which can be understood as page views), which is generally sufficient for personal deployment and self-use products.
|
||||
|
||||
If you need to learn more about using Vercel Analytics, please refer to the [Vercel Web Analytics Quick Start](https://vercel.com/docs/analytics/quickstart).
|
@ -0,0 +1,73 @@
|
||||
---
|
||||
title: LobeChat Authentication Service Configuration
|
||||
description: >-
|
||||
Learn how to configure external authentication services using Clerk or Next
|
||||
Auth for centralized user authorization management. Supported authentication
|
||||
services include Auth0, Azure ID, etc.
|
||||
tags:
|
||||
- Authentication Service
|
||||
- Next Auth
|
||||
- SSO
|
||||
- Clerk
|
||||
---
|
||||
|
||||
# Authentication Service
|
||||
|
||||
LobeChat supports the configuration of external authentication services using Clerk or Next Auth for internal use within enterprises/organizations to centrally manage user authorization.
|
||||
|
||||
## Clerk
|
||||
|
||||
Clerk is a comprehensive identity verification solution that has recently gained popularity. It provides a simple yet powerful API and services to handle user authentication and session management. Clerk's design philosophy is to offer a concise and modern authentication solution that enables developers to easily integrate and use it.
|
||||
|
||||
LobeChat has deeply integrated with Clerk to provide users with a more secure and convenient login and registration experience. It also relieves developers from the burden of managing authentication logic. Clerk's concise and modern design philosophy aligns perfectly with LobeChat's goals, making user management on the entire platform more efficient and reliable.
|
||||
|
||||
By setting the environment variables `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` in LobeChat's environment, you can enable and use Clerk.
|
||||
|
||||
## Next Auth
|
||||
|
||||
Before using NextAuth, please set the following variables in LobeChat's environment variables:
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `NEXT_AUTH_SECRET` | Required | The key used to encrypt Auth.js session tokens. You can use the following command: `openssl rand -base64 32`, or visit `https://generate-secret.vercel.app/32` to generate the key. |
|
||||
| `NEXTAUTH_URL` | Required | This URL specifies the callback address for Auth.js when performing OAuth verification. Set this only if the default generated redirect address is incorrect. `https://example.com/api/auth` |
|
||||
| `NEXT_AUTH_SSO_PROVIDERS` | Optional | This environment variable is used to enable multiple identity verification sources simultaneously, separated by commas, for example, `auth0,azure-ad,authentik`. |
|
||||
|
||||
Currently supported identity verification services include:
|
||||
|
||||
<Cards>
|
||||
<Card href={'/docs/self-hosting/advanced/auth/next-auth/auth0'} title={'Auth0'} />
|
||||
<Card
|
||||
href={'/docs/self-hosting/advanced/auth/next-auth/microsoft-entra-id'}
|
||||
title={'Microsoft Entra ID'}
|
||||
/>
|
||||
<Card href={'/docs/self-hosting/advanced/auth/next-auth/authentik'} title={'Authentik'} />
|
||||
<Card href={'/docs/self-hosting/advanced/auth/next-auth/github'} title={'Github'} />
|
||||
<Card href={'/docs/self-hosting/advanced/auth/next-auth/zitadel'} title={'ZITADEL'} />
|
||||
<Card
|
||||
href={'/docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust'}
|
||||
title={'Cloudflare Zero Trust'}
|
||||
/>
|
||||
<Card href={'/docs/self-hosting/advanced/auth/next-auth/authelia'} title={'Authelia'} />
|
||||
<Card href={'/docs/self-hosting/advanced/auth/next-auth/logto'} title={'Logto'} />
|
||||
</Cards>
|
||||
|
||||
Click on the links to view the corresponding platform's configuration documentation.
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
To simultaneously enable multiple identity verification sources, please set the `NEXT_AUTH_SSO_PROVIDERS` environment variable, separating them with commas, for example, `auth0,azure-ad,authentik`.
|
||||
|
||||
The order corresponds to the display order of the SSO providers.
|
||||
|
||||
| SSO Provider | Value |
|
||||
| ------------------ | ----------- |
|
||||
| Auth0 | `auth0` |
|
||||
| Microsoft Entra ID | `azure-ad` |
|
||||
| Authentik | `authentik` |
|
||||
| Github | `github` |
|
||||
| ZITADEL | `zitadel` |
|
||||
|
||||
## Other SSO Providers
|
||||
|
||||
Please refer to the [NextAuth.js](https://next-auth.js.org/providers) documentation and feel free to submit a Pull Request.
|
@ -0,0 +1,81 @@
|
||||
---
|
||||
title: Configure Clerk Authentication Service - Step-by-Step Guide
|
||||
description: >-
|
||||
Learn how to set up Clerk authentication with environment variables and
|
||||
webhooks.
|
||||
tags:
|
||||
- Clerk Authentication
|
||||
- Environment Variables
|
||||
- Webhook Configuration
|
||||
---
|
||||
# Configure Clerk Authentication Service
|
||||
|
||||
Go to [Clerk](https://clerk.com?utm_source=lobehub\&utm_medium=docs) to register and create an application to obtain the corresponding Public Key and Secret Key.
|
||||
|
||||
## Get Environment Variables
|
||||
|
||||
<Steps>
|
||||
|
||||
### Add Public and Private Key Environment Variables
|
||||
|
||||
Add `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` environment variables. You can click on the "API Keys" in the menu and copy the corresponding values to get these environment variables.
|
||||
|
||||
<Image
|
||||
alt={'Find the corresponding public and private key environment variables in Clerk'}
|
||||
src={'https://github.com/lobehub/lobe-chat/assets/28616219/89883703-7a1a-4a11-b944-5d804544e57c'}>
|
||||
|
||||
>
|
||||
</Image>
|
||||
|
||||
The environment variables required for this step are as follows:
|
||||
|
||||
```shell
|
||||
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxx
|
||||
CLERK_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
### Create and Configure Webhook in Clerk
|
||||
|
||||
Since we let Clerk fully handle user authentication and management, we need Clerk to notify our application and store the changes in the user lifecycle (create, update, delete). We achieve this by using the Webhook provided by Clerk.
|
||||
|
||||
We need to add an endpoint in Clerk's Webhooks to inform Clerk to send notifications to this endpoint when a user's information changes.
|
||||
|
||||
<Image
|
||||
alt={'Add Webhooks endpoint in Clerk'}
|
||||
src={'https://github.com/lobehub/lobe-chat/assets/28616219/f50f47fb-5e8e-4930-bf4e-8cf6f5b8afb9'}>
|
||||
|
||||
>
|
||||
</Image>
|
||||
|
||||
Fill in your project URL in the endpoint, such as `https://your-project.com/api/webhooks/clerk`. Then, subscribe to events by checking the three user events (`user.created`, `user.deleted`, `user.updated`), and click create.
|
||||
|
||||
<Callout type={'warning'}>The `https://` in the URL is essential to maintain the integrity of the URL.</Callout>
|
||||
|
||||
<Image
|
||||
alt={'Configure URL and user events when adding Clerk Webhooks'}
|
||||
src={'https://github.com/lobehub/lobe-chat/assets/28616219/0249ea56-ab17-4aa9-a56c-9ebd556c2645'}>
|
||||
|
||||
>
|
||||
</Image>
|
||||
|
||||
### Add Webhook Secret to Environment Variables
|
||||
|
||||
After creating, you can find the secret of this Webhook in the bottom right corner:
|
||||
|
||||
<Image
|
||||
alt={'View Clerk Webhooks secret'}
|
||||
src={'https://github.com/lobehub/lobe-chat/assets/28616219/fab4abb2-584b-49de-9340-813382951635'}>
|
||||
|
||||
>
|
||||
</Image>
|
||||
|
||||
The environment variable corresponding to this secret is `CLERK_WEBHOOK_SECRET`:
|
||||
|
||||
```shell
|
||||
CLERK_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
||||
By following these steps, you have successfully configured the Clerk authentication service.
|
||||
|
@ -0,0 +1,132 @@
|
||||
---
|
||||
title: Configure Auth0 Identity Verification Service for LobeChat
|
||||
description: >-
|
||||
Learn how to configure Auth0 Identity Verification Service for LobeChat for
|
||||
your organization, including creating applications, adding users, and
|
||||
configuring environment variables.
|
||||
tags:
|
||||
- Auth0
|
||||
- Identity Verification
|
||||
- Single Sign-On
|
||||
- Environment Variables
|
||||
- User Management
|
||||
- SSO Integrations
|
||||
- Social Login
|
||||
---
|
||||
|
||||
# Configure Auth0 Identity Verification Service
|
||||
|
||||
<Steps>
|
||||
### Create Auth0 Application
|
||||
|
||||
Register and log in to [Auth0][auth0-client-page], click on the "Applications" in the left navigation bar to switch to the application management interface, and click "Create Application" in the upper right corner to create an application.
|
||||
|
||||
<Image
|
||||
alt="Create Auth0 Application S1"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/30863298/f068190f-0027-4d3b-8667-d632e43d5a86"
|
||||
/>
|
||||
|
||||
Fill in the application name you want to display to the organization users, choose any application type, and click "Create".
|
||||
|
||||
<Image
|
||||
alt="Create Auth0 Application S2"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/30863298/3e0082df-9b6f-46f3-b67f-bdc79e1eb2cc"
|
||||
/>
|
||||
|
||||
After successful creation, click on the corresponding application to enter the application details page, switch to the "Settings" tab, and you can see the corresponding configuration information.
|
||||
|
||||
<Image
|
||||
alt="Create Auth0 Application S3"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/30863298/df4cea85-616a-46f5-b2de-42725d9b82a6"
|
||||
/>
|
||||
|
||||
In the application configuration page, you also need to configure Allowed Callback URLs, where you should fill in:
|
||||
|
||||
```bash
|
||||
http(s)://your-domain/api/auth/callback/auth0
|
||||
```
|
||||
|
||||
<Image
|
||||
alt="Create Auth0 Application S4"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/30863298/62fbd09f-a69a-4460-949b-0f6285fa65b9"
|
||||
/>
|
||||
|
||||
<Callout type={'important'}>
|
||||
You can fill in or modify Allowed Callback URLs after deployment, but make sure the filled URL is
|
||||
consistent with the deployed URL.
|
||||
</Callout>
|
||||
|
||||
### Add Users
|
||||
|
||||
Click on the "Users Management" in the left navigation bar to enter the user management interface, where you can create users for your organization to log in to LobeChat.
|
||||
|
||||
<Image
|
||||
alt="Add Users"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/30863298/0beda150-d0b6-43cf-a9f1-fce928b83a96"
|
||||
/>
|
||||
|
||||
### Configure Environment Variables
|
||||
|
||||
When deploying LobeChat, you need to configure the following environment variables:
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `NEXT_AUTH_SECRET` | Required | Key used to encrypt Auth.js session tokens. You can generate a key using the following command: `openssl rand -base64 32` |
|
||||
| `NEXT_AUTH_SSO_PROVIDERS` | Required | Select the single sign-on provider for LoboChat. Use `auth0` for Auth0. |
|
||||
| `AUTH_AUTH0_ID` | Required | Client ID of the Auth0 application |
|
||||
| `AUTH_AUTH0_SECRET` | Required | Client Secret of the Auth0 application |
|
||||
| `AUTH_AUTH0_ISSUER` | Required | Domain of the Auth0 application, `https://example.auth0.com` |
|
||||
| `NEXTAUTH_URL` | Required | The URL is used to specify the callback address for the execution of OAuth authentication in Auth.js. It needs to be set only when the default address is incorrect. `https://example.com/api/auth` |
|
||||
|
||||
<Callout type={'tip'}>
|
||||
You can refer to the related variable details at [📘Environment Variables](/docs/self-hosting/environment-variable#auth0).
|
||||
|
||||
</Callout>
|
||||
</Steps>
|
||||
|
||||
<Callout>
|
||||
After successful deployment, users will be able to authenticate and use LobeChat using the users
|
||||
configured in Auth0.
|
||||
</Callout>
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Connecting to an Existing Single Sign-On Service
|
||||
|
||||
If your enterprise or organization already has a unified identity authentication infrastructure, you can connect to an existing single sign-on service in Applications -> SSO Integrations.
|
||||
|
||||
Auth0 supports single sign-on services such as Azure Active Directory, Slack, Google Workspace, Office 365, Zoom, and more. For a detailed list of supported services, please refer to [this link][auth0-sso-integrations].
|
||||
|
||||
<Image
|
||||
alt="Connecting to an Existing Single Sign-On Service"
|
||||
src="https://github.com/lobehub/lobe-chat/assets/30863298/9891347e-a338-4aa9-8714-f16c8dbcfcec"
|
||||
/>
|
||||
|
||||
### Configuring Social Login
|
||||
|
||||
If your enterprise or organization needs to support external user logins, you can configure social login services in Authentication -> Social.
|
||||
|
||||
<Image
|
||||
alt="Configuring Social Login"
|
||||
src="https://github.com/lobehub/lobe-chat/assets/30863298/880749a6-5ba4-4e20-a968-b583a54de7fa"
|
||||
/>
|
||||
|
||||
<Callout type={'warning'}>
|
||||
Configuring social login services by default allows anyone to authenticate, which may lead to
|
||||
LobeChat being abused by external users.
|
||||
</Callout>
|
||||
|
||||
<Callout>
|
||||
If you need to restrict login users, be sure to configure a **blocking policy**: After enabling
|
||||
the social login option, refer to [this article][auth0-login-actions-manual] to create an Action
|
||||
to set up a blocking/allow list.
|
||||
</Callout>
|
||||
|
||||
[auth0-client-page]: https://manage.auth0.com/dashboard
|
||||
[auth0-login-actions-manual]: https://auth0.com/blog/permit-or-deny-login-requests-using-auth0-actions/
|
||||
[auth0-sso-integrations]: https://marketplace.auth0.com/features/sso-integrations
|
@ -0,0 +1,75 @@
|
||||
---
|
||||
title: Configuring Authelia Authentication Service for LobeChat
|
||||
description: >-
|
||||
Learn how to configure Authelia authentication service in LobeChat, including
|
||||
creating a provider, configuring environment variables, and deploying
|
||||
LobeChat. Detailed steps and necessary environment variable settings.
|
||||
tags:
|
||||
- Authelia Configuration
|
||||
- Single Sign-On (SSO)
|
||||
- LobeChat Authentication
|
||||
- Environment Variables
|
||||
- Deployment Instructions
|
||||
---
|
||||
|
||||
## Configuring Authelia Authentication Service
|
||||
|
||||
## Authelia Configuration Flow
|
||||
|
||||
<Steps>
|
||||
### Create an Authelia Identity Provider
|
||||
|
||||
We assume you are already familiar with using Authelia. Let's say your LobeChat instance is deployed at https://lobe.example.com/.
|
||||
Note that currently only localhost supports HTTP access; other domains need to enable TLS, otherwise Authelia will actively interrupt authentication by default.
|
||||
|
||||
Now, let's open and edit the configuration file of your Authelia instance:
|
||||
|
||||
Add a new lobe-chat item under identity_providers -> oidc:
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
oidc:
|
||||
...
|
||||
## The other portions of the mandatory OpenID Connect 1.0 configuration go here.
|
||||
## See: https://www.authelia.com/c/oidc
|
||||
- id: lobe-chat
|
||||
description: LobeChat
|
||||
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
|
||||
public: false
|
||||
authorization_policy: two_factor
|
||||
redirect_uris:
|
||||
- https://chat.example.com/api/auth/callback/authelia
|
||||
scopes:
|
||||
- openid
|
||||
- profile
|
||||
- email
|
||||
userinfo_signing_algorithm: none
|
||||
```
|
||||
|
||||
Make sure to replace secret and redirect_urls with your own values.
|
||||
Note! The secret configured in Authelia is ciphertext, i.e., a salted hash value. Its corresponding plaintext needs to be filled in LobeChat later.
|
||||
|
||||
Save the configuration file and restart the Authelia service. Now we have completed the Authelia configuration.
|
||||
|
||||
### Configure Environment Variables
|
||||
|
||||
When deploying LobeChat, you need to configure the following environment variables:
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `NEXT_AUTH_SECRET` | Required | The secret used to encrypt Auth.js session tokens. You can generate a secret using the following command: `openssl rand -base64 32` |
|
||||
| `NEXT_AUTH_SSO_PROVIDERS` | Required | Select the SSO provider for LoboChat. Use `authentik` for Authentik. |
|
||||
| `AUTH_AUTHELIA_ID` | Required | The id just configured in Authelia, example value is lobe-chat |
|
||||
| `AUTH_AUTHELIA_SECRET` | Required | The plaintext corresponding to the secret just configured in Authelia, example value is insecure_secret |
|
||||
| `AUTH_AUTHELIA_ISSUER` | Required | Your Authelia URL, for example https://sso.example.com |
|
||||
| `NEXTAUTH_URL` | Required | This URL is used to specify the callback address for Auth.js when performing OAuth verification. It only needs to be set when the default generated redirect address is incorrect. https://chat.example.com/api/auth |
|
||||
|
||||
<Callout type={'tip'}>
|
||||
Go to [📘 Environment Variables](/docs/self-hosting/environment-variable#Authelia) for details about the variables.
|
||||
</Callout>
|
||||
</Steps>
|
||||
|
||||
<Callout type={'info'}>
|
||||
After a successful deployment, users will be able to use LobeChat by authenticating with the users
|
||||
configured in Authelia.
|
||||
</Callout>
|
@ -0,0 +1,73 @@
|
||||
---
|
||||
title: Configuring Authentik Authentication Service for LobeChat
|
||||
description: >-
|
||||
Learn how to configure Authentik for Single Sign-On (SSO) for LobeChat,
|
||||
including creating an application provider, setting environment variables, and
|
||||
deployment instructions.
|
||||
tags:
|
||||
- Authentik Configuration
|
||||
- Single Sign-On (SSO)
|
||||
- LobeChat Authentication
|
||||
- Environment Variables
|
||||
- Deployment Instructions
|
||||
---
|
||||
|
||||
## Configuring Authentik Authentication Service
|
||||
|
||||
## Authentik Configuration Flow
|
||||
|
||||
<Steps>
|
||||
### Create an Authentik Application Provider
|
||||
|
||||
In your Authentik instance, use the administrator account to go to **Admin Interface** -> **Applications** -> **Providers** and create a new provider.
|
||||
|
||||
Select **OAuth2/OpenID Provider** as the provider type. Fill in the provider name, select the authentication flow and authorization flow.
|
||||
|
||||
In the `Redirect URL/Origin (regex)` field, fill in:
|
||||
|
||||
```bash
|
||||
https://your-domain/api/auth/callback/authentik
|
||||
```
|
||||
|
||||
<Callout type={'info'}>
|
||||
- You can fill in or modify the `Redirect URL/Origin (regex)` later, but make sure the filled in
|
||||
URL matches the deployed URL. - Replace `your-domain` with your own domain name
|
||||
</Callout>
|
||||
|
||||
<Image
|
||||
alt="Create Authentik Provider"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/67304509/4244634e-5f68-48d5-aac0-e5f4b06d1c4b"
|
||||
/>
|
||||
|
||||
Click **Done**
|
||||
|
||||
After the creation is successful, click **Applications** on the left -> **Create**, fill in the name and Slug, select the provider created in the previous step, and click **Create**.
|
||||
|
||||
After the application provider is created, click the corresponding provider to enter the details page, click **Edit**, and save the `Client ID` and `Client Secret`.
|
||||
|
||||
Copy the URL of `OpenID Configuration Issuer` and save it.
|
||||
|
||||
### Configure Environment Variables
|
||||
|
||||
When deploying LobeChat, you need to configure the following environment variables:
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `NEXT_AUTH_SECRET` | Required | The secret used to encrypt Auth.js session tokens. You can generate a secret using the following command: `openssl rand -base64 32` |
|
||||
| `NEXT_AUTH_SSO_PROVIDERS` | Required | Select the SSO provider for LoboChat. Use `authentik` for Authentik. |
|
||||
| `AUTH_AUTHENTIK_ID` | Required | The Client ID from the Authentik application provider details page |
|
||||
| `AUTH_AUTHENTIK_SECRET` | Required | The Client Secret from the Authentik application provider details page |
|
||||
| `AUTH_AUTHENTIK_ISSUER` | Required | The OpenID Configuration Issuer from the Authentik application provider details page |
|
||||
| `NEXTAUTH_URL` | Required | This URL is used to specify the callback address for Auth.js when performing OAuth authentication. It only needs to be set when the default generated redirect address is incorrect. `https://example.com/api/auth` |
|
||||
|
||||
<Callout type={'tip'}>
|
||||
Go to [📘 Environment Variables](/docs/self-hosting/environment-variable#Authentik) for details about the variables.
|
||||
|
||||
</Callout>
|
||||
</Steps>
|
||||
|
||||
<Callout type={'info'}>
|
||||
After a successful deployment, users will be able to use LobeChat by authenticating with the users
|
||||
configured in Authentik.
|
||||
</Callout>
|
@ -0,0 +1,68 @@
|
||||
---
|
||||
title: Configuring Cloudflare Zero Trust Authentication Service for LobeChat
|
||||
description: >-
|
||||
Learn how to configure Cloudflare Zero Trust for Single Sign-On (SSO) for
|
||||
LobeChat, including creating an application provider, setting environment
|
||||
variables, and deployment instructions.
|
||||
tags:
|
||||
- Cloudflare Zero Trust
|
||||
- Single Sign-On (SSO)
|
||||
- LobeChat Authentication
|
||||
- Environment Variables
|
||||
- Deployment Instructions
|
||||
---
|
||||
|
||||
# Configuring Cloudflare Zero Trust Authentication Service
|
||||
|
||||
## Cloudflare Zero Trust Configuration Flow
|
||||
|
||||
<Steps>
|
||||
### Creating an Application in Cloudflare Zero Trust
|
||||
|
||||
We assume you are already familiar with using the Cloudflare Zero Trust platform and that your LobeChat instance is deployed at `https://chat.example.com`.
|
||||
|
||||
First, we need to visit `https://one.dash.cloudflare.com/` and navigate to `Access - Applications`.
|
||||
|
||||

|
||||
|
||||
Now, on the current page, click `Add an application` and select `SaaS`.
|
||||
|
||||

|
||||
|
||||
In the `Application` text box, enter the application name, such as `LobeChat SSO`. Then click `Select OIDC`, followed by clicking `Add application`.
|
||||
|
||||

|
||||
|
||||
At this point, you have successfully created a SaaS application named `LobeChat SSO` in Cloudflare Zero Trust.
|
||||
|
||||
Next, we need to enter `https://chat.example.com/api/auth/callback/cloudflare-zero-trust` in the `Redirect URLs` field (note that `chat.example.com` should be replaced with your instance's address).
|
||||
|
||||

|
||||
|
||||
Finally, scroll down the page and record the following three values: `Client secret`, `Client ID`, and `Issuer`. You will need these for setting the environment variables when deploying LobeChat.
|
||||
|
||||

|
||||
|
||||
### Configure Environment Variables
|
||||
|
||||
When deploying LobeChat, you need to configure the following environment variables:
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `NEXT_AUTH_SECRET` | Required | The secret used to encrypt Auth.js session tokens. You can generate a secret using the following command: `openssl rand -base64 32` |
|
||||
| `NEXT_AUTH_SSO_PROVIDERS` | Required | Select the SSO provider for LoboChat. Use `cloudflare-zero-trust` for Cloudflare Zero Trust. |
|
||||
| `AUTH_CLOUDFLARE_ZERO_TRUST_ID` | Required | The Client ID from the Cloudflare Zero Trust application provider details page |
|
||||
| `AUTH_CLOUDFLARE_ZERO_TRUST_SECRET` | Required | The Client Secret from the Cloudflare Zero Trust application provider details page |
|
||||
| `AUTH_CLOUDFLARE_ZERO_TRUST_ISSUER` | Required | The OpenID Configuration Issuer from the Cloudflare Zero Trust application provider details page |
|
||||
| `NEXTAUTH_URL` | Required | This URL is used to specify the callback address for Auth.js when performing OAuth authentication. It only needs to be set when the default generated redirect address is incorrect. `https://example.com/api/auth` |
|
||||
|
||||
<Callout type={'tip'}>
|
||||
Go to [📘 Environment Variables](/docs/self-hosting/environment-variable#Cloudflare%20Zero%20Trust) for details about the variables.
|
||||
|
||||
</Callout>
|
||||
</Steps>
|
||||
|
||||
<Callout type={'info'}>
|
||||
After a successful deployment, users will be able to use LobeChat by authenticating with the users
|
||||
configured in Cloudflare Zero Trust.
|
||||
</Callout>
|
@ -0,0 +1,65 @@
|
||||
---
|
||||
title: 在 LobeChat 中配置 Cloudflare Zero Trust 身份验证服务
|
||||
description: >-
|
||||
学习如何在 LobeChat 中配置 Cloudflare Zero Trust 身份验证服务,包括创建提供程序、配置环境变量和部署
|
||||
LobeChat。详细步骤和必要环境变量设置。
|
||||
tags:
|
||||
- Cloudflare Zero Trust
|
||||
- 身份验证
|
||||
- 单点登录
|
||||
- 环境变量
|
||||
- LobeChat
|
||||
---
|
||||
|
||||
# 配置 Cloudflare Zero Trust 身份验证服务
|
||||
|
||||
## Cloudflare Zero Trust 配置流程
|
||||
|
||||
<Steps>
|
||||
### 在 Cloudflare Zero Trust 中创建应用
|
||||
|
||||
我们现在默认您已经了解了如何使用 Cloudflare Zero Trust 平台且假设您的 LobeChat 实例部署在 `https://chat.example.com` 中。
|
||||
|
||||
首先我们需要访问 `https://one.dash.cloudflare.com/` 并前往 `Access - Applications` 中。
|
||||
|
||||

|
||||
|
||||
现在,在所在页面点击 `Add an application` 并选择 `SaaS`。
|
||||
|
||||

|
||||
|
||||
在 `Application` 文本框内填入应用名称,如:`LobeChat SSO`,然后点击 `Select OIDC` 后点击 `Add applicaiton`
|
||||
|
||||

|
||||
|
||||
至此您已成功在 Clouflare Zero Trust 中创建了一个名为 `LobeChat SSO` 的 SaaS 应用。
|
||||
|
||||
接下来我们需要在 `Redirect URLs` 中填入 `https://chat.example.com/api/auth/callback/cloudflare-zero-trust`(注意此处的 `chat.example.com` 需要替换为您的实例地址)
|
||||

|
||||
|
||||
最后我们将页面往下滚动,您将需要记录以下三个值 `Client secret`, `Client ID` 及 `Issuer` 以备后续部署 LobeChat 环境变量使用。
|
||||
|
||||

|
||||
|
||||
### 配置环境变量
|
||||
|
||||
在部署 LobeChat 时,你需要配置以下环境变量:
|
||||
|
||||
| 环境变量 | 类型 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| `NEXT_AUTH_SECRET` | 必选 | 用于加密 Auth.js 会话令牌的密钥。您可以使用以下命令生成秘钥: `openssl rand -base64 32` |
|
||||
| `NEXT_AUTH_SSO_PROVIDERS` | 必选 | 选择 LoboChat 的单点登录提供商。使用 Cloudflare Zero Trust 请填写 `cloudflare-zero-trust`。 |
|
||||
| `CLOUDFLARE_ZERO_TRUST_CLIENT_ID` | 必选 | 在 Cloudflare Zero Trust 生成的 `Client ID`,示例值是 `lobe-chat` |
|
||||
| `CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET` | 必选 | 在 Cloudflare Zero Trust 生成的 `Client secret`,示例值是 `insecure_secret` |
|
||||
| `CLOUDFLARE_ZERO_TRUST_ISSUER` | 必选 | 在 Cloudflare Zero Trust 生成的 `Issuer`,例如 `https://example.cloudflareaccess.com/cdn-cgi/access/sso/oidc/7db0f` |
|
||||
| `NEXTAUTH_URL` | 必选 | 该 URL 用于指定 Auth.js 在执行 OAuth 验证时的回调地址,当默认生成的重定向地址发生不正确时才需要设置。`https://chat.example.com/api/auth` |
|
||||
|
||||
<Callout type={'tip'}>
|
||||
前往 [📘 环境变量](/zh/docs/self-hosting/environment-variable#Cloudflare%20Zero%20Trust) 可查阅相关变量详情。
|
||||
|
||||
</Callout>
|
||||
</Steps>
|
||||
|
||||
<Callout type={'info'}>
|
||||
部署成功后,用户将可以使用 Cloudflare Zero Trust 中配置的用户通过身份认证并使用 LobeChat。
|
||||
</Callout>
|
@ -0,0 +1,101 @@
|
||||
---
|
||||
title: Configuring Github Authentication Service for LobeChat
|
||||
description: >-
|
||||
Learn how to configure Github authentication service for LobeChat, including
|
||||
creating a Github provider, setting up environment variables, and deploying
|
||||
LobeChat.
|
||||
tags:
|
||||
- Github authentication
|
||||
- LobeChat
|
||||
- Environment variables
|
||||
- Single Sign-On
|
||||
- OAuth authentication
|
||||
---
|
||||
|
||||
# Configuring Github Authentication Service
|
||||
|
||||
## Github Configuration Process
|
||||
|
||||
<Steps>
|
||||
### Create a Github Provider
|
||||
|
||||
Click [here][github-create-app] to create a new Github App.
|
||||
|
||||
Fill in the Github App name, Homepage URL, and Callback URL.
|
||||
|
||||
<Image
|
||||
alt="Create a Github Provider"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/64475363/2f919f99-2aaa-4fa7-9938-169d3ed09db7"
|
||||
/>
|
||||
|
||||
Set the webhook callback URL according to your needs.
|
||||
|
||||
<Image
|
||||
alt="Fill in other fields"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/64475363/d7ef5ad1-b1a3-435e-b1bc-4436d2b6fecd"
|
||||
/>
|
||||
|
||||
Set the permission to read email addresses.
|
||||
|
||||
<Image
|
||||
alt="Set required permissions"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/64475363/23131ca1-9e84-4a89-a840-ef79c4bc0251"
|
||||
/>
|
||||
<Image
|
||||
alt="Set permission to read email addresses"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/64475363/358bca8d-3d82-4e76-9a5e-90d16a39efde"
|
||||
/>
|
||||
|
||||
Set whether it is accessible publicly or only accessible to yourself.
|
||||
|
||||
<Image
|
||||
alt="Set whether it is accessible publicly or only accessible to yourself"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/64475363/995780cb-9096-4a36-ab17-d422703ab970"
|
||||
/>
|
||||
|
||||
Click "Create Github App".
|
||||
|
||||
After successful creation, click "Generate a new client secret" to create a client secret.
|
||||
|
||||
<Image
|
||||
alt="Create a new client secret"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/64475363/6d69bdca-7d18-4cbc-b3e0-220d8815cd29"
|
||||
/>
|
||||
|
||||
After successful creation, save the `Client ID` and `Client Secret`.
|
||||
|
||||
<Image
|
||||
alt="Create a new client secret"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/64475363/c6108133-a918-48b0-ab1a-e3fa607572a4"
|
||||
/>
|
||||
|
||||
### Configure Environment Variables
|
||||
|
||||
When deploying LobeChat, you need to configure the following environment variables:
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `NEXT_AUTH_SECRET` | Required | Key used to encrypt Auth.js session tokens. You can generate the key using the command: `openssl rand -base64 32` |
|
||||
| `NEXT_AUTH_SSO_PROVIDERS` | Required | Select the Single Sign-On provider for LobeChat. Use `github` for Github. |
|
||||
| `AUTH_GITHUB_ID` | Required | Client ID in the Github App details page. |
|
||||
| `AUTH_GITHUB_SECRET` | Required | Client Secret in the Github App details page. |
|
||||
| `NEXTAUTH_URL` | Required | This URL is used to specify the callback address for Auth.js when performing OAuth authentication. Only set it if the default generated redirect address is incorrect. `https://example.com/api/auth` |
|
||||
|
||||
<Callout type={'tip'}>
|
||||
Go to [📘 Environment Variables](/docs/self-hosting/environment-variables/auth#github) for detailed
|
||||
information on these variables.
|
||||
</Callout>
|
||||
</Steps>
|
||||
|
||||
<Callout type={'info'}>
|
||||
After successful deployment, users will be able to authenticate with Github and use LobeChat.
|
||||
</Callout>
|
||||
|
||||
[github-create-app]: https://github.com/settings/apps/new
|
@ -0,0 +1,74 @@
|
||||
---
|
||||
title: Configuring Logto Authentication Service in LobeChat
|
||||
description: >-
|
||||
Learn how to configure Logto authentication service in LobeChat, including
|
||||
deployment, creation, setting permissions, and environment variables.
|
||||
tags:
|
||||
- Logto Authentication
|
||||
- Environment Variable Configuration
|
||||
- Single Sign-On
|
||||
- LobeChat
|
||||
---
|
||||
|
||||
# Configuring Logto Authentication Service
|
||||
|
||||
[Logto](https://github.com/logto-io/logto) is an open-source authentication service with a simple and beautiful interface, rich in features and easy to use. You can choose to use the official Logto Cloud or opt for a private deployment of Logto.
|
||||
|
||||
<Callout type={'tip'}>
|
||||
|
||||
If you want to deploy Logto privately, we recommend using Docker Compose to deploy it together with the LobeChat database version. In this case, LobeChat can share the same Postgres instance with it.
|
||||
|
||||
</Callout>
|
||||
|
||||
## Logto Configuration Process
|
||||
|
||||
The following assumes your LobeChat database version domain is `https://lobe.example.com`.
|
||||
|
||||
If you are using a privately deployed Logto, assume its endpoint domain is `https://lobe-auth-api.example.com`.
|
||||
|
||||
If you are using Logto Cloud, assume its endpoint domain is `https://example.logto.app`.
|
||||
|
||||
<Steps>
|
||||
### Create Logto Application
|
||||
|
||||
Access your privately deployed Logto WebUI or [Logto Cloud](http://cloud.logto.io/) to enter the console, and create a `Next.js (App Router)` application under `Applications` with any name.
|
||||
|
||||
### Configure Logto
|
||||
|
||||
Set the `Redirect URI` to `https://lobe.example.com/api/auth/callback/logto` and the `Post sign-out redirect URI` to `https://lobe.example.com/`.
|
||||
|
||||
Set `CORS allowed origins` to `https://lobe.example.com`.
|
||||
|
||||
<Image alt="Configure Logto" inStep src="https://github.com/user-attachments/assets/5b816379-c07b-40ea-bde4-df16e2e4e523" />
|
||||
|
||||
After successful creation, save the `Client ID` and `Client Secret`.
|
||||
|
||||
### Configure Environment Variables
|
||||
|
||||
<Image alt="Configure Environment Variables" inStep src="https://github.com/user-attachments/assets/15af6d94-af4f-4aa9-bbab-7a46e9f9e837" />
|
||||
|
||||
Set the obtained `Client ID` and `Client Secret` as `LOGTO_CLIENT_ID` and `LOGTO_CLIENT_SECRET` in the LobeChat environment variables.
|
||||
|
||||
Configure `LOGTO_ISSUER` in the LobeChat environment variables as follows:
|
||||
|
||||
- `https://lobe-auth-api.example.com/oidc` if you are using a privately deployed Logto
|
||||
- `https://example.logto.app/oidc` if you are using Logto Cloud
|
||||
|
||||
When deploying LobeChat, you need to configure the following environment variables:
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| ------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `NEXT_AUTH_SECRET` | Required | The key used to encrypt Auth.js session tokens. You can generate a key using the command: `openssl rand -base64 32` |
|
||||
| `NEXT_AUTH_SSO_PROVIDERS` | Required | Select the single sign-on provider for LobeChat. For Logto, enter `logto`. |
|
||||
| `AUTH_LOGTO_ID` | Required | The Client ID from the Logto App details page |
|
||||
| `AUTH_LOGTO_SECRET` | Required | The Client Secret from the Logto App details page |
|
||||
| `AUTH_LOGTO_ISSUER` | Required | OpenID Connect issuer of the Logto provider |
|
||||
| `NEXTAUTH_URL` | Required | This URL specifies the callback address for Auth.js during OAuth verification, needed only if the default generated redirect address is incorrect. `https://lobe.example.com/api/auth` |
|
||||
|
||||
<Callout type={'tip'}>
|
||||
Visit [📘 Environment Variables](/docs/self-hosting/environment-variables/auth#logto) for details on related variables.
|
||||
|
||||
</Callout>
|
||||
</Steps>
|
||||
|
||||
<Callout type={'info'}>After successful deployment, users will be able to authenticate via Logto and use LobeChat.</Callout>
|
@ -0,0 +1,104 @@
|
||||
---
|
||||
title: Configuration of Microsoft Entra ID Authentication Service for LobeChat
|
||||
description: >-
|
||||
Learn how to configure Microsoft Entra ID Authentication Service for LobeChat,
|
||||
create applications, add users, and set up environment variables for seamless
|
||||
integration.
|
||||
tags:
|
||||
- Microsoft Entra ID
|
||||
- Authentication Service
|
||||
- Azure Portal
|
||||
- SSO
|
||||
- Environment Variables
|
||||
- LobeChat
|
||||
---
|
||||
|
||||
# Configuration of Microsoft Entra ID Authentication Service
|
||||
|
||||
<Steps>
|
||||
### Create a Microsoft Entra ID Application
|
||||
|
||||
In your [Microsoft Azure Portal][microsoft-azure-portal], go to Microsoft Entra ID -> App registrations -> New registration to create a new application.
|
||||
|
||||
Fill in the desired application name to be displayed to organizational users, choose the account types you wish to support, and if only internal users are supported, select `Accounts in this organizational directory only (Default Directory only - Single tenant)`.
|
||||
|
||||
In the `Redirect URI (optional)` section, for the application type, select `Web`, and in the Callback URL, enter:
|
||||
|
||||
```bash
|
||||
https://your-domain/api/auth/callback/azure-ad
|
||||
```
|
||||
|
||||
<Callout type={'info'}>
|
||||
- You can fill in or modify the Redirect URIs after registering, but make sure the URL you enter
|
||||
matches the deployed URL. - Please replace "your-domain" with your own domain.
|
||||
</Callout>
|
||||
|
||||
<Image
|
||||
alt="App Register"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/13883964/4f9d83bd-b3fc-4abc-bcf4-ccbad65c219d"
|
||||
/>
|
||||
|
||||
Click on "Register".
|
||||
|
||||
After successfully creating the application, click on the corresponding application to enter the application details page, and switch to the "Overview" tab to view the corresponding configuration information.
|
||||
|
||||
<Image
|
||||
alt="App Overview"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/13883964/48a0b702-05bd-4ce4-a007-a8ad00a36e5a"
|
||||
/>
|
||||
|
||||
Go to "Certificates & secrets", select the "Client secrets" tab, click on "New client secret", fill in the description, select the expiration time, and click on "Add" to create a new client secret.
|
||||
|
||||
<Image
|
||||
alt="Create App Client Secret"
|
||||
inStep
|
||||
src="https://github.com/lobehub/lobe-chat/assets/13883964/c9d66fa0-158c-4bd3-a1fa-969e638259d2"
|
||||
/>
|
||||
|
||||
<Callout type={'important'}>
|
||||
Please make sure to save your client secret as this is your only chance to view it.
|
||||
</Callout>
|
||||
|
||||
### Add Users
|
||||
|
||||
Go back to the "Microsoft Entra ID" interface, enter "Users", click on "New user", fill in the user information, and click on "Create" to create a user for using LobeChat.
|
||||
|
||||
### Configure Environment Variables
|
||||
|
||||
When deploying LobeChat, you need to configure the following environment variables:
|
||||
|
||||
| Environment Variable | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `NEXT_AUTH_SECRET` | Required | Key used to encrypt Auth.js session tokens. You can generate the key using the following command: `openssl rand -base64 32` |
|
||||
| `NEXT_AUTH_SSO_PROVIDERS` | Required | Select the single sign-on provider for LoboChat. Use `azure-ad` for Microsoft Entra ID. |
|
||||
| `AUTH_AZURE_AD_ID` | Required | Client ID of the Microsoft Entra ID application. |
|
||||
| `AUTH_AZURE_AD_SECRET` | Required | Client Secret of the Microsoft Entra ID application. |
|
||||
| `AUTH_AZURE_AD_TENANT_ID` | Required | Tenant ID of the Microsoft Entra ID application. |
|
||||
| `NEXTAUTH_URL` | Required | This URL is used to specify the callback address for Auth.js when performing OAuth authentication. It is only necessary to set it when the default generated redirect address is incorrect. `https://example.com/api/auth` |
|
||||
|
||||
<Callout type={'tip'}>
|
||||
You can refer to [📘 environment
|
||||
variables](/docs/self-hosting/environment-variable#microsoft-entra-id) for details on related
|
||||
variables.
|
||||
</Callout>
|
||||
|
||||
</Steps>
|
||||
|
||||
<Callout>
|
||||
After successful deployment, users will be able to authenticate and use LobeChat using the users
|
||||
configured in Microsoft Entra ID.
|
||||
</Callout>
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
Please explore further in the [Microsoft Entra ID Learning Center][microsoft-learn-entra].
|
||||
|
||||
## Related Resources
|
||||
|
||||
- [Quickstart: Register an app][microsoft-entra-register-app]
|
||||
|
||||
[microsoft-azure-portal]: https://portal.azure.com/
|
||||
[microsoft-entra-register-app]: https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app
|
||||
[microsoft-learn-entra]: https://learn.microsoft.com/en-us/entra/identity/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue