diff --git a/.bunfig.toml b/.bunfig.toml new file mode 100644 index 0000000000000..d6bb75b00762b --- /dev/null +++ b/.bunfig.toml @@ -0,0 +1,3 @@ +[install.lockfile] + +save = false diff --git a/.changelogrc.js b/.changelogrc.js new file mode 100644 index 0000000000000..9a2f5f98d8cd6 --- /dev/null +++ b/.changelogrc.js @@ -0,0 +1 @@ +module.exports = require('@lobehub/lint').changelog; diff --git a/.commitlintrc.js b/.commitlintrc.js new file mode 100644 index 0000000000000..9b8c6ace5a004 --- /dev/null +++ b/.commitlintrc.js @@ -0,0 +1 @@ +module.exports = require('@lobehub/lint').commitlint; diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000..e07e90e6a9e61 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +Dockerfile +.dockerignore +node_modules +npm-debug.log +.next +.git +scripts +docs +.github +*.md +.env.example diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000..7e3649acc2c16 --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000000..40a511afc8a78 --- /dev/null +++ b/.env.example @@ -0,0 +1,45 @@ +# add a access code to lock your lobe-chat application, it should be a six length string +ACCESS_CODE=lobe66 + +# add your custom model name, multi model seperate by comma. for example gpt-3.5-1106,gpt-4-1106 +# NEXT_PUBLIC_CUSTOM_MODELS=model1,model2,model3 + +# ---- only choose one from OpenAI Service and Azure OpenAI Service ---- # + +######################################## +############ OpenAI Service ############ +######################################## + +# 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 + +######################################## +######### Azure OpenAI Service ######### +######################################## +# 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 +# USE_AZURE_OPENAI=1 + +# 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. +# OPENAI_PROXY_URL=https://docs-test-001.openai.azure.com + +# Azure's API version, follows the YYYY-MM-DD format +# AZURE_API_VERSION=2023-08-01-preview + +######################################## +############ Market Service ############ +######################################## + +# The LobeChat plugins market index url +# PLUGINS_INDEX_URL=https://chat-plugins.lobehub.com + +# The LobeChat agents market index url +# AGENTS_INDEX_URL=https://chat-agents.lobehub.com + diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000000..b245203304656 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,32 @@ +# Eslintignore for LobeHub +################################################################ + +# dependencies +node_modules + +# ci +coverage +.coverage + +# test +jest* +_test_ +__test__ +*.test.ts + +# umi +.umi +.umi-production +.umi-test +.dumi/tmp* +!.dumirc.ts + +# production +dist +es +lib +logs + +# misc +# add other ignore file below +.next \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000000..9c44cf2458e52 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,18 @@ +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; + +module.exports = config; diff --git a/.github/ISSUE_TEMPLATE/1_bug_report.yml b/.github/ISSUE_TEMPLATE/1_bug_report.yml new file mode 100644 index 0000000000000..d181c38798158 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_bug_report.yml @@ -0,0 +1,45 @@ +name: '🐛 反馈缺陷 Bug Report' +description: '反馈一个问题缺陷 | Report an bug' +title: '[Bug] ' +labels: '🐛 Bug' +body: + - type: dropdown + attributes: + label: '💻 系统环境 | Operating System' + options: + - Windows + - macOS + - Ubuntu + - Other Linux + - Other + validations: + required: true + - type: dropdown + attributes: + label: '🌐 浏览器 | Browser' + options: + - Chrome + - Edge + - Safari + - Firefox + - Other + validations: + required: true + - type: textarea + attributes: + label: '🐛 问题描述 | Bug Description' + description: A clear and concise description of the bug. + validations: + required: true + - type: textarea + attributes: + label: '🚦 期望结果 | Expected Behavior' + description: A clear and concise description of what you expected to happen. + - type: textarea + attributes: + label: '📷 复现步骤 | Recurrence Steps' + description: A clear and concise description of how to recurrence. + - type: textarea + attributes: + label: '📝 补充信息 | Additional Information' + description: If your problem needs further explanation, or if the issue you're seeing cannot be reproduced in a gist, please add more information here. diff --git a/.github/ISSUE_TEMPLATE/2_feature_request.yml b/.github/ISSUE_TEMPLATE/2_feature_request.yml new file mode 100644 index 0000000000000..edcf7d0643cc3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_feature_request.yml @@ -0,0 +1,21 @@ +name: '🌠 功能需求 Feature Request' +description: '需求或建议 | Suggest an idea' +title: '[Request] ' +labels: '🌠 Feature Request' +body: + - type: textarea + attributes: + label: '🥰 需求描述 | Feature Description' + description: Please add a clear and concise description of the problem you are seeking to solve with this feature request. + validations: + required: true + - type: textarea + attributes: + label: '🧐 解决方案 | Proposed Solution' + description: Describe the solution you'd like in a clear and concise manner. + validations: + required: true + - type: textarea + attributes: + label: '📝 补充信息 | Additional Information' + description: Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/3_question.yml b/.github/ISSUE_TEMPLATE/3_question.yml new file mode 100644 index 0000000000000..f989f7d11be92 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3_question.yml @@ -0,0 +1,15 @@ +name: '😇 疑问或帮助 Help Wanted' +description: '疑问或需要帮助 | Need help' +title: '[Question] ' +labels: '😇 Help Wanted' +body: + - type: textarea + attributes: + label: '🧐 问题描述 | Proposed Solution' + description: A clear and concise description of the proplem. + validations: + required: true + - type: textarea + attributes: + label: '📝 补充信息 | Additional Information' + description: Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/4_other.md b/.github/ISSUE_TEMPLATE/4_other.md new file mode 100644 index 0000000000000..215dd1f39d8a3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/4_other.md @@ -0,0 +1,7 @@ +--- +name: '📝 其他 Other' +about: '其他问题 | Other issues' +title: '' +labels: '' +assignees: '' +--- diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000000..ae2208c76afcd --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ +#### 💻 变更类型 | Change Type + + + +- [ ] ✨ feat +- [ ] 🐛 fix +- [ ] ♻️ refactor +- [ ] 💄 style +- [ ] 🔨 chore +- [ ] 📝 docs + +#### 🔀 变更说明 | Description of Change + + + +#### 📝 补充信息 | Additional Information + + diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000000000..cbfce1c8bb622 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,45 @@ +name: Publish Docker Image + +on: + workflow_dispatch: + release: + types: [published] + +jobs: + push_to_registry: + name: Push Docker image to Docker Hub + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v4 + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_REGISTRY_USER }} + password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: lobehub/lobe-chat + tags: | + type=raw,value=latest + type=ref,event=tag + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/issue-auto-comments.yml b/.github/workflows/issue-auto-comments.yml new file mode 100644 index 0000000000000..124d0044609eb --- /dev/null +++ b/.github/workflows/issue-auto-comments.yml @@ -0,0 +1,73 @@ +name: Issue Auto Comment +on: + issues: + types: + - opened + - closed + - assigned + pull_request_target: + types: + - opened + - closed + +permissions: + contents: read + +jobs: + run: + permissions: + issues: write # for actions-cool/issues-helper to update issues + pull-requests: write # for actions-cool/issues-helper to update PRs + runs-on: ubuntu-latest + steps: + - name: Auto Comment on Issues Opened + uses: wow-actions/auto-comment@v1 + with: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN}} + issuesOpened: | + 👀 @{{ author }} + + Thank you for raising an issue. We will investigate into the matter and get back to you as soon as possible. + Please make sure you have given us as much context as possible.\ + 非常感谢您提交 issue。我们会尽快调查此事,并尽快回复您。 请确保您已经提供了尽可能多的背景信息。 + - name: Auto Comment on Issues Closed + uses: wow-actions/auto-comment@v1 + with: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN}} + issuesClosed: | + ✅ @{{ author }} + + This issue is closed, If you have any questions, you can comment and reply.\ + 此问题已经关闭。如果您有任何问题,可以留言并回复。 + - name: Auto Comment on Pull Request Opened + uses: wow-actions/auto-comment@v1 + with: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN}} + pullRequestOpened: | + 👍 @{{ author }} + + Thank you for raising your pull request and contributing to our Community + Please make sure you have followed our contributing guidelines. We will review it as soon as possible. + If you encounter any problems, please feel free to connect with us.\ + 非常感谢您提出拉取请求并为我们的社区做出贡献,请确保您已经遵循了我们的贡献指南,我们会尽快审查它。 + 如果您遇到任何问题,请随时与我们联系。 + - name: Auto Comment on Pull Request Merged + uses: actions-cool/pr-welcome@main + if: github.event.pull_request.merged == true + with: + token: ${{ secrets.GH_TOKEN }} + comment: | + ❤️ Great PR @${{ github.event.pull_request.user.login }} ❤️ + + The growth of project is inseparable from user feedback and contribution, thanks for your contribution! If you are interesting with the lobehub developer community, please join our [discord](https://discord.com/invite/AYFPHvv2jT) and then dm @arvinxx or @canisminor1990. They will invite you to our private developer channel. We are talking about the lobe-chat development or sharing ai newsletter around the world.\ + 项目的成长离不开用户反馈和贡献,感谢您的贡献! 如果您对 LobeHub 开发者社区感兴趣,请加入我们的 [discord](https://discord.com/invite/AYFPHvv2jT),然后私信 @arvinxx 或 @canisminor1990。他们会邀请您加入我们的私密开发者频道。我们将会讨论关于 Lobe Chat 的开发,分享和讨论全球范围内的 AI 消息。 + emoji: 'hooray' + pr-emoji: '+1, heart' + - name: Remove inactive + if: github.event.issue.state == 'open' && github.actor == github.event.issue.user.login + uses: actions-cool/issues-helper@v3 + with: + actions: 'remove-labels' + token: ${{ secrets.GH_TOKEN }} + issue-number: ${{ github.event.issue.number }} + labels: 'Inactive' diff --git a/.github/workflows/issue-close-require.yml b/.github/workflows/issue-close-require.yml new file mode 100644 index 0000000000000..d0ef9f0ae9851 --- /dev/null +++ b/.github/workflows/issue-close-require.yml @@ -0,0 +1,66 @@ +name: Issue Close Require + +on: + schedule: + - cron: '0 0 * * *' + +permissions: + contents: read + +jobs: + issue-check-inactive: + permissions: + issues: write # for actions-cool/issues-helper to update issues + pull-requests: write # for actions-cool/issues-helper to update PRs + runs-on: ubuntu-latest + steps: + - name: check-inactive + uses: actions-cool/issues-helper@v3 + with: + actions: 'check-inactive' + token: ${{ secrets.GH_TOKEN }} + inactive-label: 'Inactive' + inactive-day: 30 + + issue-close-require: + permissions: + issues: write # for actions-cool/issues-helper to update issues + pull-requests: write # for actions-cool/issues-helper to update PRs + runs-on: ubuntu-latest + steps: + - name: need reproduce + uses: actions-cool/issues-helper@v3 + with: + actions: 'close-issues' + token: ${{ secrets.GH_TOKEN }} + labels: '✅ Fixed' + inactive-day: 3 + body: | + 👋 @{{ github.event.issue.user.login }} +
+ Since the issue was labeled with `✅ Fixed`, but no response in 3 days. This issue will be closed. If you have any questions, you can comment and reply.\ + 由于该 issue 被标记为已修复,同时 3 天未收到回应。现关闭 issue,若有任何问题,可评论回复。 + - name: need reproduce + uses: actions-cool/issues-helper@v3 + with: + actions: 'close-issues' + token: ${{ secrets.GH_TOKEN }} + labels: '🤔 Need Reproduce' + inactive-day: 3 + body: | + 👋 @{{ github.event.issue.user.login }} +
+ Since the issue was labeled with `🤔 Need Reproduce`, but no response in 3 days. This issue will be closed. If you have any questions, you can comment and reply.\ + 由于该 issue 被标记为需要更多信息,却 3 天未收到回应。现关闭 issue,若有任何问题,可评论回复。 + - name: need reproduce + uses: actions-cool/issues-helper@v3 + with: + actions: 'close-issues' + token: ${{ secrets.GH_TOKEN }} + labels: "🙅🏻‍♀️ WON'T DO" + inactive-day: 3 + body: | + 👋 @{{ github.event.issue.user.login }} +
+ Since the issue was labeled with `🙅🏻‍♀️ WON'T DO`, and no response in 3 days. This issue will be closed. If you have any questions, you can comment and reply.\ + 由于该 issue 被标记为暂不处理,同时 3 天未收到回应。现关闭 issue,若有任何问题,可评论回复。 diff --git a/.github/workflows/issues-translate.yml b/.github/workflows/issues-translate.yml new file mode 100644 index 0000000000000..6df34feec0818 --- /dev/null +++ b/.github/workflows/issues-translate.yml @@ -0,0 +1,14 @@ +name: Issue Translate +on: + issue_comment: + types: [created] + issues: + types: [opened] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: usthe/issues-translate-action@v2.7 + with: + BOT_GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml new file mode 100644 index 0000000000000..2397521887bef --- /dev/null +++ b/.github/workflows/lighthouse.yml @@ -0,0 +1,72 @@ +name: Lighthouse Badger + +env: + TOKEN_NAME: 'GH_TOKEN' + REPO_BRANCH: 'lobehub/lobe-chat lighthouse' + USER_NAME: 'lobehubbot' + USER_EMAIL: 'i@lobehub.com' + AUDIT_TYPE: 'both' + MOBILE_LIGHTHOUSE_PARAMS: '--throttling.cpuSlowdownMultiplier=2' + DESKTOP_LIGHTHOUSE_PARAMS: '--preset=desktop --throttling.cpuSlowdownMultiplier=1' + COMMIT_MESSAGE: '🤖 chore: Lighthouse Results Refreshed' + +on: + schedule: + - cron: '0 0 * * *' # every day + workflow_dispatch: + +jobs: + lighthouse-badger-advanced: + name: ${{ matrix.NAME }} + runs-on: ubuntu-22.04 + timeout-minutes: 8 + strategy: + fail-fast: false + matrix: + include: + - NAME: 'ChatGPT Power | Welcome' + URLS: 'https://chat-preview.lobehub.com/welcome' + BADGES_ARGS: '-b pagespeed -o lighthouse/welcome -r' + COMMIT_MESSAGE: '🤖 chore: Lighthouse Results | Welcome' + - NAME: 'ChatGPT Power | Chat' + URLS: 'https://chat-preview.lobehub.com/chat' + BADGES_ARGS: '-b pagespeed -o lighthouse/chat -r' + COMMIT_MESSAGE: '🤖 chore: Lighthouse Results | Chat' + - NAME: 'ChatGPT Power | Market' + URLS: 'https://chat-preview.lobehub.com/market' + BADGES_ARGS: '-b pagespeed -o lighthouse/market -r' + COMMIT_MESSAGE: '🤖 chore: Lighthouse Results | Market' + - NAME: 'ChatGPT Power | Settings' + URLS: 'https://chat-preview.lobehub.com/settings' + BADGES_ARGS: '-b pagespeed -o lighthouse/settings -r' + COMMIT_MESSAGE: '🤖 chore: Lighthouse Results | Settings' + + steps: + - name: Preparatory Tasks + run: | + REPOSITORY=`expr "${{ env.REPO_BRANCH }}" : "\([^ ]*\)"` + BRANCH=`expr "${{ env.REPO_BRANCH }}" : ".* \([^ ]*\)"` + echo "REPOSITORY=$REPOSITORY" >> $GITHUB_ENV + echo "BRANCH=$BRANCH" >> $GITHUB_ENV + env: + REPO_BRANCH: ${{ matrix.REPO_BRANCH || env.REPO_BRANCH }} + - uses: actions/checkout@v4 + with: + repository: ${{ env.REPOSITORY }} + token: ${{ secrets[matrix.TOKEN_NAME] || secrets[env.TOKEN_NAME] }} + ref: ${{ env.BRANCH }} + - uses: actions/checkout@v4 + with: + repository: 'myactionway/lighthouse-badges' + path: temp_lighthouse_badges_nested + - uses: myactionway/lighthouse-badger-action@v2.2 + with: + urls: ${{ matrix.URLS }} + badges_args: ${{ matrix.BADGES_ARGS }} + audit_type: ${{ matrix.AUDIT_TYPE || env.AUDIT_TYPE }} + mobile_lighthouse_params: ${{ matrix.MOBILE_LIGHTHOUSE_PARAMS || env.MOBILE_LIGHTHOUSE_PARAMS }} + desktop_lighthouse_params: ${{ matrix.DESKTOP_LIGHTHOUSE_PARAMS || env.DESKTOP_LIGHTHOUSE_PARAMS }} + user_name: ${{ matrix.USER_NAME || env.USER_NAME }} + user_email: ${{ matrix.USER_EMAIL || env.USER_EMAIL }} + commit_message: ${{ matrix.COMMIT_MESSAGE || env.COMMIT_MESSAGE }} + max_push_attempts: 5 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000000..7d116a8322913 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,44 @@ +name: Release CI +on: + push: + branches: + - main + +jobs: + release: + name: Release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install bun + uses: oven-sh/setup-bun@v1 + + - name: Install deps + run: bun i + + - name: Lint + run: bun run lint + + - name: Test + run: bun run test + + - name: Release + run: bun run release + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Workflow + run: bun run workflow:readme + + - name: Commit changes + run: |- + git diff + git config --global user.name "lobehubbot" + git config --global user.email "i@lobehub.com" + git add . + git commit -m "📝 docs(bot): Auto sync agents & plugin to readme" || exit 0 + git push + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 0000000000000..bd59ad320aea0 --- /dev/null +++ b/.github/workflows/sync.yml @@ -0,0 +1,54 @@ +name: Upstream Sync + +permissions: + contents: write + issues: write + actions: write + +on: + schedule: + - cron: '0 * * * *' # every hour + workflow_dispatch: + +jobs: + sync_latest_from_upstream: + name: Sync latest commits from upstream repo + runs-on: ubuntu-latest + if: ${{ github.event.repository.fork }} + + steps: + - uses: actions/checkout@v4 + + - name: Clean issue notice + uses: actions-cool/issues-helper@v3 + with: + actions: 'close-issues' + labels: '🚨 Sync Fail' + + - name: Sync upstream changes + id: sync + uses: aormsby/Fork-Sync-With-Upstream-action@v3.4 + with: + upstream_sync_repo: lobehub/lobe-chat + upstream_sync_branch: main + target_sync_branch: main + target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set + test_mode: false + + - name: Sync check + if: failure() + uses: actions-cool/issues-helper@v3 + with: + actions: 'create-issue' + title: '🚨 同步失败 | Sync Fail' + labels: '🚨 Sync Fail' + body: | + Due to a change in the workflow file of the [ChatGPT Power][ChatGPT Power] upstream repository, GitHub has automatically suspended the scheduled automatic update. You need to manually sync your fork. Please refer to the detailed [Tutorial][tutorial-en-US] for instructions. + + 由于 [ChatGPT Power][ChatGPT Power] 上游仓库的 workflow 文件变更,导致 GitHub 自动暂停了本次自动更新,你需要手动 Sync Fork 一次,请查看 [详细教程][tutorial-zh-CN] + + ![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/273954625-df80c890-0822-4ac2-95e6-c990785cbed5.png) + + [ChatGPT Power]: https://github.com/lobehub/lobe-chat + [tutorial-zh-CN]: https://github.com/lobehub/lobe-chat/wiki/Upstream-Sync.zh-CN + [tutorial-en-US]: https://github.com/lobehub/lobe-chat/wiki/Upstream-Sync diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000000..1446dbe4b839f --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,23 @@ +name: Test CI +on: [push, pull_request] +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install bun + uses: oven-sh/setup-bun@v1 + + - name: Install deps + run: bun i + + - name: Lint + run: bun run lint + + - name: Test and coverage + run: bun run test:coverage + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 diff --git a/.github/workflows/wiki-sync.yml b/.github/workflows/wiki-sync.yml new file mode 100644 index 0000000000000..1d1eedd881225 --- /dev/null +++ b/.github/workflows/wiki-sync.yml @@ -0,0 +1,19 @@ +name: Wiki Sync + +on: + workflow_dispatch: + push: + paths: + - 'docs/**' + branches: + - main + +jobs: + update-wiki: + runs-on: ubuntu-latest + name: Wiki sync + steps: + - uses: OrlovM/Wiki-Action@v1 + with: + path: 'docs' + token: ${{ secrets.GH_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000..8b5c1058d48ea --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ +# 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 +bun.lockb \ No newline at end of file diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 0000000000000..c160a7712333e --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx --no -- commitlint --edit ${1} diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000000000..8da041a2244a3 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npm run type-check +npx --no-install lint-staged diff --git a/.i18nrc.js b/.i18nrc.js new file mode 100644 index 0000000000000..9cfa51cae4279 --- /dev/null +++ b/.i18nrc.js @@ -0,0 +1,12 @@ +const { description } = require('./package.json'); +const { defineConfig } = require('@lobehub/i18n-cli'); + +module.exports = defineConfig({ + reference: description, + entry: 'locales/zh_CN', + entryLocale: 'zh_CN', + output: 'locales', + outputLocales: ['zh_TW', 'en_US', 'es_ES', 'ru_RU', 'ja_JP', 'ko_KR'], + temperature: 0, + modelName: 'gpt-3.5-turbo-1106', +}); diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000000000..d9ed3d371eb9d --- /dev/null +++ b/.npmrc @@ -0,0 +1,11 @@ +lockfile=false +resolution-mode=highest +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* diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000000..3e459cbe47962 --- /dev/null +++ b/.prettierignore @@ -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 \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000000000..f0355a9c1a75f --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1 @@ +module.exports = require('@lobehub/lint').prettier; diff --git a/.releaserc.js b/.releaserc.js new file mode 100644 index 0000000000000..37930011d9d43 --- /dev/null +++ b/.releaserc.js @@ -0,0 +1 @@ +module.exports = require('@lobehub/lint').semanticRelease; diff --git a/.remarkrc.js b/.remarkrc.js new file mode 100644 index 0000000000000..b673c10ed1cc7 --- /dev/null +++ b/.remarkrc.js @@ -0,0 +1 @@ +module.exports = require('@lobehub/lint').remarklint; diff --git a/.stylelintrc.js b/.stylelintrc.js new file mode 100644 index 0000000000000..c40700dd91da8 --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,8 @@ +const config = require('@lobehub/lint').stylelint; + +module.exports = { + ...config, + rules: { + 'selector-id-pattern': null, + }, +}; diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000000..90e4e7f4f5b11 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7127 @@ + + +# Changelog + +## [Version 0.105.0](https://github.com/lobehub/lobe-chat/compare/v0.104.0...v0.105.0) + +Released on **2023-11-22** + +#### ✨ Features + +- **misc**: Standalone pluginn can get more arguments on init. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Standalone pluginn can get more arguments on init, closes [#498](https://github.com/lobehub/lobe-chat/issues/498) ([a7624f5](https://github.com/lobehub/lobe-chat/commit/a7624f5)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.104.0](https://github.com/lobehub/lobe-chat/compare/v0.103.1...v0.104.0) + +Released on **2023-11-21** + +#### ✨ Features + +- **misc**: Support using env variable to set regions for OpenAI Edge Functions.. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Support using env variable to set regions for OpenAI Edge Functions., closes [#473](https://github.com/lobehub/lobe-chat/issues/473) ([de6b79e](https://github.com/lobehub/lobe-chat/commit/de6b79e)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.103.1](https://github.com/lobehub/lobe-chat/compare/v0.103.0...v0.103.1) + +Released on **2023-11-21** + +#### 🐛 Bug Fixes + +- **misc**: Image optimization in docker standalone build. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Image optimization in docker standalone build, closes [#494](https://github.com/lobehub/lobe-chat/issues/494) ([d2bcac3](https://github.com/lobehub/lobe-chat/commit/d2bcac3)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.103.0](https://github.com/lobehub/lobe-chat/compare/v0.102.4...v0.103.0) + +Released on **2023-11-20** + +#### ✨ Features + +- **misc**: Support the auto create topic configuration. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Support the auto create topic configuration, closes [#490](https://github.com/lobehub/lobe-chat/issues/490) ([a7b7ef0](https://github.com/lobehub/lobe-chat/commit/a7b7ef0)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.102.4](https://github.com/lobehub/lobe-chat/compare/v0.102.3...v0.102.4) + +Released on **2023-11-20** + +#### 🐛 Bug Fixes + +- **plugin**: Fix plugin can't get settings from lobe-chat. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **plugin**: Fix plugin can't get settings from lobe-chat, closes [#488](https://github.com/lobehub/lobe-chat/issues/488) ([1555140](https://github.com/lobehub/lobe-chat/commit/1555140)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.102.3](https://github.com/lobehub/lobe-chat/compare/v0.102.2...v0.102.3) + +Released on **2023-11-20** + +#### 🐛 Bug Fixes + +- **misc**: Fix plugin not work correct when adding agent from market. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix plugin not work correct when adding agent from market, closes [#394](https://github.com/lobehub/lobe-chat/issues/394) ([7c99816](https://github.com/lobehub/lobe-chat/commit/7c99816)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.102.2](https://github.com/lobehub/lobe-chat/compare/v0.102.1...v0.102.2) + +Released on **2023-11-20** + +#### 🐛 Bug Fixes + +- **misc**: Fix model tag missing. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix model tag missing, closes [#481](https://github.com/lobehub/lobe-chat/issues/481) ([8c96cf0](https://github.com/lobehub/lobe-chat/commit/8c96cf0)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.102.1](https://github.com/lobehub/lobe-chat/compare/v0.102.0...v0.102.1) + +Released on **2023-11-19** + +#### 🐛 Bug Fixes + +- **misc**: Fix image upload list missing. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix image upload list missing ([6bbac34](https://github.com/lobehub/lobe-chat/commit/6bbac34)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.102.0](https://github.com/lobehub/lobe-chat/compare/v0.101.7...v0.102.0) + +Released on **2023-11-19** + +#### ✨ Features + +- **misc**: Support TTS & STT. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Support TTS & STT, closes [#443](https://github.com/lobehub/lobe-chat/issues/443) ([4fa2ef4](https://github.com/lobehub/lobe-chat/commit/4fa2ef4)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.101.7](https://github.com/lobehub/lobe-chat/compare/v0.101.6...v0.101.7) + +Released on **2023-11-18** + +#### 🐛 Bug Fixes + +- **misc**: Agent details sidebar and market page height overflow. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Agent details sidebar and market page height overflow ([71a54cc](https://github.com/lobehub/lobe-chat/commit/71a54cc)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.101.6](https://github.com/lobehub/lobe-chat/compare/v0.101.5...v0.101.6) + +Released on **2023-11-17** + +#### 💄 Styles + +- **misc**: Add config to renderErrorMessages, Use new Alert ui. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Add config to renderErrorMessages ([75b6b40](https://github.com/lobehub/lobe-chat/commit/75b6b40)) +- **misc**: Use new Alert ui ([cf845a7](https://github.com/lobehub/lobe-chat/commit/cf845a7)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.101.5](https://github.com/lobehub/lobe-chat/compare/v0.101.4...v0.101.5) + +Released on **2023-11-17** + +#### 🐛 Bug Fixes + +- **misc**: Improve openai error info. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Improve openai error info, closes [#469](https://github.com/lobehub/lobe-chat/issues/469) ([5523b64](https://github.com/lobehub/lobe-chat/commit/5523b64)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.101.4](https://github.com/lobehub/lobe-chat/compare/v0.101.3...v0.101.4) + +Released on **2023-11-14** + +#### 🐛 Bug Fixes + +- **misc**: Fix the plugin array merge error when fork agent from market. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix the plugin array merge error when fork agent from market, closes [#459](https://github.com/lobehub/lobe-chat/issues/459) ([fc29b33](https://github.com/lobehub/lobe-chat/commit/fc29b33)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.101.3](https://github.com/lobehub/lobe-chat/compare/v0.101.2...v0.101.3) + +Released on **2023-11-14** + +#### 💄 Styles + +- **misc**: Improve password ui to make it more clear. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Improve password ui to make it more clear, closes [#458](https://github.com/lobehub/lobe-chat/issues/458) ([e3d2a8e](https://github.com/lobehub/lobe-chat/commit/e3d2a8e)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.101.2](https://github.com/lobehub/lobe-chat/compare/v0.101.1...v0.101.2) + +Released on **2023-11-14** + +#### 💄 Styles + +- **misc**: upload image to vision model adapting to mobile device. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: upload image to vision model adapting to mobile device, closes [#457](https://github.com/lobehub/lobe-chat/issues/457) ([9c4f4ee](https://github.com/lobehub/lobe-chat/commit/9c4f4ee)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.101.1](https://github.com/lobehub/lobe-chat/compare/v0.101.0...v0.101.1) + +Released on **2023-11-14** + +#### 🐛 Bug Fixes + +- **misc**: Fix market search (fix. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix market search (fix, closes [#437](https://github.com/lobehub/lobe-chat/issues/437) ([178b742](https://github.com/lobehub/lobe-chat/commit/178b742)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.101.0](https://github.com/lobehub/lobe-chat/compare/v0.100.5...v0.101.0) + +Released on **2023-11-14** + +#### ✨ Features + +- **misc**: Support upload images to chat with gpt4-vision model. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Support upload images to chat with gpt4-vision model, closes [#440](https://github.com/lobehub/lobe-chat/issues/440) ([858d047](https://github.com/lobehub/lobe-chat/commit/858d047)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.100.5](https://github.com/lobehub/lobe-chat/compare/v0.100.4...v0.100.5) + +Released on **2023-11-11** + +#### ♻ Code Refactoring + +- **misc**: Refactor the input area to suit the files upload feature. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor the input area to suit the files upload feature, closes [#442](https://github.com/lobehub/lobe-chat/issues/442) ([57a61fd](https://github.com/lobehub/lobe-chat/commit/57a61fd)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.100.4](https://github.com/lobehub/lobe-chat/compare/v0.100.3...v0.100.4) + +Released on **2023-11-11** + +#### 🐛 Bug Fixes + +- **misc**: Hotkey disabled in form tags. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Hotkey disabled in form tags ([165888f](https://github.com/lobehub/lobe-chat/commit/165888f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.100.3](https://github.com/lobehub/lobe-chat/compare/v0.100.2...v0.100.3) + +Released on **2023-11-09** + +#### 🐛 Bug Fixes + +- **misc**: Fix market error. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix market error ([3d7550c](https://github.com/lobehub/lobe-chat/commit/3d7550c)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.100.2](https://github.com/lobehub/lobe-chat/compare/v0.100.1...v0.100.2) + +Released on **2023-11-09** + +#### 🐛 Bug Fixes + +- **misc**: Upgrade viewport for nextjs 14. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Upgrade viewport for nextjs 14, closes [#436](https://github.com/lobehub/lobe-chat/issues/436) ([57d3d07](https://github.com/lobehub/lobe-chat/commit/57d3d07)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.100.1](https://github.com/lobehub/lobe-chat/compare/v0.100.0...v0.100.1) + +Released on **2023-11-09** + +
+ +
+Improvements and Fixes + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.100.0](https://github.com/lobehub/lobe-chat/compare/v0.99.1...v0.100.0) + +Released on **2023-11-09** + +#### ✨ Features + +- **hotkeys**: Compatible with SSR, display platform specific key. +- **misc**: Platform check utils. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **hotkeys**: Compatible with SSR ([99fa4f8](https://github.com/lobehub/lobe-chat/commit/99fa4f8)) +- **hotkeys**: Display platform specific key ([ee332a4](https://github.com/lobehub/lobe-chat/commit/ee332a4)) +- **misc**: Platform check utils ([08a3cb9](https://github.com/lobehub/lobe-chat/commit/08a3cb9)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.99.1](https://github.com/lobehub/lobe-chat/compare/v0.99.0...v0.99.1) + +Released on **2023-11-08** + +#### 💄 Styles + +- **misc**: Add max height to model menu in chat input area. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Add max height to model menu in chat input area, closes [#430](https://github.com/lobehub/lobe-chat/issues/430) ([c9a86f3](https://github.com/lobehub/lobe-chat/commit/c9a86f3)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.99.0](https://github.com/lobehub/lobe-chat/compare/v0.98.3...v0.99.0) + +Released on **2023-11-08** + +#### ✨ Features + +- **misc**: Add Environment Variable for custom model name when deploying. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add Environment Variable for custom model name when deploying, closes [#429](https://github.com/lobehub/lobe-chat/issues/429) ([15f9fa2](https://github.com/lobehub/lobe-chat/commit/15f9fa2)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.98.3](https://github.com/lobehub/lobe-chat/compare/v0.98.2...v0.98.3) + +Released on **2023-11-07** + +#### 🐛 Bug Fixes + +- **misc**: Fix redirect to welcome problem when there are topics in inbox. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix redirect to welcome problem when there are topics in inbox, closes [#422](https://github.com/lobehub/lobe-chat/issues/422) ([3d2588a](https://github.com/lobehub/lobe-chat/commit/3d2588a)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.98.2](https://github.com/lobehub/lobe-chat/compare/v0.98.1...v0.98.2) + +Released on **2023-11-07** + +#### ♻ Code Refactoring + +- **misc**: Refactor antd locale file to useSWR. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor antd locale file to useSWR ([2e1cd7c](https://github.com/lobehub/lobe-chat/commit/2e1cd7c)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.98.1](https://github.com/lobehub/lobe-chat/compare/v0.98.0...v0.98.1) + +Released on **2023-11-07** + +#### 💄 Styles + +- **misc**: Update welcome assetes. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Update welcome assetes ([8840554](https://github.com/lobehub/lobe-chat/commit/8840554)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.98.0](https://github.com/lobehub/lobe-chat/compare/v0.97.1...v0.98.0) + +Released on **2023-11-07** + +#### ✨ Features + +- **misc**: Support latest openai model. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Support latest openai model, closes [#417](https://github.com/lobehub/lobe-chat/issues/417) ([46386dc](https://github.com/lobehub/lobe-chat/commit/46386dc)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.97.1](https://github.com/lobehub/lobe-chat/compare/v0.97.0...v0.97.1) + +Released on **2023-11-06** + +#### 🐛 Bug Fixes + +- **misc**: Use pnpm to fix docker release. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Use pnpm to fix docker release ([886cc3b](https://github.com/lobehub/lobe-chat/commit/886cc3b)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.97.0](https://github.com/lobehub/lobe-chat/compare/v0.96.9...v0.97.0) + +Released on **2023-11-05** + +#### ✨ Features + +- **misc**: Add open new topic when open a topic. + +#### 🐛 Bug Fixes + +- **misc**: Fix toggle back to default topic when clearing topic. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add open new topic when open a topic ([4df6384](https://github.com/lobehub/lobe-chat/commit/4df6384)) + +#### What's fixed + +- **misc**: Fix toggle back to default topic when clearing topic ([6fe0a5c](https://github.com/lobehub/lobe-chat/commit/6fe0a5c)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.96.9](https://github.com/lobehub/lobe-chat/compare/v0.96.8...v0.96.9) + +Released on **2023-11-04** + +#### 💄 Styles + +- **misc**: Update topic list header. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Update topic list header ([ce932d7](https://github.com/lobehub/lobe-chat/commit/ce932d7)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.96.8](https://github.com/lobehub/lobe-chat/compare/v0.96.7...v0.96.8) + +Released on **2023-10-31** + +#### 🐛 Bug Fixes + +- **misc**: Fix a bug that weather plugin is not work correctly, template remove sharp deps. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix a bug that weather plugin is not work correctly ([dbb65ff](https://github.com/lobehub/lobe-chat/commit/dbb65ff)) +- **misc**: Template remove sharp deps ([380723d](https://github.com/lobehub/lobe-chat/commit/380723d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.96.7](https://github.com/lobehub/lobe-chat/compare/v0.96.6...v0.96.7) + +Released on **2023-10-31** + +#### 🐛 Bug Fixes + +- **misc**: Fix a bug when click inbox not switch back to chat page. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix a bug when click inbox not switch back to chat page ([31f6d29](https://github.com/lobehub/lobe-chat/commit/31f6d29)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.96.6](https://github.com/lobehub/lobe-chat/compare/v0.96.5...v0.96.6) + +Released on **2023-10-30** + +#### 🐛 Bug Fixes + +- **misc**: Improve plausible analytics ENV. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Improve plausible analytics ENV ([aa851d4](https://github.com/lobehub/lobe-chat/commit/aa851d4)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.96.5](https://github.com/lobehub/lobe-chat/compare/v0.96.4...v0.96.5) + +Released on **2023-10-29** + +#### 🐛 Bug Fixes + +- **misc**: Fix docker image optimization error log. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix docker image optimization error log ([730aec1](https://github.com/lobehub/lobe-chat/commit/730aec1)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.96.4](https://github.com/lobehub/lobe-chat/compare/v0.96.3...v0.96.4) + +Released on **2023-10-29** + +#### 🐛 Bug Fixes + +- **misc**: Fix agents market locale fallback to english. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix agents market locale fallback to english, closes [#382](https://github.com/lobehub/lobe-chat/issues/382) ([3814523](https://github.com/lobehub/lobe-chat/commit/3814523)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.96.3](https://github.com/lobehub/lobe-chat/compare/v0.96.2...v0.96.3) + +Released on **2023-10-28** + +#### 💄 Styles + +- **misc**: Fix SessionList on mobile. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Fix SessionList on mobile ([e7e7b80](https://github.com/lobehub/lobe-chat/commit/e7e7b80)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.96.2](https://github.com/lobehub/lobe-chat/compare/v0.96.1...v0.96.2) + +Released on **2023-10-28** + +#### 💄 Styles + +- **misc**: Fix some styles and make updates to various files. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Fix some styles and make updates to various files ([44a5f0a](https://github.com/lobehub/lobe-chat/commit/44a5f0a)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.96.1](https://github.com/lobehub/lobe-chat/compare/v0.96.0...v0.96.1) + +Released on **2023-10-28** + +#### 💄 Styles + +- **misc**: Add guide to market page. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Add guide to market page ([8a794f9](https://github.com/lobehub/lobe-chat/commit/8a794f9)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.96.0](https://github.com/lobehub/lobe-chat/compare/v0.95.1...v0.96.0) + +Released on **2023-10-27** + +#### ✨ Features + +- **misc**: Improve pin mode about session group. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Improve pin mode about session group, closes [#369](https://github.com/lobehub/lobe-chat/issues/369) ([75c5883](https://github.com/lobehub/lobe-chat/commit/75c5883)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.95.1](https://github.com/lobehub/lobe-chat/compare/v0.95.0...v0.95.1) + +Released on **2023-10-25** + +#### 💄 Styles + +- **misc**: Improve plugin message ui. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Improve plugin message ui ([6edd25b](https://github.com/lobehub/lobe-chat/commit/6edd25b)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.95.0](https://github.com/lobehub/lobe-chat/compare/v0.94.5...v0.95.0) + +Released on **2023-10-24** + +#### ♻ Code Refactoring + +- **misc**: 优化 plugin 文件夹命名以支持 standalone 类型的插件. + +#### ✨ Features + +- **misc**: Support function call at message end, support plugin settings modal, support plugin state and settings. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 优化 plugin 文件夹命名以支持 standalone 类型的插件 ([98860a8](https://github.com/lobehub/lobe-chat/commit/98860a8)) + +#### What's improved + +- **misc**: Support function call at message end, closes [#357](https://github.com/lobehub/lobe-chat/issues/357) ([e195fdb](https://github.com/lobehub/lobe-chat/commit/e195fdb)) +- **misc**: Support plugin settings modal ([f47b6fa](https://github.com/lobehub/lobe-chat/commit/f47b6fa)) +- **misc**: Support plugin state and settings ([10829a4](https://github.com/lobehub/lobe-chat/commit/10829a4)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.94.5](https://github.com/lobehub/lobe-chat/compare/v0.94.4...v0.94.5) + +Released on **2023-10-22** + +#### 🐛 Bug Fixes + +- **misc**: Fallback agent market index to en when not find correct locale. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fallback agent market index to en when not find correct locale, closes [#355](https://github.com/lobehub/lobe-chat/issues/355) ([7a45ab4](https://github.com/lobehub/lobe-chat/commit/7a45ab4)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.94.4](https://github.com/lobehub/lobe-chat/compare/v0.94.3...v0.94.4) + +Released on **2023-10-21** + +#### 🐛 Bug Fixes + +- **misc**: Fix break cn chars in stream mode. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix break cn chars in stream mode, closes [#347](https://github.com/lobehub/lobe-chat/issues/347) ([f831447](https://github.com/lobehub/lobe-chat/commit/f831447)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.94.3](https://github.com/lobehub/lobe-chat/compare/v0.94.2...v0.94.3) + +Released on **2023-10-19** + +#### 🐛 Bug Fixes + +- **misc**: Fix agent share format. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix agent share format ([56ebc0b](https://github.com/lobehub/lobe-chat/commit/56ebc0b)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.94.2](https://github.com/lobehub/lobe-chat/compare/v0.94.1...v0.94.2) + +Released on **2023-10-19** + +#### 🐛 Bug Fixes + +- **misc**: Fix agent market with other locales. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix agent market with other locales ([2414d34](https://github.com/lobehub/lobe-chat/commit/2414d34)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.94.1](https://github.com/lobehub/lobe-chat/compare/v0.94.0...v0.94.1) + +Released on **2023-10-19** + +#### 💄 Styles + +- **misc**: Update ShareAgentButton. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Update ShareAgentButton ([c396bd7](https://github.com/lobehub/lobe-chat/commit/c396bd7)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.94.0](https://github.com/lobehub/lobe-chat/compare/v0.93.0...v0.94.0) + +Released on **2023-10-18** + +#### ✨ Features + +- **misc**: Add agent share. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add agent share ([953d7c7](https://github.com/lobehub/lobe-chat/commit/953d7c7)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.93.0](https://github.com/lobehub/lobe-chat/compare/v0.92.0...v0.93.0) + +Released on **2023-10-18** + +#### ♻ Code Refactoring + +- **misc**: Refactor chain. + +#### ✨ Features + +- **misc**: Support multi-language translate. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor chain ([49c4863](https://github.com/lobehub/lobe-chat/commit/49c4863)) + +#### What's improved + +- **misc**: Support multi-language translate ([548bc5d](https://github.com/lobehub/lobe-chat/commit/548bc5d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.92.0](https://github.com/lobehub/lobe-chat/compare/v0.91.0...v0.92.0) + +Released on **2023-10-18** + +#### ✨ Features + +- **misc**: Support translate message to current language. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Support translate message to current language, closes [#340](https://github.com/lobehub/lobe-chat/issues/340) ([cf15f1e](https://github.com/lobehub/lobe-chat/commit/cf15f1e)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.91.0](https://github.com/lobehub/lobe-chat/compare/v0.90.3...v0.91.0) + +Released on **2023-10-17** + +#### ✨ Features + +- **misc**: Add hotkeys. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add hotkeys, closes [#286](https://github.com/lobehub/lobe-chat/issues/286) ([041054d](https://github.com/lobehub/lobe-chat/commit/041054d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.90.3](https://github.com/lobehub/lobe-chat/compare/v0.90.2...v0.90.3) + +Released on **2023-10-17** + +#### 🐛 Bug Fixes + +- **misc**: Fix ActionBar props and regenerate btn with error message. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix ActionBar props and regenerate btn with error message, closes [#337](https://github.com/lobehub/lobe-chat/issues/337) ([246e8fd](https://github.com/lobehub/lobe-chat/commit/246e8fd)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.90.2](https://github.com/lobehub/lobe-chat/compare/v0.90.1...v0.90.2) + +Released on **2023-10-17** + +#### ♻ Code Refactoring + +- **misc**: Refactor OpenAIStreamPayload with chat name. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor OpenAIStreamPayload with chat name ([a799530](https://github.com/lobehub/lobe-chat/commit/a799530)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.90.1](https://github.com/lobehub/lobe-chat/compare/v0.90.0...v0.90.1) + +Released on **2023-10-17** + +#### 💄 Styles + +- **misc**: Fix lazyload height. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Fix lazyload height ([98efe02](https://github.com/lobehub/lobe-chat/commit/98efe02)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.90.0](https://github.com/lobehub/lobe-chat/compare/v0.89.10...v0.90.0) + +Released on **2023-10-17** + +#### ✨ Features + +- **misc**: Add Lazyload. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add Lazyload ([27d6cb7](https://github.com/lobehub/lobe-chat/commit/27d6cb7)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.89.10](https://github.com/lobehub/lobe-chat/compare/v0.89.9...v0.89.10) + +Released on **2023-10-17** + +#### ♻ Code Refactoring + +- **misc**: Refactor ChatList onActionsClick. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor ChatList onActionsClick ([d06d87e](https://github.com/lobehub/lobe-chat/commit/d06d87e)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.89.9](https://github.com/lobehub/lobe-chat/compare/v0.89.8...v0.89.9) + +Released on **2023-10-17** + +#### 🐛 Bug Fixes + +- **misc**: Fix ChatList FC Render. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix ChatList FC Render ([4b8bdbd](https://github.com/lobehub/lobe-chat/commit/4b8bdbd)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.89.8](https://github.com/lobehub/lobe-chat/compare/v0.89.7...v0.89.8) + +Released on **2023-10-16** + +#### ♻ Code Refactoring + +- **misc**: Refactor ChatList. + +#### 🐛 Bug Fixes + +- **misc**: Fix type. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor ChatList, closes [#147](https://github.com/lobehub/lobe-chat/issues/147) ([aa4216c](https://github.com/lobehub/lobe-chat/commit/aa4216c)) + +#### What's fixed + +- **misc**: Fix type ([1e931d5](https://github.com/lobehub/lobe-chat/commit/1e931d5)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.89.7](https://github.com/lobehub/lobe-chat/compare/v0.89.6...v0.89.7) + +Released on **2023-10-16** + +#### 🐛 Bug Fixes + +- **misc**: Fix setting tab highlight (fix. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix setting tab highlight (fix, closes [#332](https://github.com/lobehub/lobe-chat/issues/332) ([d288f9d](https://github.com/lobehub/lobe-chat/commit/d288f9d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.89.6](https://github.com/lobehub/lobe-chat/compare/v0.89.5...v0.89.6) + +Released on **2023-10-15** + +
+ +
+Improvements and Fixes + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.89.5](https://github.com/lobehub/lobe-chat/compare/v0.89.4...v0.89.5) + +Released on **2023-10-15** + +#### 🐛 Bug Fixes + +- **misc**: Fix fallback to en when the locale is zh, fix reset button not clear plugin settings. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix fallback to en when the locale is zh ([ff2c00e](https://github.com/lobehub/lobe-chat/commit/ff2c00e)) +- **misc**: Fix reset button not clear plugin settings ([aa1e657](https://github.com/lobehub/lobe-chat/commit/aa1e657)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.89.4](https://github.com/lobehub/lobe-chat/compare/v0.89.3...v0.89.4) + +Released on **2023-10-15** + +#### 🐛 Bug Fixes + +- **misc**: Fix qwen, chatglm request failed. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix qwen, chatglm request failed, closes [#318](https://github.com/lobehub/lobe-chat/issues/318) ([a5699e2](https://github.com/lobehub/lobe-chat/commit/a5699e2)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.89.3](https://github.com/lobehub/lobe-chat/compare/v0.89.2...v0.89.3) + +Released on **2023-10-12** + +#### 🐛 Bug Fixes + +- **misc**: Fix plugin error with nginx reverse proxy. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix plugin error with nginx reverse proxy, closes [#315](https://github.com/lobehub/lobe-chat/issues/315) ([3ba3a3b](https://github.com/lobehub/lobe-chat/commit/3ba3a3b)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.89.2](https://github.com/lobehub/lobe-chat/compare/v0.89.1...v0.89.2) + +Released on **2023-10-12** + +#### 💄 Styles + +- **misc**: Modify onClick event in SessionHeader, change title in Loading component,. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Modify onClick event in SessionHeader, change title in Loading component, ([b984f6a](https://github.com/lobehub/lobe-chat/commit/b984f6a)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.89.1](https://github.com/lobehub/lobe-chat/compare/v0.89.0...v0.89.1) + +Released on **2023-10-12** + +#### 🐛 Bug Fixes + +- **misc**: Remove useless dynamic import. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Remove useless dynamic import ([4a9c426](https://github.com/lobehub/lobe-chat/commit/4a9c426)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.89.0](https://github.com/lobehub/lobe-chat/compare/v0.88.0...v0.89.0) + +Released on **2023-10-12** + +#### ✨ Features + +- **agent-card**: Add and modify features for agent card. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **agent-card**: Add and modify features for agent card ([3e3090a](https://github.com/lobehub/lobe-chat/commit/3e3090a)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.88.0](https://github.com/lobehub/lobe-chat/compare/v0.87.0...v0.88.0) + +Released on **2023-10-11** + +#### ✨ Features + +- **misc**: Add mobile responsiveness, create new component, modify properties, make API calls, Dynamically import components using "dynamic" function. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add mobile responsiveness, create new component, modify properties, make API calls ([759c920](https://github.com/lobehub/lobe-chat/commit/759c920)) +- **misc**: Dynamically import components using "dynamic" function ([dd9db22](https://github.com/lobehub/lobe-chat/commit/dd9db22)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.87.0](https://github.com/lobehub/lobe-chat/compare/v0.86.5...v0.87.0) + +Released on **2023-10-11** + +#### ✨ Features + +- **misc**: Support custom model name. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Support custom model name, closes [#305](https://github.com/lobehub/lobe-chat/issues/305) ([84a066a](https://github.com/lobehub/lobe-chat/commit/84a066a)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.86.5](https://github.com/lobehub/lobe-chat/compare/v0.86.4...v0.86.5) + +Released on **2023-10-11** + +#### 🐛 Bug Fixes + +- **misc**: Fix clear session error. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix clear session error, closes [#303](https://github.com/lobehub/lobe-chat/issues/303) ([09512fc](https://github.com/lobehub/lobe-chat/commit/09512fc)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.86.4](https://github.com/lobehub/lobe-chat/compare/v0.86.3...v0.86.4) + +Released on **2023-10-11** + +#### 💄 Styles + +- **misc**: Improve api key form. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Improve api key form ([fa3170d](https://github.com/lobehub/lobe-chat/commit/fa3170d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.86.3](https://github.com/lobehub/lobe-chat/compare/v0.86.2...v0.86.3) + +Released on **2023-10-11** + +#### 🐛 Bug Fixes + +- **misc**: Fix docker image. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix docker image ([14ff80e](https://github.com/lobehub/lobe-chat/commit/14ff80e)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.86.2](https://github.com/lobehub/lobe-chat/compare/v0.86.1...v0.86.2) + +Released on **2023-10-11** + +#### 🐛 Bug Fixes + +- **docker**: Improve config to reduce unnecessary env and change default PORT. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **docker**: Improve config to reduce unnecessary env and change default PORT, closes [#298](https://github.com/lobehub/lobe-chat/issues/298) ([6061318](https://github.com/lobehub/lobe-chat/commit/6061318)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.86.1](https://github.com/lobehub/lobe-chat/compare/v0.86.0...v0.86.1) + +Released on **2023-10-11** + +#### 🐛 Bug Fixes + +- **misc**: Fix docker reverse proxy don't work. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix docker reverse proxy don't work, closes [#294](https://github.com/lobehub/lobe-chat/issues/294) ([a51ba1d](https://github.com/lobehub/lobe-chat/commit/a51ba1d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.86.0](https://github.com/lobehub/lobe-chat/compare/v0.85.3...v0.86.0) + +Released on **2023-10-10** + +#### ✨ Features + +- **misc**: Support docker deploy. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Support docker deploy, closes [#283](https://github.com/lobehub/lobe-chat/issues/283) ([5bbc87c](https://github.com/lobehub/lobe-chat/commit/5bbc87c)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.85.3](https://github.com/lobehub/lobe-chat/compare/v0.85.2...v0.85.3) + +Released on **2023-10-10** + +#### 💄 Styles + +- **misc**: Add new components, modify display properties, and update settings feature, Replace 100vh with 100% to fix mobile scroll problem. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Add new components, modify display properties, and update settings feature ([87a4a46](https://github.com/lobehub/lobe-chat/commit/87a4a46)) +- **misc**: Replace 100vh with 100% to fix mobile scroll problem ([2ef3c94](https://github.com/lobehub/lobe-chat/commit/2ef3c94)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.85.2](https://github.com/lobehub/lobe-chat/compare/v0.85.1...v0.85.2) + +Released on **2023-10-10** + +#### 🐛 Bug Fixes + +- **misc**: Add apikey form when there is no default api key in env. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Add apikey form when there is no default api key in env, closes [#290](https://github.com/lobehub/lobe-chat/issues/290) ([2c907e9](https://github.com/lobehub/lobe-chat/commit/2c907e9)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.85.1](https://github.com/lobehub/lobe-chat/compare/v0.85.0...v0.85.1) + +Released on **2023-10-10** + +#### 🐛 Bug Fixes + +- **misc**: Fix mobile safe area (fix. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix mobile safe area (fix, closes [#211](https://github.com/lobehub/lobe-chat/issues/211) ([68775b8](https://github.com/lobehub/lobe-chat/commit/68775b8)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.85.0](https://github.com/lobehub/lobe-chat/compare/v0.84.0...v0.85.0) + +Released on **2023-10-10** + +#### ✨ Features + +- **misc**: Add ja_JP, ko_KR and update workflow. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add ja_JP, ko_KR and update workflow ([57512a0](https://github.com/lobehub/lobe-chat/commit/57512a0)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.84.0](https://github.com/lobehub/lobe-chat/compare/v0.83.10...v0.84.0) + +Released on **2023-10-10** + +#### ✨ Features + +- **misc**: Support detect new version and upgrade action. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Support detect new version and upgrade action, closes [#282](https://github.com/lobehub/lobe-chat/issues/282) ([5da19b2](https://github.com/lobehub/lobe-chat/commit/5da19b2)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.83.10](https://github.com/lobehub/lobe-chat/compare/v0.83.9...v0.83.10) + +Released on **2023-10-09** + +#### ♻ Code Refactoring + +- **layout**: Refactor layout, Refactor settings layout, Refactor ssc layout. +- **share**: Use modern-screenshot. + +#### 🐛 Bug Fixes + +- **misc**: Fix rsc layout. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **layout**: Refactor layout ([ace21f4](https://github.com/lobehub/lobe-chat/commit/ace21f4)) +- **layout**: Refactor settings layout ([bd48121](https://github.com/lobehub/lobe-chat/commit/bd48121)) +- **layout**: Refactor ssc layout ([26e1c41](https://github.com/lobehub/lobe-chat/commit/26e1c41)) +- **share**: Use modern-screenshot, closes [#256](https://github.com/lobehub/lobe-chat/issues/256) ([b3d7108](https://github.com/lobehub/lobe-chat/commit/b3d7108)) + +#### What's fixed + +- **misc**: Fix rsc layout ([d73f13f](https://github.com/lobehub/lobe-chat/commit/d73f13f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.83.9](https://github.com/lobehub/lobe-chat/compare/v0.83.8...v0.83.9) + +Released on **2023-10-08** + +#### ♻ Code Refactoring + +- **agent-market**: Refactor desktop and mobile to improve mobile performance. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **agent-market**: Refactor desktop and mobile to improve mobile performance, closes [#278](https://github.com/lobehub/lobe-chat/issues/278) ([82b7f60](https://github.com/lobehub/lobe-chat/commit/82b7f60)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.83.8](https://github.com/lobehub/lobe-chat/compare/v0.83.7...v0.83.8) + +Released on **2023-10-07** + +
+ +
+Improvements and Fixes + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.83.7](https://github.com/lobehub/lobe-chat/compare/v0.83.6...v0.83.7) + +Released on **2023-10-07** + +#### 🐛 Bug Fixes + +- **misc**: Fix shuffle, use search url with agent item. + +#### 💄 Styles + +- **misc**: Better tag style, improve loading state. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix shuffle ([d4b9dc3](https://github.com/lobehub/lobe-chat/commit/d4b9dc3)) +- **misc**: Use search url with agent item ([98df623](https://github.com/lobehub/lobe-chat/commit/98df623)) + +#### Styles + +- **misc**: Better tag style ([38e42ea](https://github.com/lobehub/lobe-chat/commit/38e42ea)) +- **misc**: Improve loading state ([f00c868](https://github.com/lobehub/lobe-chat/commit/f00c868)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.83.6](https://github.com/lobehub/lobe-chat/compare/v0.83.5...v0.83.6) + +Released on **2023-10-06** + +#### 💄 Styles + +- **misc**: Update modal style. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Update modal style ([2ab1475](https://github.com/lobehub/lobe-chat/commit/2ab1475)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.83.5](https://github.com/lobehub/lobe-chat/compare/v0.83.4...v0.83.5) + +Released on **2023-10-06** + +#### 🐛 Bug Fixes + +- **misc**: Fix agent market list. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix agent market list, closes [#273](https://github.com/lobehub/lobe-chat/issues/273) ([c020277](https://github.com/lobehub/lobe-chat/commit/c020277)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.83.4](https://github.com/lobehub/lobe-chat/compare/v0.83.3...v0.83.4) + +Released on **2023-10-06** + +#### 🐛 Bug Fixes + +- **misc**: Fix agent settings. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix agent settings, closes [#271](https://github.com/lobehub/lobe-chat/issues/271) ([aac9a70](https://github.com/lobehub/lobe-chat/commit/aac9a70)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.83.3](https://github.com/lobehub/lobe-chat/compare/v0.83.2...v0.83.3) + +Released on **2023-10-06** + +#### ♻ Code Refactoring + +- **misc**: Refactor the settings layout to rsc. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor the settings layout to rsc ([b840f44](https://github.com/lobehub/lobe-chat/commit/b840f44)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.83.2](https://github.com/lobehub/lobe-chat/compare/v0.83.1...v0.83.2) + +Released on **2023-10-06** + +#### 🐛 Bug Fixes + +- **misc**: Fix setCookie method that set cookie with sub-path. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix setCookie method that set cookie with sub-path, closes [#269](https://github.com/lobehub/lobe-chat/issues/269) ([1b859b7](https://github.com/lobehub/lobe-chat/commit/1b859b7)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.83.1](https://github.com/lobehub/lobe-chat/compare/v0.83.0...v0.83.1) + +Released on **2023-10-06** + +#### ♻ Code Refactoring + +- **misc**: Refactor settings page entry. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor settings page entry ([e86aff2](https://github.com/lobehub/lobe-chat/commit/e86aff2)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.83.0](https://github.com/lobehub/lobe-chat/compare/v0.82.9...v0.83.0) + +Released on **2023-10-06** + +#### ✨ Features + +- **misc**: Upgrade locale with SSR. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Upgrade locale with SSR, closes [#268](https://github.com/lobehub/lobe-chat/issues/268) ([2fdea52](https://github.com/lobehub/lobe-chat/commit/2fdea52)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.82.9](https://github.com/lobehub/lobe-chat/compare/v0.82.8...v0.82.9) + +Released on **2023-10-05** + +
+ +
+Improvements and Fixes + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.82.8](https://github.com/lobehub/lobe-chat/compare/v0.82.7...v0.82.8) + +Released on **2023-09-30** + +#### ♻ Code Refactoring + +- **misc**: Refactor / route to reduce page js size. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor / route to reduce page js size ([79f0347](https://github.com/lobehub/lobe-chat/commit/79f0347)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.82.7](https://github.com/lobehub/lobe-chat/compare/v0.82.6...v0.82.7) + +Released on **2023-09-30** + +#### ♻ Code Refactoring + +- **misc**: Refactor the api router to app route handlers. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor the api router to app route handlers, closes [#254](https://github.com/lobehub/lobe-chat/issues/254) ([f032112](https://github.com/lobehub/lobe-chat/commit/f032112)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.82.6](https://github.com/lobehub/lobe-chat/compare/v0.82.5...v0.82.6) + +Released on **2023-09-29** + +#### 🐛 Bug Fixes + +- **misc**: Fix share default config, pin openai to fix type error. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix share default config ([e00d6bf](https://github.com/lobehub/lobe-chat/commit/e00d6bf)) +- **misc**: Pin openai to fix type error ([5af4050](https://github.com/lobehub/lobe-chat/commit/5af4050)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.82.5](https://github.com/lobehub/lobe-chat/compare/v0.82.4...v0.82.5) + +Released on **2023-09-29** + +#### 💄 Styles + +- **misc**: Update theme color and styling of mobile settings page. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Update theme color and styling of mobile settings page ([1acfb71](https://github.com/lobehub/lobe-chat/commit/1acfb71)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.82.4](https://github.com/lobehub/lobe-chat/compare/v0.82.3...v0.82.4) + +Released on **2023-09-29** + +#### 🐛 Bug Fixes + +- **misc**: 修正 localStorage 不存在造成设置页刷新 500 保存的问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正 localStorage 不存在造成设置页刷新 500 保存的问题 ([b894cc8](https://github.com/lobehub/lobe-chat/commit/b894cc8)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.82.3](https://github.com/lobehub/lobe-chat/compare/v0.82.2...v0.82.3) + +Released on **2023-09-29** + +#### 🐛 Bug Fixes + +- **misc**: 修正 access code 校验逻辑,修正 api key 无法正常显示在秘钥输入框,并增加显示关闭按钮,修正移动端输入 access code 默认打开数据键盘的问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正 access code 校验逻辑,closes [#184](https://github.com/lobehub/lobe-chat/issues/184) ([a7301c3](https://github.com/lobehub/lobe-chat/commit/a7301c3)) +- **misc**: 修正 api key 无法正常显示在秘钥输入框,并增加显示关闭按钮,closes [#182](https://github.com/lobehub/lobe-chat/issues/182) ([def1153](https://github.com/lobehub/lobe-chat/commit/def1153)) +- **misc**: 修正移动端输入 access code 默认打开数据键盘的问题 ([7994982](https://github.com/lobehub/lobe-chat/commit/7994982)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.82.2](https://github.com/lobehub/lobe-chat/compare/v0.82.1...v0.82.2) + +Released on **2023-09-28** + +#### ♻ Code Refactoring + +- **misc**: Refactor settings page and mobile ux. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor settings page and mobile ux ([89c5648](https://github.com/lobehub/lobe-chat/commit/89c5648)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.82.1](https://github.com/lobehub/lobe-chat/compare/v0.82.0...v0.82.1) + +Released on **2023-09-27** + +#### 🐛 Bug Fixes + +- **misc**: Fix share screenshot scrollbar. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix share screenshot scrollbar ([244b3b4](https://github.com/lobehub/lobe-chat/commit/244b3b4)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.82.0](https://github.com/lobehub/lobe-chat/compare/v0.81.0...v0.82.0) + +Released on **2023-09-27** + +#### ✨ Features + +- **share**: Add screenshot. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **share**: Add screenshot, closes [#152](https://github.com/lobehub/lobe-chat/issues/152) ([f5d21f4](https://github.com/lobehub/lobe-chat/commit/f5d21f4)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.81.0](https://github.com/lobehub/lobe-chat/compare/v0.80.2...v0.81.0) + +Released on **2023-09-27** + +#### ✨ Features + +- **misc**: Add several analytics sdk. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add several analytics sdk, closes [#244](https://github.com/lobehub/lobe-chat/issues/244) ([65c6c93](https://github.com/lobehub/lobe-chat/commit/65c6c93)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.80.2](https://github.com/lobehub/lobe-chat/compare/v0.80.1...v0.80.2) + +Released on **2023-09-27** + +#### 💄 Styles + +- **misc**: Switch Modal components to @lobehub/ui. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Switch Modal components to @lobehub/ui ([d056015](https://github.com/lobehub/lobe-chat/commit/d056015)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.80.1](https://github.com/lobehub/lobe-chat/compare/v0.80.0...v0.80.1) + +Released on **2023-09-27** + +#### 💄 Styles + +- **misc**: Fix conversation mobile view area. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Fix conversation mobile view area ([6668e11](https://github.com/lobehub/lobe-chat/commit/6668e11)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.80.0](https://github.com/lobehub/lobe-chat/compare/v0.79.8...v0.80.0) + +Released on **2023-09-27** + +#### ✨ Features + +- **misc**: Improve user experience and ensure consistency. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Improve user experience and ensure consistency ([abba584](https://github.com/lobehub/lobe-chat/commit/abba584)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.79.8](https://github.com/lobehub/lobe-chat/compare/v0.79.7...v0.79.8) + +Released on **2023-09-27** + +#### 💄 Styles + +- **misc**: Fix safearea in mobile. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Fix safearea in mobile ([2adfb04](https://github.com/lobehub/lobe-chat/commit/2adfb04)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.79.7](https://github.com/lobehub/lobe-chat/compare/v0.79.6...v0.79.7) + +Released on **2023-09-27** + +#### ♻ Code Refactoring + +- **misc**: Use hook to check PWA env. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Use hook to check PWA env ([b4234db](https://github.com/lobehub/lobe-chat/commit/b4234db)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.79.6](https://github.com/lobehub/lobe-chat/compare/v0.79.5...v0.79.6) + +Released on **2023-09-27** + +#### 💄 Styles + +- **misc**: Optimize PWA style and scroll effect. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Optimize PWA style and scroll effect ([0ae05b8](https://github.com/lobehub/lobe-chat/commit/0ae05b8)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.79.5](https://github.com/lobehub/lobe-chat/compare/v0.79.4...v0.79.5) + +Released on **2023-09-26** + +#### 🐛 Bug Fixes + +- **misc**: Fix URI error. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix URI error ([282a0c8](https://github.com/lobehub/lobe-chat/commit/282a0c8)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.79.4](https://github.com/lobehub/lobe-chat/compare/v0.79.3...v0.79.4) + +Released on **2023-09-26** + +#### ♻ Code Refactoring + +- **misc**: Move dir from page to app and remove .page suffix. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Move dir from page to app and remove .page suffix, closes [#236](https://github.com/lobehub/lobe-chat/issues/236) ([2907303](https://github.com/lobehub/lobe-chat/commit/2907303)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.79.3](https://github.com/lobehub/lobe-chat/compare/v0.79.2...v0.79.3) + +Released on **2023-09-25** + +#### 💄 Styles + +- **meta**: Update meta image. + +
+ +
+Improvements and Fixes + +#### Styles + +- **meta**: Update meta image, closes [#66](https://github.com/lobehub/lobe-chat/issues/66) ([a71ffff](https://github.com/lobehub/lobe-chat/commit/a71ffff)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.79.2](https://github.com/lobehub/lobe-chat/compare/v0.79.1...v0.79.2) + +Released on **2023-09-25** + +#### 💄 Styles + +- **meta**: Fix and add metadata. + +
+ +
+Improvements and Fixes + +#### Styles + +- **meta**: Fix and add metadata ([c872522](https://github.com/lobehub/lobe-chat/commit/c872522)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.79.1](https://github.com/lobehub/lobe-chat/compare/v0.79.0...v0.79.1) + +Released on **2023-09-25** + +#### ♻ Code Refactoring + +- **migration**: Next.js app router. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **migration**: Next.js app router, closes [#220](https://github.com/lobehub/lobe-chat/issues/220) ([bb8085e](https://github.com/lobehub/lobe-chat/commit/bb8085e)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.79.0](https://github.com/lobehub/lobe-chat/compare/v0.78.1...v0.79.0) + +Released on **2023-09-25** + +#### ✨ Features + +- **conversation**: Add history range divider. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **conversation**: Add history range divider, closes [#118](https://github.com/lobehub/lobe-chat/issues/118) ([92d2c96](https://github.com/lobehub/lobe-chat/commit/92d2c96)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.78.1](https://github.com/lobehub/lobe-chat/compare/v0.78.0...v0.78.1) + +Released on **2023-09-21** + +#### 💄 Styles + +- **misc**: Show topic tooltip on left side. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Show topic tooltip on left side ([f686fd2](https://github.com/lobehub/lobe-chat/commit/f686fd2)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.78.0](https://github.com/lobehub/lobe-chat/compare/v0.77.2...v0.78.0) + +Released on **2023-09-17** + +#### ✨ Features + +- **misc**: Auto create topic when chatting. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Auto create topic when chatting, closes [#203](https://github.com/lobehub/lobe-chat/issues/203) ([f952792](https://github.com/lobehub/lobe-chat/commit/f952792)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.77.2](https://github.com/lobehub/lobe-chat/compare/v0.77.1...v0.77.2) + +Released on **2023-09-15** + +#### 🐛 Bug Fixes + +- **settings**: Fix settings route. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **settings**: Fix settings route, closes [#195](https://github.com/lobehub/lobe-chat/issues/195) ([1b7d84e](https://github.com/lobehub/lobe-chat/commit/1b7d84e)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.77.1](https://github.com/lobehub/lobe-chat/compare/v0.77.0...v0.77.1) + +Released on **2023-09-14** + +#### 🐛 Bug Fixes + +- **misc**: Fix lint. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix lint ([9f4f9d7](https://github.com/lobehub/lobe-chat/commit/9f4f9d7)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.77.0](https://github.com/lobehub/lobe-chat/compare/v0.76.2...v0.77.0) + +Released on **2023-09-14** + +#### ✨ Features + +- **misc**: Update localization files and add translations for different languages. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Update localization files and add translations for different languages ([0157f92](https://github.com/lobehub/lobe-chat/commit/0157f92)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.76.2](https://github.com/lobehub/lobe-chat/compare/v0.76.1...v0.76.2) + +Released on **2023-09-11** + +#### 🐛 Bug Fixes + +- **misc**: Fix client config. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix client config ([d62f1b3](https://github.com/lobehub/lobe-chat/commit/d62f1b3)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.76.1](https://github.com/lobehub/lobe-chat/compare/v0.76.0...v0.76.1) + +Released on **2023-09-11** + +#### 🐛 Bug Fixes + +- **misc**: Fix save topic button. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix save topic button ([871905f](https://github.com/lobehub/lobe-chat/commit/871905f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.76.0](https://github.com/lobehub/lobe-chat/compare/v0.75.0...v0.76.0) + +Released on **2023-09-11** + +#### ✨ Features + +- **misc**: Support Azure OpenAI Deploy env. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Support Azure OpenAI Deploy env, closes [#183](https://github.com/lobehub/lobe-chat/issues/183) ([bda6732](https://github.com/lobehub/lobe-chat/commit/bda6732)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.75.0](https://github.com/lobehub/lobe-chat/compare/v0.74.0...v0.75.0) + +Released on **2023-09-11** + +#### ♻ Code Refactoring + +- **misc**: Fefactor index url fetch. + +#### ✨ Features + +- **market**: Add prompt token count. +- **misc**: Add agents market and improve UI components, Add and refactor components for chat input feature, Add functions for generating and analyzing JSON files, generating resource files and table of contents, and formatting console output, Add new settings for Azure OpenAI and OpenAI in locales files, Add new string, create AgentModal component, implement GridCardItem and Loading components, import AgentModal, Add SideBar component, new actions, and update market store state and selectors, Add translations and new setting to "setting.json", Improve functionality and user interface of market page, Modify market features components and update CSS styles, support add agent to chat. + +#### 🐛 Bug Fixes + +- **misc**: Fix fetcher, Fix market sidebar scroll and add i18n. + +#### 💄 Styles + +- **misc**: Update loading style and compatible with unknown agent identifier. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Fefactor index url fetch ([257584b](https://github.com/lobehub/lobe-chat/commit/257584b)) + +#### What's improved + +- **market**: Add prompt token count ([16221a7](https://github.com/lobehub/lobe-chat/commit/16221a7)) +- **misc**: Add agents market and improve UI components ([116c136](https://github.com/lobehub/lobe-chat/commit/116c136)) +- **misc**: Add and refactor components for chat input feature ([f1ac9fe](https://github.com/lobehub/lobe-chat/commit/f1ac9fe)) +- **misc**: Add functions for generating and analyzing JSON files, generating resource files and table of contents, and formatting console output ([d7c2e74](https://github.com/lobehub/lobe-chat/commit/d7c2e74)) +- **misc**: Add new settings for Azure OpenAI and OpenAI in locales files ([e9e25b5](https://github.com/lobehub/lobe-chat/commit/e9e25b5)) +- **misc**: Add new string, create AgentModal component, implement GridCardItem and Loading components, import AgentModal ([2a0e59f](https://github.com/lobehub/lobe-chat/commit/2a0e59f)) +- **misc**: Add SideBar component, new actions, and update market store state and selectors ([8f6cfda](https://github.com/lobehub/lobe-chat/commit/8f6cfda)) +- **misc**: Add translations and new setting to "setting.json" ([aca3822](https://github.com/lobehub/lobe-chat/commit/aca3822)) +- **misc**: Improve functionality and user interface of market page ([1d465d6](https://github.com/lobehub/lobe-chat/commit/1d465d6)) +- **misc**: Modify market features components and update CSS styles ([97e4179](https://github.com/lobehub/lobe-chat/commit/97e4179)) +- **misc**: Support add agent to chat ([3b930c4](https://github.com/lobehub/lobe-chat/commit/3b930c4)) + +#### What's fixed + +- **misc**: Fix fetcher ([171b2da](https://github.com/lobehub/lobe-chat/commit/171b2da)) +- **misc**: Fix market sidebar scroll and add i18n ([9c897d2](https://github.com/lobehub/lobe-chat/commit/9c897d2)) + +#### Styles + +- **misc**: Update loading style and compatible with unknown agent identifier ([2e2231d](https://github.com/lobehub/lobe-chat/commit/2e2231d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.74.0](https://github.com/lobehub/lobe-chat/compare/v0.73.0...v0.74.0) + +Released on **2023-09-11** + +#### ✨ Features + +- **misc**: Add russian locally, Update Russian and English locally (LLM tab). + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add russian locally ([7b67c9f](https://github.com/lobehub/lobe-chat/commit/7b67c9f)) +- **misc**: Update Russian and English locally (LLM tab) ([3b23e70](https://github.com/lobehub/lobe-chat/commit/3b23e70)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.73.0](https://github.com/lobehub/lobe-chat/compare/v0.72.4...v0.73.0) + +Released on **2023-09-10** + +#### ✨ Features + +- **misc**: Support Azure OpenAI. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Support Azure OpenAI, closes [#177](https://github.com/lobehub/lobe-chat/issues/177) ([f0c9532](https://github.com/lobehub/lobe-chat/commit/f0c9532)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.72.4](https://github.com/lobehub/lobe-chat/compare/v0.72.3...v0.72.4) + +Released on **2023-09-10** + +#### 🐛 Bug Fixes + +- **misc**: Use en-US when no suit lang with plugin index. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Use en-US when no suit lang with plugin index ([4e9668d](https://github.com/lobehub/lobe-chat/commit/4e9668d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.72.3](https://github.com/lobehub/lobe-chat/compare/v0.72.2...v0.72.3) + +Released on **2023-09-09** + +#### 🐛 Bug Fixes + +- **misc**: Fix sessionList double click on mobile. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix sessionList double click on mobile, closes [#169](https://github.com/lobehub/lobe-chat/issues/169) ([3ea2bce](https://github.com/lobehub/lobe-chat/commit/3ea2bce)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.72.2](https://github.com/lobehub/lobe-chat/compare/v0.72.1...v0.72.2) + +Released on **2023-09-09** + +#### 🐛 Bug Fixes + +- **misc**: Fix mobile switch when session selected. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix mobile switch when session selected, closes [#167](https://github.com/lobehub/lobe-chat/issues/167) ([40d8a11](https://github.com/lobehub/lobe-chat/commit/40d8a11)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.72.1](https://github.com/lobehub/lobe-chat/compare/v0.72.0...v0.72.1) + +Released on **2023-09-09** + +#### 🐛 Bug Fixes + +- **misc**: 修正异步水合造成的初始状态不稳定的问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正异步水合造成的初始状态不稳定的问题 ([2208f8a](https://github.com/lobehub/lobe-chat/commit/2208f8a)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.72.0](https://github.com/lobehub/lobe-chat/compare/v0.71.1...v0.72.0) + +Released on **2023-09-09** + +#### ✨ Features + +- **misc**: Add plugin market Setting Modal, 支持快速刷新与预览 manifest, 适配插件 i18n 方案. + +#### 🐛 Bug Fixes + +- **misc**: 修正删除插件时错误开启的问题. + +#### 💄 Styles + +- **misc**: 优化 manifest 预览的尺寸. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add plugin market Setting Modal ([a0603a9](https://github.com/lobehub/lobe-chat/commit/a0603a9)) +- **misc**: 支持快速刷新与预览 manifest, closes [#150](https://github.com/lobehub/lobe-chat/issues/150) ([5bd2eb0](https://github.com/lobehub/lobe-chat/commit/5bd2eb0)) +- **misc**: 适配插件 i18n 方案 ([8709ab3](https://github.com/lobehub/lobe-chat/commit/8709ab3)) + +#### What's fixed + +- **misc**: 修正删除插件时错误开启的问题 ([0e35c18](https://github.com/lobehub/lobe-chat/commit/0e35c18)) + +#### Styles + +- **misc**: 优化 manifest 预览的尺寸 ([27f8d6d](https://github.com/lobehub/lobe-chat/commit/27f8d6d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.71.1](https://github.com/lobehub/lobe-chat/compare/v0.71.0...v0.71.1) + +Released on **2023-09-09** + +#### 🐛 Bug Fixes + +- **misc**: Fix mobile route. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix mobile route, closes [#165](https://github.com/lobehub/lobe-chat/issues/165) ([d5e03b6](https://github.com/lobehub/lobe-chat/commit/d5e03b6)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.71.0](https://github.com/lobehub/lobe-chat/compare/v0.70.4...v0.71.0) + +Released on **2023-09-09** + +#### ✨ Features + +- **misc**: Migrate localStorage to indexedDB. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Migrate localStorage to indexedDB, closes [#160](https://github.com/lobehub/lobe-chat/issues/160) ([7f96deb](https://github.com/lobehub/lobe-chat/commit/7f96deb)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.70.4](https://github.com/lobehub/lobe-chat/compare/v0.70.3...v0.70.4) + +Released on **2023-09-09** + +#### 🐛 Bug Fixes + +- **misc**: Fix route. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix route ([2d1e8d6](https://github.com/lobehub/lobe-chat/commit/2d1e8d6)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.70.3](https://github.com/lobehub/lobe-chat/compare/v0.70.2...v0.70.3) + +Released on **2023-09-09** + +#### 💄 Styles + +- **misc**: Better mobile style. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Better mobile style ([776c407](https://github.com/lobehub/lobe-chat/commit/776c407)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.70.2](https://github.com/lobehub/lobe-chat/compare/v0.70.1...v0.70.2) + +Released on **2023-09-08** + +#### 🐛 Bug Fixes + +- **misc**: 修正移动端路由问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正移动端路由问题 ([ae3d2f4](https://github.com/lobehub/lobe-chat/commit/ae3d2f4)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.70.1](https://github.com/lobehub/lobe-chat/compare/v0.70.0...v0.70.1) + +Released on **2023-09-08** + +#### ♻ Code Refactoring + +- **misc**: Refactor settingsSelectors to globalSelectors. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor settingsSelectors to globalSelectors ([38917e8](https://github.com/lobehub/lobe-chat/commit/38917e8)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.70.0](https://github.com/lobehub/lobe-chat/compare/v0.69.1...v0.70.0) + +Released on **2023-09-08** + +#### ✨ Features + +- **misc**: Refactor to url state. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Refactor to url state, closes [#157](https://github.com/lobehub/lobe-chat/issues/157) ([2efac2b](https://github.com/lobehub/lobe-chat/commit/2efac2b)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.69.1](https://github.com/lobehub/lobe-chat/compare/v0.69.0...v0.69.1) + +Released on **2023-09-06** + +#### ♻ Code Refactoring + +- **misc**: Migrate openai-edge to openai. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Migrate openai-edge to openai, closes [#145](https://github.com/lobehub/lobe-chat/issues/145) ([75ee574](https://github.com/lobehub/lobe-chat/commit/75ee574)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.69.0](https://github.com/lobehub/lobe-chat/compare/v0.68.1...v0.69.0) + +Released on **2023-09-06** + +#### ✨ Features + +- **misc**: Add new import statement for "Flexbox" component in "Empty" component. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add new import statement for "Flexbox" component in "Empty" component ([68db626](https://github.com/lobehub/lobe-chat/commit/68db626)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.68.1](https://github.com/lobehub/lobe-chat/compare/v0.68.0...v0.68.1) + +Released on **2023-09-03** + +#### 🐛 Bug Fixes + +- **misc**: 修正数组合并逻辑,修正被移除插件无法看到的问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正数组合并逻辑 ([e36e621](https://github.com/lobehub/lobe-chat/commit/e36e621)) +- **misc**: 修正被移除插件无法看到的问题 ([c17eb56](https://github.com/lobehub/lobe-chat/commit/c17eb56)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.68.0](https://github.com/lobehub/lobe-chat/compare/v0.67.0...v0.68.0) + +Released on **2023-09-03** + +#### ✨ Features + +- **misc**: Plugin default use iframe render. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Plugin default use iframe render, closes [#141](https://github.com/lobehub/lobe-chat/issues/141) ([35a3a16](https://github.com/lobehub/lobe-chat/commit/35a3a16)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.67.0](https://github.com/lobehub/lobe-chat/compare/v0.66.0...v0.67.0) + +Released on **2023-09-02** + +#### ♻ Code Refactoring + +- **plugin**: 重构 plugin Store 组织结构,便于开发与迭代维护. + +#### ✨ Features + +- **plugin-dev**: 优化 manifest 报错原因提示,并支持 id 从 manifest 自动获取. + +#### 🐛 Bug Fixes + +- **plugin-dev**: 修正编辑模式下预览展示问题和 id 重复校验问题. +- **plugin**: 修正开启插件后会话无效的问题. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **plugin**: 重构 plugin Store 组织结构,便于开发与迭代维护 ([ec527cb](https://github.com/lobehub/lobe-chat/commit/ec527cb)) + +#### What's improved + +- **plugin-dev**: 优化 manifest 报错原因提示,并支持 id 从 manifest 自动获取 ([7f0787d](https://github.com/lobehub/lobe-chat/commit/7f0787d)) + +#### What's fixed + +- **plugin-dev**: 修正编辑模式下预览展示问题和 id 重复校验问题 ([17c39ef](https://github.com/lobehub/lobe-chat/commit/17c39ef)) +- **plugin**: 修正开启插件后会话无效的问题 ([82e3beb](https://github.com/lobehub/lobe-chat/commit/82e3beb)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.66.0](https://github.com/lobehub/lobe-chat/compare/v0.65.1...v0.66.0) + +Released on **2023-09-02** + +#### ✨ Features + +- **misc**: Add russian locally. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add russian locally, closes [#137](https://github.com/lobehub/lobe-chat/issues/137) ([785d50f](https://github.com/lobehub/lobe-chat/commit/785d50f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.65.1](https://github.com/lobehub/lobe-chat/compare/v0.65.0...v0.65.1) + +Released on **2023-09-01** + +#### 🐛 Bug Fixes + +- **misc**: 修正 defaultAgent 无法正常变更的问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正 defaultAgent 无法正常变更的问题 ([788d94b](https://github.com/lobehub/lobe-chat/commit/788d94b)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.65.0](https://github.com/lobehub/lobe-chat/compare/v0.64.1...v0.65.0) + +Released on **2023-08-29** + +#### ✨ Features + +- **misc**: 支持本地插件自定义 gateway. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持本地插件自定义 gateway, closes [#129](https://github.com/lobehub/lobe-chat/issues/129) ([770048a](https://github.com/lobehub/lobe-chat/commit/770048a)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.64.1](https://github.com/lobehub/lobe-chat/compare/v0.64.0...v0.64.1) + +Released on **2023-08-29** + +#### 💄 Styles + +- **misc**: Update i18n. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Update i18n, closes [#128](https://github.com/lobehub/lobe-chat/issues/128) ([3bf1509](https://github.com/lobehub/lobe-chat/commit/3bf1509)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.64.0](https://github.com/lobehub/lobe-chat/compare/v0.63.3...v0.64.0) + +Released on **2023-08-29** + +#### ♻ Code Refactoring + +- **misc**: Remove no need i18n. + +#### ✨ Features + +- **misc**: 增加自定义插件的增删改配置功能,完善自定义插件表单的校验逻辑,支持本地插件侧的请求与错误呈现,新增插件配置 Dev 弹窗,绑定本地插件的增删改逻辑. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Remove no need i18n ([808a86a](https://github.com/lobehub/lobe-chat/commit/808a86a)) + +#### What's improved + +- **misc**: 增加自定义插件的增删改配置功能 ([faba081](https://github.com/lobehub/lobe-chat/commit/faba081)) +- **misc**: 完善自定义插件表单的校验逻辑 ([4e1fd28](https://github.com/lobehub/lobe-chat/commit/4e1fd28)) +- **misc**: 支持本地插件侧的请求与错误呈现 ([7e2b39a](https://github.com/lobehub/lobe-chat/commit/7e2b39a)) +- **misc**: 新增插件配置 Dev 弹窗 ([20269b7](https://github.com/lobehub/lobe-chat/commit/20269b7)) +- **misc**: 绑定本地插件的增删改逻辑 ([902e7ed](https://github.com/lobehub/lobe-chat/commit/902e7ed)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.63.3](https://github.com/lobehub/lobe-chat/compare/v0.63.2...v0.63.3) + +Released on **2023-08-28** + +#### ♻ Code Refactoring + +- **misc**: Refactor with new market url. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor with new market url, closes [#123](https://github.com/lobehub/lobe-chat/issues/123) ([34a88f8](https://github.com/lobehub/lobe-chat/commit/34a88f8)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.63.2](https://github.com/lobehub/lobe-chat/compare/v0.63.1...v0.63.2) + +Released on **2023-08-27** + +#### ♻ Code Refactoring + +- **misc**: Refactor AgentSettings. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor AgentSettings, closes [#121](https://github.com/lobehub/lobe-chat/issues/121) ([1f29199](https://github.com/lobehub/lobe-chat/commit/1f29199)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.63.1](https://github.com/lobehub/lobe-chat/compare/v0.63.0...v0.63.1) + +Released on **2023-08-27** + +#### ♻ Code Refactoring + +- **misc**: Refactor the selectors import. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor the selectors import, closes [#120](https://github.com/lobehub/lobe-chat/issues/120) ([6646502](https://github.com/lobehub/lobe-chat/commit/6646502)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.63.0](https://github.com/lobehub/lobe-chat/compare/v0.62.1...v0.63.0) + +Released on **2023-08-27** + +#### ✨ Features + +- **misc**: support sharing to shareGPT. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: support sharing to shareGPT, closes [#119](https://github.com/lobehub/lobe-chat/issues/119) ([026e9ec](https://github.com/lobehub/lobe-chat/commit/026e9ec)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.62.1](https://github.com/lobehub/lobe-chat/compare/v0.62.0...v0.62.1) + +Released on **2023-08-26** + +#### 🐛 Bug Fixes + +- **misc**: Fix plugin settings error. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix plugin settings error, closes [#117](https://github.com/lobehub/lobe-chat/issues/117) ([064d90e](https://github.com/lobehub/lobe-chat/commit/064d90e)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.62.0](https://github.com/lobehub/lobe-chat/compare/v0.61.0...v0.62.0) + +Released on **2023-08-26** + +#### ✨ Features + +- **misc**: 支持超过 4k 的会话使用 16k 总结标题. + +#### 🐛 Bug Fixes + +- **misc**: Fix plugin settings error. + +#### 💄 Styles + +- **misc**: 优化清理会话的操作路径,优化默认角色的配置. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持超过 4k 的会话使用 16k 总结标题 ([5764cfb](https://github.com/lobehub/lobe-chat/commit/5764cfb)) + +#### What's fixed + +- **misc**: Fix plugin settings error ([008c2e3](https://github.com/lobehub/lobe-chat/commit/008c2e3)) + +#### Styles + +- **misc**: 优化清理会话的操作路径 ([6b7218e](https://github.com/lobehub/lobe-chat/commit/6b7218e)) +- **misc**: 优化默认角色的配置 ([a07d7a8](https://github.com/lobehub/lobe-chat/commit/a07d7a8)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.61.0](https://github.com/lobehub/lobe-chat/compare/v0.60.4...v0.61.0) + +Released on **2023-08-26** + +#### ✨ Features + +- **misc**: 新增自动滚动. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 新增自动滚动,closes [#113](https://github.com/lobehub/lobe-chat/issues/113) ([03fd161](https://github.com/lobehub/lobe-chat/commit/03fd161)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.60.4](https://github.com/lobehub/lobe-chat/compare/v0.60.3...v0.60.4) + +Released on **2023-08-26** + +#### 💄 Styles + +- **misc**: 优化文案. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 优化文案 ([9a1e004](https://github.com/lobehub/lobe-chat/commit/9a1e004)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.60.3](https://github.com/lobehub/lobe-chat/compare/v0.60.2...v0.60.3) + +Released on **2023-08-26** + +#### 🐛 Bug Fixes + +- **misc**: Fix global state merge error. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix global state merge error ([cbc2fc8](https://github.com/lobehub/lobe-chat/commit/cbc2fc8)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.60.2](https://github.com/lobehub/lobe-chat/compare/v0.60.1...v0.60.2) + +Released on **2023-08-26** + +#### 🐛 Bug Fixes + +- **misc**: Fix fetch plugin header error. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix fetch plugin header error ([fa4a0e1](https://github.com/lobehub/lobe-chat/commit/fa4a0e1)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.60.1](https://github.com/lobehub/lobe-chat/compare/v0.60.0...v0.60.1) + +Released on **2023-08-26** + +#### 🐛 Bug Fixes + +- **misc**: Fix settings storage error. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix settings storage error ([57d7eb1](https://github.com/lobehub/lobe-chat/commit/57d7eb1)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.60.0](https://github.com/lobehub/lobe-chat/compare/v0.59.0...v0.60.0) + +Released on **2023-08-26** + +#### ♻ Code Refactoring + +- **misc**: Refactor with new market index url. + +#### ✨ Features + +- **misc**: 支持插件 manifest 加载失败后重试. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor with new market index url ([d2834b7](https://github.com/lobehub/lobe-chat/commit/d2834b7)) + +#### What's improved + +- **misc**: 支持插件 manifest 加载失败后重试 ([f36378e](https://github.com/lobehub/lobe-chat/commit/f36378e)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.59.0](https://github.com/lobehub/lobe-chat/compare/v0.58.0...v0.59.0) + +Released on **2023-08-26** + +#### ✨ Features + +- **misc**: 支持展示插件插件状态,支持插件 i18n 模式展示. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持展示插件插件状态 ([7e916ac](https://github.com/lobehub/lobe-chat/commit/7e916ac)) +- **misc**: 支持插件 i18n 模式展示 ([8614734](https://github.com/lobehub/lobe-chat/commit/8614734)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.58.0](https://github.com/lobehub/lobe-chat/compare/v0.57.0...v0.58.0) + +Released on **2023-08-26** + +#### ✨ Features + +- **misc**: Implement responsive design for mobile devices. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Implement responsive design for mobile devices, closes [#95](https://github.com/lobehub/lobe-chat/issues/95) ([fdb3c93](https://github.com/lobehub/lobe-chat/commit/fdb3c93)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.57.0](https://github.com/lobehub/lobe-chat/compare/v0.56.0...v0.57.0) + +Released on **2023-08-26** + +#### ♻ Code Refactoring + +- **misc**: Refactor to ChatErrorType. + +#### ✨ Features + +- **misc**: 完善插件请求的错误处理,支持修改与记录插件的配置,支持发送插件配置信息,支持渲染 manifest 中的 settings, 支持设置不正确时进行插件的配置,新增插件请求状态的错误处理. + +#### 🐛 Bug Fixes + +- **misc**: 修正缓存旧数据的报错问题. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor to ChatErrorType ([cd1a033](https://github.com/lobehub/lobe-chat/commit/cd1a033)) + +#### What's improved + +- **misc**: 完善插件请求的错误处理 ([0698d89](https://github.com/lobehub/lobe-chat/commit/0698d89)) +- **misc**: 支持修改与记录插件的配置 ([76e8237](https://github.com/lobehub/lobe-chat/commit/76e8237)) +- **misc**: 支持发送插件配置信息 ([2cedc85](https://github.com/lobehub/lobe-chat/commit/2cedc85)) +- **misc**: 支持渲染 manifest 中的 settings ([1185300](https://github.com/lobehub/lobe-chat/commit/1185300)) +- **misc**: 支持设置不正确时进行插件的配置 ([f972481](https://github.com/lobehub/lobe-chat/commit/f972481)) +- **misc**: 新增插件请求状态的错误处理 ([228002a](https://github.com/lobehub/lobe-chat/commit/228002a)) + +#### What's fixed + +- **misc**: 修正缓存旧数据的报错问题 ([5d8008f](https://github.com/lobehub/lobe-chat/commit/5d8008f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.56.0](https://github.com/lobehub/lobe-chat/compare/v0.55.1...v0.56.0) + +Released on **2023-08-24** + +#### ✨ Features + +- **misc**: Use new plugin manifest to support plugin’s multi api. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Use new plugin manifest to support plugin’s multi api, closes [#101](https://github.com/lobehub/lobe-chat/issues/101) ([4534598](https://github.com/lobehub/lobe-chat/commit/4534598)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.55.1](https://github.com/lobehub/lobe-chat/compare/v0.55.0...v0.55.1) + +Released on **2023-08-22** + +#### ♻ Code Refactoring + +- **misc**: Refactor plugin api with @lobehub/chat-plugins-gateway. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor plugin api with @lobehub/chat-plugins-gateway, closes [#100](https://github.com/lobehub/lobe-chat/issues/100) ([b88d0db](https://github.com/lobehub/lobe-chat/commit/b88d0db)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.55.0](https://github.com/lobehub/lobe-chat/compare/v0.54.4...v0.55.0) + +Released on **2023-08-22** + +#### ♻ Code Refactoring + +- **misc**: 将网关实现代码集成进 Chat 本体,抽取插件为独立 store, 重构 openai 接口调用逻辑,将插件 schema 开启关闭逻辑与接口解耦,重构插件列表获取逻辑,进而完全移除 plugins 目录. + +#### ✨ Features + +- **misc**: 初步完成插件市场动态加载全链路,实现插件组件的动态加载. + +#### 🐛 Bug Fixes + +- **misc**: Fix error, 修正无法正常开启插件的问题,修正测试,补充插件 store 的水合逻辑. + +#### 💄 Styles + +- **misc**: 完成插件市场 loading 态样式. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 将网关实现代码集成进 Chat 本体 ([17e8161](https://github.com/lobehub/lobe-chat/commit/17e8161)) +- **misc**: 抽取插件为独立 store ([12b7e7d](https://github.com/lobehub/lobe-chat/commit/12b7e7d)) +- **misc**: 重构 openai 接口调用逻辑,将插件 schema 开启关闭逻辑与接口解耦 ([5aa886e](https://github.com/lobehub/lobe-chat/commit/5aa886e)) +- **misc**: 重构插件列表获取逻辑,进而完全移除 plugins 目录 ([10055e1](https://github.com/lobehub/lobe-chat/commit/10055e1)) + +#### What's improved + +- **misc**: 初步完成插件市场动态加载全链路 ([bc5e40f](https://github.com/lobehub/lobe-chat/commit/bc5e40f)) +- **misc**: 实现插件组件的动态加载 ([04dbab2](https://github.com/lobehub/lobe-chat/commit/04dbab2)) + +#### What's fixed + +- **misc**: Fix error ([fbeec75](https://github.com/lobehub/lobe-chat/commit/fbeec75)) +- **misc**: 修正无法正常开启插件的问题 ([b3e9090](https://github.com/lobehub/lobe-chat/commit/b3e9090)) +- **misc**: 修正测试 ([001de5b](https://github.com/lobehub/lobe-chat/commit/001de5b)) +- **misc**: 补充插件 store 的水合逻辑 ([bfb649b](https://github.com/lobehub/lobe-chat/commit/bfb649b)) + +#### Styles + +- **misc**: 完成插件市场 loading 态样式 ([8009691](https://github.com/lobehub/lobe-chat/commit/8009691)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.54.4](https://github.com/lobehub/lobe-chat/compare/v0.54.3...v0.54.4) + +Released on **2023-08-21** + +#### 🐛 Bug Fixes + +- **misc**: Fix not cannot change setting error. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix not cannot change setting error, closes [#86](https://github.com/lobehub/lobe-chat/issues/86) ([6405c28](https://github.com/lobehub/lobe-chat/commit/6405c28)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.54.3](https://github.com/lobehub/lobe-chat/compare/v0.54.2...v0.54.3) + +Released on **2023-08-21** + +#### ♻ Code Refactoring + +- **misc**: Refactor plugin request. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor plugin request, closes [#89](https://github.com/lobehub/lobe-chat/issues/89) ([23efee3](https://github.com/lobehub/lobe-chat/commit/23efee3)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.54.2](https://github.com/lobehub/lobe-chat/compare/v0.54.1...v0.54.2) + +Released on **2023-08-16** + +#### 💄 Styles + +- **misc**: 修正图片选项的样式问题. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 修正图片选项的样式问题 ([5f576cb](https://github.com/lobehub/lobe-chat/commit/5f576cb)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.54.1](https://github.com/lobehub/lobe-chat/compare/v0.54.0...v0.54.1) + +Released on **2023-08-16** + +#### 🐛 Bug Fixes + +- **misc**: 修正 i18n 失效的问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正 i18n 失效的问题,closes [#80](https://github.com/lobehub/lobe-chat/issues/80) ([b8d957b](https://github.com/lobehub/lobe-chat/commit/b8d957b)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.54.0](https://github.com/lobehub/lobe-chat/compare/v0.53.0...v0.54.0) + +Released on **2023-08-15** + +#### ✨ Features + +- **misc**: Add new features and improve user interface and functionality. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add new features and improve user interface and functionality ([1543bd1](https://github.com/lobehub/lobe-chat/commit/1543bd1)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.53.0](https://github.com/lobehub/lobe-chat/compare/v0.52.1...v0.53.0) + +Released on **2023-08-15** + +#### ✨ Features + +- **sidebar**: Add DraggablePanelContainer and adjust layout and styling. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **sidebar**: Add DraggablePanelContainer and adjust layout and styling ([e8c384f](https://github.com/lobehub/lobe-chat/commit/e8c384f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.52.1](https://github.com/lobehub/lobe-chat/compare/v0.52.0...v0.52.1) + +Released on **2023-08-15** + +#### ♻ Code Refactoring + +- **misc**: Replace cdn. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Replace cdn ([2875400](https://github.com/lobehub/lobe-chat/commit/2875400)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.52.0](https://github.com/lobehub/lobe-chat/compare/v0.51.0...v0.52.0) + +Released on **2023-08-15** + +#### ✨ Features + +- **misc**: Add avatar compress. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add avatar compress ([1325b40](https://github.com/lobehub/lobe-chat/commit/1325b40)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.51.0](https://github.com/lobehub/lobe-chat/compare/v0.50.0...v0.51.0) + +Released on **2023-08-15** + +#### ✨ Features + +- **misc**: Add Footer component and modify Token and index files. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add Footer component and modify Token and index files ([41a3823](https://github.com/lobehub/lobe-chat/commit/41a3823)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.50.0](https://github.com/lobehub/lobe-chat/compare/v0.49.0...v0.50.0) + +Released on **2023-08-15** + +#### ✨ Features + +- **misc**: Update messages, settings, error codes, plugin names, weather data display, and UI. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Update messages, settings, error codes, plugin names, weather data display, and UI ([a41db51](https://github.com/lobehub/lobe-chat/commit/a41db51)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.49.0](https://github.com/lobehub/lobe-chat/compare/v0.48.0...v0.49.0) + +Released on **2023-08-15** + +#### ✨ Features + +- **misc**: Add `BackToBottom` to conversation, Update icons and text in various components. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add `BackToBottom` to conversation ([1433aa9](https://github.com/lobehub/lobe-chat/commit/1433aa9)) +- **misc**: Update icons and text in various components ([0e7a683](https://github.com/lobehub/lobe-chat/commit/0e7a683)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.48.0](https://github.com/lobehub/lobe-chat/compare/v0.47.0...v0.48.0) + +Released on **2023-08-15** + +#### ✨ Features + +- **misc**: Import SiOpenai icon and replace 'Tag' component in chat feature. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Import SiOpenai icon and replace 'Tag' component in chat feature ([98b0352](https://github.com/lobehub/lobe-chat/commit/98b0352)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.47.0](https://github.com/lobehub/lobe-chat/compare/v0.46.1...v0.47.0) + +Released on **2023-08-15** + +#### ✨ Features + +- **misc**: Add and update UI elements and agent configuration. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add and update UI elements and agent configuration ([eb7fbee](https://github.com/lobehub/lobe-chat/commit/eb7fbee)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.46.1](https://github.com/lobehub/lobe-chat/compare/v0.46.0...v0.46.1) + +Released on **2023-08-14** + +#### 💄 Styles + +- **misc**: Fix SystemRole Skeleton padding. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Fix SystemRole Skeleton padding ([ce485a0](https://github.com/lobehub/lobe-chat/commit/ce485a0)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.46.0](https://github.com/lobehub/lobe-chat/compare/v0.45.0...v0.46.0) + +Released on **2023-08-14** + +#### ✨ Features + +- **misc**: Update styling and functionality of AgentPrompt and EditableMessage components, 支持停止生成消息. + +#### 🐛 Bug Fixes + +- **misc**: Remove input highlight. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Update styling and functionality of AgentPrompt and EditableMessage components ([80b521c](https://github.com/lobehub/lobe-chat/commit/80b521c)) +- **misc**: 支持停止生成消息,closes [#78](https://github.com/lobehub/lobe-chat/issues/78) ([9eeca80](https://github.com/lobehub/lobe-chat/commit/9eeca80)) + +#### What's fixed + +- **misc**: Remove input highlight ([ad2001a](https://github.com/lobehub/lobe-chat/commit/ad2001a)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.45.0](https://github.com/lobehub/lobe-chat/compare/v0.44.4...v0.45.0) + +Released on **2023-08-14** + +#### ✨ Features + +- **misc**: 优化每个角色的初始引导. + +#### 💄 Styles + +- **misc**: 优化初始化加载状态,等到会话加载完毕再显示内容. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 优化每个角色的初始引导,closes [#76](https://github.com/lobehub/lobe-chat/issues/76) ([8d78dc5](https://github.com/lobehub/lobe-chat/commit/8d78dc5)) + +#### Styles + +- **misc**: 优化初始化加载状态,等到会话加载完毕再显示内容 ([cf603cb](https://github.com/lobehub/lobe-chat/commit/cf603cb)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.44.4](https://github.com/lobehub/lobe-chat/compare/v0.44.3...v0.44.4) + +Released on **2023-08-13** + +#### 💄 Styles + +- **misc**: 优化 Chat Skeleton 样式,优化 Inbox 样式. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 优化 Chat Skeleton 样式 ([3f83be0](https://github.com/lobehub/lobe-chat/commit/3f83be0)) +- **misc**: 优化 Inbox 样式 ([924c12e](https://github.com/lobehub/lobe-chat/commit/924c12e)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.44.3](https://github.com/lobehub/lobe-chat/compare/v0.44.2...v0.44.3) + +Released on **2023-08-13** + +#### ♻ Code Refactoring + +- **misc**: 重构 organizeChats 方法. + +#### 🐛 Bug Fixes + +- **misc**: 修正 inbox 点击重新生成会报错的问题. + +#### 💄 Styles + +- **misc**: 修正话题列表无法滚动的问题. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 重构 organizeChats 方法 ([799612e](https://github.com/lobehub/lobe-chat/commit/799612e)) + +#### What's fixed + +- **misc**: 修正 inbox 点击重新生成会报错的问题 ([064ef56](https://github.com/lobehub/lobe-chat/commit/064ef56)) + +#### Styles + +- **misc**: 修正话题列表无法滚动的问题 ([26772e7](https://github.com/lobehub/lobe-chat/commit/26772e7)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.44.2](https://github.com/lobehub/lobe-chat/compare/v0.44.1...v0.44.2) + +Released on **2023-08-13** + +#### 🐛 Bug Fixes + +- **misc**: 修正重新生成时切分历史消息的逻辑. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正重新生成时切分历史消息的逻辑,closes [#50](https://github.com/lobehub/lobe-chat/issues/50) ([de5141f](https://github.com/lobehub/lobe-chat/commit/de5141f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.44.1](https://github.com/lobehub/lobe-chat/compare/v0.44.0...v0.44.1) + +Released on **2023-08-12** + +
+ +
+Improvements and Fixes + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.44.0](https://github.com/lobehub/lobe-chat/compare/v0.43.0...v0.44.0) + +Released on **2023-08-12** + +#### ♻ Code Refactoring + +- **misc**: 优化 Inbox 会话的实现逻辑,将 chat 中的功能模型拆分到 features 中,重构 session 相关实现,移除循环依赖. + +#### ✨ Features + +- **misc**: 支持 inbox 消息导出,支持 inbox 的会话功能,新增 inbox 数据模型,新增 inbox 模块入口. + +#### 💄 Styles + +- **misc**: Fix Inbox defaultMessage avatar, 优化 header 的 setting 展示,优化门禁下默认的解锁方式,补充 ChatList 的 Loading 态. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 优化 Inbox 会话的实现逻辑 ([22cc4cf](https://github.com/lobehub/lobe-chat/commit/22cc4cf)) +- **misc**: 将 chat 中的功能模型拆分到 features 中 ([e25a856](https://github.com/lobehub/lobe-chat/commit/e25a856)) +- **misc**: 重构 session 相关实现,移除循环依赖 ([9acf65c](https://github.com/lobehub/lobe-chat/commit/9acf65c)) + +#### What's improved + +- **misc**: 支持 inbox 消息导出 ([498e075](https://github.com/lobehub/lobe-chat/commit/498e075)) +- **misc**: 支持 inbox 的会话功能 ([9b713b8](https://github.com/lobehub/lobe-chat/commit/9b713b8)) +- **misc**: 新增 inbox 数据模型 ([91a8158](https://github.com/lobehub/lobe-chat/commit/91a8158)) +- **misc**: 新增 inbox 模块入口 ([6fc8907](https://github.com/lobehub/lobe-chat/commit/6fc8907)) + +#### Styles + +- **misc**: Fix Inbox defaultMessage avatar ([dbc18a4](https://github.com/lobehub/lobe-chat/commit/dbc18a4)) +- **misc**: 优化 header 的 setting 展示 ([201d380](https://github.com/lobehub/lobe-chat/commit/201d380)) +- **misc**: 优化门禁下默认的解锁方式 ([df9bb45](https://github.com/lobehub/lobe-chat/commit/df9bb45)) +- **misc**: 补充 ChatList 的 Loading 态 ([eb3eb5d](https://github.com/lobehub/lobe-chat/commit/eb3eb5d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.43.0](https://github.com/lobehub/lobe-chat/compare/v0.42.3...v0.43.0) + +Released on **2023-08-12** + +#### ✨ Features + +- **misc**: 支持切换语言. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持切换语言,closes [#67](https://github.com/lobehub/lobe-chat/issues/67) ([63ed8ec](https://github.com/lobehub/lobe-chat/commit/63ed8ec)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.42.3](https://github.com/lobehub/lobe-chat/compare/v0.42.2...v0.42.3) + +Released on **2023-08-12** + +#### 💄 Styles + +- **misc**: 暂时隐藏 Hero 模板. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 暂时隐藏 Hero 模板 ([8289ae6](https://github.com/lobehub/lobe-chat/commit/8289ae6)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.42.2](https://github.com/lobehub/lobe-chat/compare/v0.42.1...v0.42.2) + +Released on **2023-08-12** + +#### ♻ Code Refactoring + +- **misc**: 将 useSettings 更名为 useGlobalStore, 将原本的 settings 更名为 global, 收敛切换 SideBar 方法为 useSwitchSideBarOnInit, 重构需本地缓存的状态为 preference. + +#### 🐛 Bug Fixes + +- **misc**: 修正移除 session 时的路由跳转逻辑. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 将 useSettings 更名为 useGlobalStore ([bdde7df](https://github.com/lobehub/lobe-chat/commit/bdde7df)) +- **misc**: 将原本的 settings 更名为 global ([e42d34c](https://github.com/lobehub/lobe-chat/commit/e42d34c)) +- **misc**: 收敛切换 SideBar 方法为 useSwitchSideBarOnInit ([bbad38f](https://github.com/lobehub/lobe-chat/commit/bbad38f)) +- **misc**: 重构需本地缓存的状态为 preference ([8359b62](https://github.com/lobehub/lobe-chat/commit/8359b62)) + +#### What's fixed + +- **misc**: 修正移除 session 时的路由跳转逻辑 ([8b7838d](https://github.com/lobehub/lobe-chat/commit/8b7838d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.42.1](https://github.com/lobehub/lobe-chat/compare/v0.42.0...v0.42.1) + +Released on **2023-08-12** + +#### 💄 Styles + +- **misc**: 优化 App 首页 Loading 态. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 优化 App 首页 Loading 态 ([72104e8](https://github.com/lobehub/lobe-chat/commit/72104e8)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.42.0](https://github.com/lobehub/lobe-chat/compare/v0.41.2...v0.42.0) + +Released on **2023-08-11** + +#### ✨ Features + +- **misc**: Add `Welcome` page. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add `Welcome` page, closes [#60](https://github.com/lobehub/lobe-chat/issues/60) ([810ab0f](https://github.com/lobehub/lobe-chat/commit/810ab0f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.41.2](https://github.com/lobehub/lobe-chat/compare/v0.41.1...v0.41.2) + +Released on **2023-08-10** + +#### ♻ Code Refactoring + +- **misc**: 将 sessionStore 默认 equalFn 改为 shallow, 将 settingStore 默认 equalFn 改为 shallow. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 将 sessionStore 默认 equalFn 改为 shallow ([5c1b8d7](https://github.com/lobehub/lobe-chat/commit/5c1b8d7)) +- **misc**: 将 settingStore 默认 equalFn 改为 shallow ([1e72308](https://github.com/lobehub/lobe-chat/commit/1e72308)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.41.1](https://github.com/lobehub/lobe-chat/compare/v0.41.0...v0.41.1) + +Released on **2023-08-10** + +#### ♻ Code Refactoring + +- **misc**: 重构 settings store 代码写法. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 重构 settings store 代码写法 ([4b6f917](https://github.com/lobehub/lobe-chat/commit/4b6f917)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.41.0](https://github.com/lobehub/lobe-chat/compare/v0.40.7...v0.41.0) + +Released on **2023-08-10** + +#### ✨ Features + +- **misc**: 支持持久化隐藏 Topic 功能. + +#### 💄 Styles + +- **misc**: 优化第一次水合逻辑. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持持久化隐藏 Topic 功能 ([9ea2778](https://github.com/lobehub/lobe-chat/commit/9ea2778)) + +#### Styles + +- **misc**: 优化第一次水合逻辑 ([fefae61](https://github.com/lobehub/lobe-chat/commit/fefae61)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.40.7](https://github.com/lobehub/lobe-chat/compare/v0.40.6...v0.40.7) + +Released on **2023-08-10** + +#### 💄 Styles + +- **misc**: 优化 Topic 的水合加载效果. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 优化 Topic 的水合加载效果 ([0cd0088](https://github.com/lobehub/lobe-chat/commit/0cd0088)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.40.6](https://github.com/lobehub/lobe-chat/compare/v0.40.5...v0.40.6) + +Released on **2023-08-10** + +#### ♻ Code Refactoring + +- **misc**: 重构优化 hydrated 的判断逻辑. + +#### 💄 Styles + +- **misc**: 优化水合前的加载效果. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 重构优化 hydrated 的判断逻辑 ([1781119](https://github.com/lobehub/lobe-chat/commit/1781119)) + +#### Styles + +- **misc**: 优化水合前的加载效果 ([6bbd978](https://github.com/lobehub/lobe-chat/commit/6bbd978)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.40.5](https://github.com/lobehub/lobe-chat/compare/v0.40.4...v0.40.5) + +Released on **2023-08-10** + +#### 💄 Styles + +- **misc**: 增加未初始化的 loading 态. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 增加未初始化的 loading 态 ([dcb7c07](https://github.com/lobehub/lobe-chat/commit/dcb7c07)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.40.4](https://github.com/lobehub/lobe-chat/compare/v0.40.3...v0.40.4) + +Released on **2023-08-10** + +#### 💄 Styles + +- **misc**: 优化 Header 样式. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 优化 Header 样式 ([edd148a](https://github.com/lobehub/lobe-chat/commit/edd148a)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.40.3](https://github.com/lobehub/lobe-chat/compare/v0.40.2...v0.40.3) + +Released on **2023-08-10** + +#### 🐛 Bug Fixes + +- **misc**: 修正没有 prompt 的编辑与保存按钮的问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正没有 prompt 的编辑与保存按钮的问题 ([b7e1648](https://github.com/lobehub/lobe-chat/commit/b7e1648)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.40.2](https://github.com/lobehub/lobe-chat/compare/v0.40.1...v0.40.2) + +Released on **2023-08-08** + +#### 🐛 Bug Fixes + +- **misc**: 修正 defaults 造成的 config 报错. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正 defaults 造成的 config 报错 ([0857fa7](https://github.com/lobehub/lobe-chat/commit/0857fa7)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.40.1](https://github.com/lobehub/lobe-chat/compare/v0.40.0...v0.40.1) + +Released on **2023-08-06** + +#### 🐛 Bug Fixes + +- **misc**: 优化 openai 接口的错误处理逻辑. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 优化 openai 接口的错误处理逻辑 ([eae78fe](https://github.com/lobehub/lobe-chat/commit/eae78fe)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.40.0](https://github.com/lobehub/lobe-chat/compare/v0.39.4...v0.40.0) + +Released on **2023-08-05** + +#### ✨ Features + +- **misc**: Add new dependency, add Tag and PluginTag components, update HeaderTitle. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add new dependency, add Tag and PluginTag components, update HeaderTitle, closes [#56](https://github.com/lobehub/lobe-chat/issues/56) [#55](https://github.com/lobehub/lobe-chat/issues/55) [#54](https://github.com/lobehub/lobe-chat/issues/54) ([2812ea2](https://github.com/lobehub/lobe-chat/commit/2812ea2)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.39.4](https://github.com/lobehub/lobe-chat/compare/v0.39.3...v0.39.4) + +Released on **2023-08-05** + +#### 💄 Styles + +- **misc**: 修正 assistant 消息没有 background 的问题. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 修正 assistant 消息没有 background 的问题,closes [#42](https://github.com/lobehub/lobe-chat/issues/42) ([812e976](https://github.com/lobehub/lobe-chat/commit/812e976)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.39.3](https://github.com/lobehub/lobe-chat/compare/v0.39.2...v0.39.3) + +Released on **2023-08-04** + +#### 🐛 Bug Fixes + +- **misc**: 优化 405 报错返回内容,并优化 openai 服务端超时处理逻辑. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 优化 405 报错返回内容,并优化 openai 服务端超时处理逻辑 ([0acc829](https://github.com/lobehub/lobe-chat/commit/0acc829)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.39.2](https://github.com/lobehub/lobe-chat/compare/v0.39.1...v0.39.2) + +Released on **2023-08-04** + +#### 💄 Styles + +- **misc**: 优化 topic 样式. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 优化 topic 样式 ([75dc034](https://github.com/lobehub/lobe-chat/commit/75dc034)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.39.1](https://github.com/lobehub/lobe-chat/compare/v0.39.0...v0.39.1) + +Released on **2023-08-04** + +#### 🐛 Bug Fixes + +- **misc**: 修正 basePath 在生产环境下不生效的问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正 basePath 在生产环境下不生效的问题 ([71b9139](https://github.com/lobehub/lobe-chat/commit/71b9139)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.39.0](https://github.com/lobehub/lobe-chat/compare/v0.38.0...v0.39.0) + +Released on **2023-08-04** + +#### ✨ Features + +- **misc**: 支持多轮的插件意图识别,支持自定义 OpenAI 代理地址. + +#### 💄 Styles + +- **misc**: 优化插件的展示逻辑. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持多轮的插件意图识别 ([5127f1b](https://github.com/lobehub/lobe-chat/commit/5127f1b)) +- **misc**: 支持自定义 OpenAI 代理地址 ([33a111c](https://github.com/lobehub/lobe-chat/commit/33a111c)) + +#### Styles + +- **misc**: 优化插件的展示逻辑 ([7621bad](https://github.com/lobehub/lobe-chat/commit/7621bad)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.38.0](https://github.com/lobehub/lobe-chat/compare/v0.37.0...v0.38.0) + +Released on **2023-08-04** + +#### ✨ Features + +- **misc**: Add topic empty. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add topic empty ([b9f267c](https://github.com/lobehub/lobe-chat/commit/b9f267c)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.37.0](https://github.com/lobehub/lobe-chat/compare/v0.36.1...v0.37.0) + +Released on **2023-08-03** + +#### ✨ Features + +- **misc**: 支持使用全局助手的设置作为默认助手的创建角色. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持使用全局助手的设置作为默认助手的创建角色,closes [#44](https://github.com/lobehub/lobe-chat/issues/44) ([f91857d](https://github.com/lobehub/lobe-chat/commit/f91857d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.36.1](https://github.com/lobehub/lobe-chat/compare/v0.36.0...v0.36.1) + +Released on **2023-08-03** + +#### ♻ Code Refactoring + +- **misc**: Refactor zustand usage with v4.4. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Refactor zustand usage with v4.4, closes [#52](https://github.com/lobehub/lobe-chat/issues/52) ([4c65aa7](https://github.com/lobehub/lobe-chat/commit/4c65aa7)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.36.0](https://github.com/lobehub/lobe-chat/compare/v0.35.1...v0.36.0) + +Released on **2023-08-03** + +#### ✨ Features + +- **misc**: 实现自定义历史消息数功能. + +#### 🐛 Bug Fixes + +- **misc**: Fix setting type. + +#### 💄 Styles + +- **misc**: Fix session item height. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 实现自定义历史消息数功能 ([7baa022](https://github.com/lobehub/lobe-chat/commit/7baa022)) + +#### What's fixed + +- **misc**: Fix setting type ([57e415e](https://github.com/lobehub/lobe-chat/commit/57e415e)) + +#### Styles + +- **misc**: Fix session item height ([6cd1de5](https://github.com/lobehub/lobe-chat/commit/6cd1de5)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.35.1](https://github.com/lobehub/lobe-chat/compare/v0.35.0...v0.35.1) + +Released on **2023-07-31** + +#### 💄 Styles + +- **misc**: Update doc mode and token tags. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Update doc mode and token tags ([1d3c5b6](https://github.com/lobehub/lobe-chat/commit/1d3c5b6)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.35.0](https://github.com/lobehub/lobe-chat/compare/v0.34.0...v0.35.0) + +Released on **2023-07-31** + +#### ✨ Features + +- **misc**: Add agent settings functionality, new components, and features for AgentMeta, Add and modify translations for various keys in JSON code files. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add agent settings functionality, new components, and features for AgentMeta ([b1e5ff9](https://github.com/lobehub/lobe-chat/commit/b1e5ff9)) +- **misc**: Add and modify translations for various keys in JSON code files ([503adb4](https://github.com/lobehub/lobe-chat/commit/503adb4)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.34.0](https://github.com/lobehub/lobe-chat/compare/v0.33.0...v0.34.0) + +Released on **2023-07-31** + +#### ✨ Features + +- **misc**: Add agent settings functionality, Add new components and features for AgentMeta, Improve organization and functionality of settings and configuration features. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add agent settings functionality ([b0aaeed](https://github.com/lobehub/lobe-chat/commit/b0aaeed)) +- **misc**: Add new components and features for AgentMeta ([1232d95](https://github.com/lobehub/lobe-chat/commit/1232d95)) +- **misc**: Improve organization and functionality of settings and configuration features ([badde35](https://github.com/lobehub/lobe-chat/commit/badde35)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.33.0](https://github.com/lobehub/lobe-chat/compare/v0.32.0...v0.33.0) + +Released on **2023-07-30** + +#### ✨ Features + +- **misc**: 支持输入模板预处理. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持输入模板预处理 ([84082c1](https://github.com/lobehub/lobe-chat/commit/84082c1)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.32.0](https://github.com/lobehub/lobe-chat/compare/v0.31.0...v0.32.0) + +Released on **2023-07-30** + +#### ✨ Features + +- **misc**: 支持会话置顶. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持会话置顶,closes [#32](https://github.com/lobehub/lobe-chat/issues/32) ([fc44b5d](https://github.com/lobehub/lobe-chat/commit/fc44b5d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.31.0](https://github.com/lobehub/lobe-chat/compare/v0.30.1...v0.31.0) + +Released on **2023-07-30** + +#### ✨ Features + +- **misc**: 支持展示 token 使用量. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持展示 token 使用量,closes [#31](https://github.com/lobehub/lobe-chat/issues/31) ([e4d4dac](https://github.com/lobehub/lobe-chat/commit/e4d4dac)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.30.1](https://github.com/lobehub/lobe-chat/compare/v0.30.0...v0.30.1) + +Released on **2023-07-30** + +#### 💄 Styles + +- **misc**: 优化搜索引擎插件展示. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 优化搜索引擎插件展示 ([347e6b0](https://github.com/lobehub/lobe-chat/commit/347e6b0)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.30.0](https://github.com/lobehub/lobe-chat/compare/v0.29.0...v0.30.0) + +Released on **2023-07-30** + +#### ✨ Features + +- **misc**: 优化保存为话题功能,实现 Topic 重命名功能,实现话题删除功能,支持缓存角色面板的展开折叠状态. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 优化保存为话题功能 ([fdbe084](https://github.com/lobehub/lobe-chat/commit/fdbe084)) +- **misc**: 实现 Topic 重命名功能 ([5ef1685](https://github.com/lobehub/lobe-chat/commit/5ef1685)) +- **misc**: 实现话题删除功能 ([970889d](https://github.com/lobehub/lobe-chat/commit/970889d)) +- **misc**: 支持缓存角色面板的展开折叠状态 ([c241c4b](https://github.com/lobehub/lobe-chat/commit/c241c4b)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.29.0](https://github.com/lobehub/lobe-chat/compare/v0.28.0...v0.29.0) + +Released on **2023-07-30** + +#### ✨ Features + +- **misc**: 实现单个会话和角色的导出功能,实现清空所有会话消息. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 实现单个会话和角色的导出功能 ([d15a481](https://github.com/lobehub/lobe-chat/commit/d15a481)) +- **misc**: 实现清空所有会话消息 ([64c5125](https://github.com/lobehub/lobe-chat/commit/64c5125)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.28.0](https://github.com/lobehub/lobe-chat/compare/v0.27.4...v0.28.0) + +Released on **2023-07-30** + +#### ♻ Code Refactoring + +- **misc**: 重构 settings 相关类型. + +#### ✨ Features + +- **misc**: 优化 SideBar 实现,激活态指示更加明确,实现 session 导入功能,实现配置导出功能. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 重构 settings 相关类型 ([6b7c0a0](https://github.com/lobehub/lobe-chat/commit/6b7c0a0)) + +#### What's improved + +- **misc**: 优化 SideBar 实现,激活态指示更加明确 ([8a467df](https://github.com/lobehub/lobe-chat/commit/8a467df)) +- **misc**: 实现 session 导入功能 ([5650167](https://github.com/lobehub/lobe-chat/commit/5650167)) +- **misc**: 实现配置导出功能 ([c1f73fe](https://github.com/lobehub/lobe-chat/commit/c1f73fe)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.27.4](https://github.com/lobehub/lobe-chat/compare/v0.27.3...v0.27.4) + +Released on **2023-07-29** + +#### 🐛 Bug Fixes + +- **misc**: 修正日志超过 4096 长度的问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正日志超过 4096 长度的问题 ([6066aff](https://github.com/lobehub/lobe-chat/commit/6066aff)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.27.3](https://github.com/lobehub/lobe-chat/compare/v0.27.2...v0.27.3) + +Released on **2023-07-29** + +#### 🐛 Bug Fixes + +- **misc**: 修正返回结果导致插件无法正常识别的问题. + +#### 💄 Styles + +- **misc**: 优化样式. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正返回结果导致插件无法正常识别的问题 ([b183188](https://github.com/lobehub/lobe-chat/commit/b183188)) + +#### Styles + +- **misc**: 优化样式 ([9ce5d1d](https://github.com/lobehub/lobe-chat/commit/9ce5d1d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.27.2](https://github.com/lobehub/lobe-chat/compare/v0.27.1...v0.27.2) + +Released on **2023-07-29** + +#### ♻ Code Refactoring + +- **misc**: 重构并优化文档抓取插件能力. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 重构并优化文档抓取插件能力 ([ff56348](https://github.com/lobehub/lobe-chat/commit/ff56348)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.27.1](https://github.com/lobehub/lobe-chat/compare/v0.27.0...v0.27.1) + +Released on **2023-07-29** + +#### 💄 Styles + +- **misc**: 优化搜索引擎样式. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 优化搜索引擎样式 ([699afb3](https://github.com/lobehub/lobe-chat/commit/699afb3)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.27.0](https://github.com/lobehub/lobe-chat/compare/v0.26.1...v0.27.0) + +Released on **2023-07-29** + +#### ✨ Features + +- **misc**: 优化搜索引擎插件交互展示. + +#### 💄 Styles + +- **misc**: 优化兜底结果展示. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 优化搜索引擎插件交互展示 ([4751084](https://github.com/lobehub/lobe-chat/commit/4751084)) + +#### Styles + +- **misc**: 优化兜底结果展示 ([9da45d6](https://github.com/lobehub/lobe-chat/commit/9da45d6)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.26.1](https://github.com/lobehub/lobe-chat/compare/v0.26.0...v0.26.1) + +Released on **2023-07-29** + +#### ♻ Code Refactoring + +- **misc**: 优化 setting Layout 实现. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 优化 setting Layout 实现 ([f789935](https://github.com/lobehub/lobe-chat/commit/f789935)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.26.0](https://github.com/lobehub/lobe-chat/compare/v0.25.0...v0.26.0) + +Released on **2023-07-28** + +#### ✨ Features + +- **misc**: support password auth and error. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: support password auth and error, closes [#22](https://github.com/lobehub/lobe-chat/issues/22) ([67f1f4d](https://github.com/lobehub/lobe-chat/commit/67f1f4d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.25.0](https://github.com/lobehub/lobe-chat/compare/v0.24.0...v0.25.0) + +Released on **2023-07-26** + +#### ✨ Features + +- **sidebar**: Add import functionality and set labels and onClick functions + +
+ +
+Improvements and Fixes + +#### ✨ Features + +- **sidebar**: Add import functionality and set labels and onClick functions ([03ea9bd](https://github.com/lobehub/lobe-chat/commit/03ea9bd)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.24.0](https://github.com/lobehub/lobe-chat/compare/v0.23.0...v0.24.0) + +Released on **2023-07-26** + +#### ✨ Features + +- **misc**: Add new translations, update existing translations, add functionality to components, modify styling, and adjust placeholder text + +
+ +
+Improvements and Fixes + +#### ✨ Features + +- Add new translations, update existing translations, add functionality to components, modify styling, and adjust placeholder text ([da4ae72](https://github.com/lobehub/lobe-chat/commit/da4ae72)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.23.0](https://github.com/lobehub/lobe-chat/compare/v0.22.2...v0.23.0) + +Released on **2023-07-26** + +#### ✨ Features + +- **misc**: Add new features, update URLs, customize appearance, and implement components + +
+ +
+Improvements and Fixes + +#### ✨ Features + +- Add new features, update URLs, customize appearance, and implement components ([4b61bf4](https://github.com/lobehub/lobe-chat/commit/4b61bf4)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.22.2](https://github.com/lobehub/lobe-chat/compare/v0.22.1...v0.22.2) + +Released on **2023-07-26** + +#### 💄 Styles + +- **misc**: 优化 tooltip 显示. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 优化 tooltip 显示 ([4ba0295](https://github.com/lobehub/lobe-chat/commit/4ba0295)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.22.1](https://github.com/lobehub/lobe-chat/compare/v0.22.0...v0.22.1) + +Released on **2023-07-25** + +#### 🐛 Bug Fixes + +- **misc**: 修正自定义 OpenAI API Key 的使用问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正自定义 OpenAI API Key 的使用问题 ([84475c0](https://github.com/lobehub/lobe-chat/commit/84475c0)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.22.0](https://github.com/lobehub/lobe-chat/compare/v0.21.0...v0.22.0) + +Released on **2023-07-25** + +#### ✨ Features + +- **misc**: 支持使用自定义 OpenAI Key. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持使用自定义 OpenAI Key, closes [#20](https://github.com/lobehub/lobe-chat/issues/20) ([fb454a0](https://github.com/lobehub/lobe-chat/commit/fb454a0)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.21.0](https://github.com/lobehub/lobe-chat/compare/v0.20.0...v0.21.0) + +Released on **2023-07-25** + +#### ♻ Code Refactoring + +- **misc**: Move component folder. + +#### ✨ Features + +- **misc**: 支持快捷配置模型、温度. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Move component folder ([fb85d16](https://github.com/lobehub/lobe-chat/commit/fb85d16)) + +#### What's improved + +- **misc**: 支持快捷配置模型、温度,closes [#19](https://github.com/lobehub/lobe-chat/issues/19) ([31daee1](https://github.com/lobehub/lobe-chat/commit/31daee1)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.20.0](https://github.com/lobehub/lobe-chat/compare/v0.19.0...v0.20.0) + +Released on **2023-07-25** + +#### ✨ Features + +- **misc**: 实现话题模块. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 实现话题模块,closes [#16](https://github.com/lobehub/lobe-chat/issues/16) ([64fd6ee](https://github.com/lobehub/lobe-chat/commit/64fd6ee)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.19.0](https://github.com/lobehub/lobe-chat/compare/v0.18.2...v0.19.0) + +Released on **2023-07-24** + +#### ♻ Code Refactoring + +- **misc**: 将 message reducer 提取到独立文件夹中,清理无用代码实现. + +#### ✨ Features + +- **misc**: 数据结构层完成 topic 模型改造. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 将 message reducer 提取到独立文件夹中 ([64f40ca](https://github.com/lobehub/lobe-chat/commit/64f40ca)) +- **misc**: 清理无用代码实现 ([3655b60](https://github.com/lobehub/lobe-chat/commit/3655b60)) + +#### What's improved + +- **misc**: 数据结构层完成 topic 模型改造 ([99fa2a6](https://github.com/lobehub/lobe-chat/commit/99fa2a6)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.18.2](https://github.com/lobehub/lobe-chat/compare/v0.18.1...v0.18.2) + +Released on **2023-07-24** + +#### 💄 Styles + +- **misc**: 修正 markdown li 丢失的问题. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 修正 markdown li 丢失的问题 ([eb6e831](https://github.com/lobehub/lobe-chat/commit/eb6e831)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.18.1](https://github.com/lobehub/lobe-chat/compare/v0.18.0...v0.18.1) + +Released on **2023-07-24** + +#### ♻ Code Refactoring + +- **misc**: 优化新会话的创建逻辑 session. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 优化新会话的创建逻辑 session ([d70f22d](https://github.com/lobehub/lobe-chat/commit/d70f22d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.18.0](https://github.com/lobehub/lobe-chat/compare/v0.17.0...v0.18.0) + +Released on **2023-07-24** + +#### ✨ Features + +- **misc**: 实现会话展示模式切换,并优化默认创建角色的配置. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 实现会话展示模式切换,并优化默认创建角色的配置 ([27ae82f](https://github.com/lobehub/lobe-chat/commit/27ae82f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.17.0](https://github.com/lobehub/lobe-chat/compare/v0.16.1...v0.17.0) + +Released on **2023-07-24** + +#### ✨ Features + +- **misc**: 表单配置支持设定各项高级参数. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 表单配置支持设定各项高级参数 ([6949cc6](https://github.com/lobehub/lobe-chat/commit/6949cc6)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.16.1](https://github.com/lobehub/lobe-chat/compare/v0.16.0...v0.16.1) + +Released on **2023-07-24** + +#### ♻ Code Refactoring + +- **misc**: 重构优化 selectors 实现. + +#### 💄 Styles + +- **misc**: 优化 document title. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 重构优化 selectors 实现 ([97fe1cd](https://github.com/lobehub/lobe-chat/commit/97fe1cd)) + +#### Styles + +- **misc**: 优化 document title ([c3cda00](https://github.com/lobehub/lobe-chat/commit/c3cda00)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.16.0](https://github.com/lobehub/lobe-chat/compare/v0.15.1...v0.16.0) + +Released on **2023-07-24** + +#### ✨ Features + +- **misc**: 支持自动跳转到第一条会话. + +#### 💄 Styles + +- **misc**: 修正插件的展示文案. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持自动跳转到第一条会话 ([54f01c7](https://github.com/lobehub/lobe-chat/commit/54f01c7)) + +#### Styles + +- **misc**: 修正插件的展示文案 ([53c81ae](https://github.com/lobehub/lobe-chat/commit/53c81ae)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.15.1](https://github.com/lobehub/lobe-chat/compare/v0.15.0...v0.15.1) + +Released on **2023-07-24** + +#### 💄 Styles + +- **misc**: 更新插件文案. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 更新插件文案 ([0411335](https://github.com/lobehub/lobe-chat/commit/0411335)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.15.0](https://github.com/lobehub/lobe-chat/compare/v0.14.0...v0.15.0) + +Released on **2023-07-24** + +#### ✨ Features + +- **misc**: Add new features and improve user experience, Import and use constants from "meta.ts" instead of "agentConfig". + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add new features and improve user experience ([64c8782](https://github.com/lobehub/lobe-chat/commit/64c8782)) +- **misc**: Import and use constants from "meta.ts" instead of "agentConfig" ([1eb6a17](https://github.com/lobehub/lobe-chat/commit/1eb6a17)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.14.0](https://github.com/lobehub/lobe-chat/compare/v0.13.1...v0.14.0) + +Released on **2023-07-24** + +#### ✨ Features + +- **misc**: 支持网页抓取. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持网页抓取,closes [#14](https://github.com/lobehub/lobe-chat/issues/14) ([9e933b0](https://github.com/lobehub/lobe-chat/commit/9e933b0)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.13.1](https://github.com/lobehub/lobe-chat/compare/v0.13.0...v0.13.1) + +Released on **2023-07-23** + +#### 🐛 Bug Fixes + +- **misc**: 修正搜索引擎插件的实现问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正搜索引擎插件的实现问题 ([d19a805](https://github.com/lobehub/lobe-chat/commit/d19a805)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.13.0](https://github.com/lobehub/lobe-chat/compare/v0.12.1...v0.13.0) + +Released on **2023-07-23** + +#### ✨ Features + +- **misc**: 优化插件模式下的用户体验. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 优化插件模式下的用户体验,closes [#13](https://github.com/lobehub/lobe-chat/issues/13) ([4596f12](https://github.com/lobehub/lobe-chat/commit/4596f12)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.12.1](https://github.com/lobehub/lobe-chat/compare/v0.12.0...v0.12.1) + +Released on **2023-07-23** + +#### 🐛 Bug Fixes + +- **misc**: 修正 message parentId 不正确的问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: 修正 message parentId 不正确的问题 ([f86852a](https://github.com/lobehub/lobe-chat/commit/f86852a)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.12.0](https://github.com/lobehub/lobe-chat/compare/v0.11.0...v0.12.0) + +Released on **2023-07-23** + +#### ✨ Features + +- **misc**: 支持插件列表 与 基于 Serpapi 的搜索引擎插件. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持插件列表 与 基于 Serpapi 的搜索引擎插件,closes [#12](https://github.com/lobehub/lobe-chat/issues/12) ([d89e06f](https://github.com/lobehub/lobe-chat/commit/d89e06f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.11.0](https://github.com/lobehub/lobe-chat/compare/v0.10.2...v0.11.0) + +Released on **2023-07-23** + +#### ♻ Code Refactoring + +- **misc**: Remove langchain, 优化代码. + +#### ✨ Features + +- **misc**: 支持查询天气. + +#### 💄 Styles + +- **misc**: Update manifest, 增加国际化文案. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: Remove langchain ([7b0f96c](https://github.com/lobehub/lobe-chat/commit/7b0f96c)) +- **misc**: 优化代码 ([6a8f7df](https://github.com/lobehub/lobe-chat/commit/6a8f7df)) + +#### What's improved + +- **misc**: 支持查询天气 ([34bf285](https://github.com/lobehub/lobe-chat/commit/34bf285)) + +#### Styles + +- **misc**: Update manifest ([ea9e8de](https://github.com/lobehub/lobe-chat/commit/ea9e8de)) +- **misc**: 增加国际化文案 ([f5e8d7c](https://github.com/lobehub/lobe-chat/commit/f5e8d7c)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.10.2](https://github.com/lobehub/lobe-chat/compare/v0.10.1...v0.10.2) + +Released on **2023-07-23** + +#### 💄 Styles + +- **misc**: 优化模型在 list 中的展示逻辑. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 优化模型在 list 中的展示逻辑 ([4bdf3c5](https://github.com/lobehub/lobe-chat/commit/4bdf3c5)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.10.1](https://github.com/lobehub/lobe-chat/compare/v0.10.0...v0.10.1) + +Released on **2023-07-22** + +#### 💄 Styles + +- **misc**: 修正对话中用户头像的问题. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: 修正对话中用户头像的问题 ([560c8bb](https://github.com/lobehub/lobe-chat/commit/560c8bb)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.10.0](https://github.com/lobehub/lobe-chat/compare/v0.9.0...v0.10.0) + +Released on **2023-07-22** + +#### ✨ Features + +- **misc**: 支持复制与编辑会话消息. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持复制与编辑会话消息 ([bebcf9f](https://github.com/lobehub/lobe-chat/commit/bebcf9f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.9.0](https://github.com/lobehub/lobe-chat/compare/v0.8.2...v0.9.0) + +Released on **2023-07-22** + +#### ✨ Features + +- **misc**: 展示模型类型. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 展示模型类型 ([58ea93c](https://github.com/lobehub/lobe-chat/commit/58ea93c)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.8.2](https://github.com/lobehub/lobe-chat/compare/v0.8.1...v0.8.2) + +Released on **2023-07-22** + +#### 🐛 Bug Fixes + +- **misc**: Fix miss manifest.json link, 优化 model tag 展示逻辑. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix miss manifest.json link ([ac4b2f3](https://github.com/lobehub/lobe-chat/commit/ac4b2f3)) +- **misc**: 优化 model tag 展示逻辑 ([3463ede](https://github.com/lobehub/lobe-chat/commit/3463ede)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.8.1](https://github.com/lobehub/lobe-chat/compare/v0.8.0...v0.8.1) + +Released on **2023-07-22** + +#### 🐛 Bug Fixes + +- **misc**: Fix import. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix import ([4fb9967](https://github.com/lobehub/lobe-chat/commit/4fb9967)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.8.0](https://github.com/lobehub/lobe-chat/compare/v0.7.0...v0.8.0) + +Released on **2023-07-22** + +#### ✨ Features + +- **misc**: 支持 pwa 模式. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持 pwa 模式 ([8aad92d](https://github.com/lobehub/lobe-chat/commit/8aad92d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.7.0](https://github.com/lobehub/lobe-chat/compare/v0.6.1...v0.7.0) + +Released on **2023-07-22** + +#### ✨ Features + +- **misc**: 支持展示来自模型的标记信息. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持展示来自模型的标记信息 ([e27fae9](https://github.com/lobehub/lobe-chat/commit/e27fae9)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.6.1](https://github.com/lobehub/lobe-chat/compare/v0.6.0...v0.6.1) + +Released on **2023-07-22** + +#### 🐛 Bug Fixes + +- **misc**: Add deps. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Add deps ([3dc45fe](https://github.com/lobehub/lobe-chat/commit/3dc45fe)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.6.0](https://github.com/lobehub/lobe-chat/compare/v0.5.0...v0.6.0) + +Released on **2023-07-22** + +#### ♻ Code Refactoring + +- **misc**: 重构 selector 文件组织. + +#### ✨ Features + +- **misc**: 补充 token 详情. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 重构 selector 文件组织 ([2ad0ef9](https://github.com/lobehub/lobe-chat/commit/2ad0ef9)) + +#### What's improved + +- **misc**: 补充 token 详情 ([098f7ff](https://github.com/lobehub/lobe-chat/commit/098f7ff)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.5.0](https://github.com/lobehub/lobe-chat/compare/v0.4.3...v0.5.0) + +Released on **2023-07-22** + +#### ✨ Features + +- **misc**: 支持选择 Emoji. + +#### 🐛 Bug Fixes + +- **misc**: 修正 total token 计算不正确的问题. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: 支持选择 Emoji ([6cb4828](https://github.com/lobehub/lobe-chat/commit/6cb4828)) + +#### What's fixed + +- **misc**: 修正 total token 计算不正确的问题 ([17815c6](https://github.com/lobehub/lobe-chat/commit/17815c6)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.4.3](https://github.com/lobehub/lobe-chat/compare/v0.4.2...v0.4.3) + +Released on **2023-07-22** + +#### ♻ Code Refactoring + +- **misc**: 优化 edit 代码结构. + +
+ +
+Improvements and Fixes + +#### Code refactoring + +- **misc**: 优化 edit 代码结构 ([fdb3a3f](https://github.com/lobehub/lobe-chat/commit/fdb3a3f)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.4.2](https://github.com/lobehub/lobe-chat/compare/v0.4.1...v0.4.2) + +Released on **2023-07-22** + +#### 💄 Styles + +- **misc**: Fix input style, fix layout. + +
+ +
+Improvements and Fixes + +#### Styles + +- **misc**: Fix input style ([504bd64](https://github.com/lobehub/lobe-chat/commit/504bd64)) +- **misc**: Fix layout ([2d83aff](https://github.com/lobehub/lobe-chat/commit/2d83aff)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.4.1](https://github.com/lobehub/lobe-chat/compare/v0.4.0...v0.4.1) + +Released on **2023-07-22** + +#### 🐛 Bug Fixes + +- **misc**: Fix SSR style error. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- **misc**: Fix SSR style error ([289eae7](https://github.com/lobehub/lobe-chat/commit/289eae7)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.4.0](https://github.com/lobehub/lobe-chat/compare/v0.3.0...v0.4.0) + +Released on **2023-07-20** + +#### ✨ Features + +- **misc**: Add styles and modify layout of FolderPanel, SliderWithInput, SessionList, EditPage, ChatLayout, and SettingLayout components, Introduce FOLDER_WIDTH constant and update components. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add styles and modify layout of FolderPanel, SliderWithInput, SessionList, EditPage, ChatLayout, and SettingLayout components ([7f19a09](https://github.com/lobehub/lobe-chat/commit/7f19a09)) +- **misc**: Introduce FOLDER_WIDTH constant and update components ([c511964](https://github.com/lobehub/lobe-chat/commit/c511964)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.3.0](https://github.com/lobehub/lobe-chat/compare/v0.2.0...v0.3.0) + +Released on **2023-07-18** + +#### ✨ Features + +- **misc**: Add new files, modify components, and adjust layout and styling. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add new files, modify components, and adjust layout and styling ([b8c3b38](https://github.com/lobehub/lobe-chat/commit/b8c3b38)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.2.0](https://github.com/lobehub/lobe-chat/compare/v0.1.6...v0.2.0) + +Released on **2023-07-18** + +#### ✨ Features + +- **misc**: Add import statement and define CSS styles for Avatar component. + +
+ +
+Improvements and Fixes + +#### What's improved + +- **misc**: Add import statement and define CSS styles for Avatar component ([8c23a8d](https://github.com/lobehub/lobe-chat/commit/8c23a8d)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.1.6](https://github.com/lobehub/lobe-chat/compare/v0.1.5...v0.1.6) + +Released on **2023-07-18** + +
+ +
+Improvements and Fixes + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000000..83832d49622a9 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -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 +. + +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 +. Translations are available at +. + +[homepage]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000000..9fd6479662da1 --- /dev/null +++ b/CONTRIBUTING.md @@ -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 +yarn 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! 🚀🦄 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000..2bc75291100dc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,52 @@ +FROM node:20-slim AS base + +## Install dependencies only when needed +FROM base AS builder +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable + +WORKDIR /app + +COPY package.json ./ + +# If you want to build docker in China +#RUN npm config set registry https://registry.npmmirror.com/ +RUN pnpm i + +COPY . . +RUN pnpm run build:docker # run build standalone for docker version + +## Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV production + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + +# Set the correct permission for prerender cache +RUN mkdir .next +RUN chown nextjs:nodejs .next + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3210 + +# set hostname to localhost +ENV HOSTNAME "0.0.0.0" +ENV PORT=3210 + +ENV ACCESS_CODE "lobe66" +ENV OPENAI_API_KEY "" +ENV OPENAI_PROXY_URL "" + +CMD ["node", "server.js"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000..1dd53d2a9d99e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 LobeHub + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000000000..9caa8c9617b08 --- /dev/null +++ b/README.md @@ -0,0 +1,594 @@ +
+ + + + + +# Lobe Chat + +LobeChat is an open-source, high-performance chatbot framework
that supports speech synthesis, multimodal, and extensible ([Function Call][fc-link]) plugin system.
+Supports one-click free deployment of your private ChatGPT/LLM web application. + +**English** · [简体中文](./README.zh-CN.md) · [Changelog](./CHANGELOG.md) · [Wiki][github-wiki-link] · [Report Bug][github-issues-link] · [Request Feature][github-issues-link] + + + +[![][github-release-shield]][github-release-link] +[![][docker-release-shield]][docker-release-link] +[![][vercel-shield]][vercel-link] +[![][discord-shield]][discord-link]
+[![][github-action-test-shield]][github-action-test-link] +[![][github-action-release-shield]][github-action-release-link] +[![][github-releasedate-shield]][github-releasedate-link]
+[![][github-contributors-shield]][github-contributors-link] +[![][github-forks-shield]][github-forks-link] +[![][github-stars-shield]][github-stars-link] +[![][github-issues-shield]][github-issues-link] +[![][github-license-shield]][github-license-link] + +**Share LobeChat Repository** + +[![][share-x-shield]][share-x-link] +[![][share-telegram-shield]][share-telegram-link] +[![][share-whatsapp-shield]][share-whatsapp-link] +[![][share-reddit-shield]][share-reddit-link] +[![][share-weibo-shield]][share-weibo-link] + +Pioneering the new age of thinking and creating. Built for you, the Super Individual. + +![](https://gw.alipayobjects.com/zos/kitchen/RKnWrrfuMl/welcome.webp) + +
+ +
+Table of contents + +#### TOC + +- [👋🏻 Getting Started & Join Our Community](#-getting-started--join-our-community) +- [✨ Features](#-features) +- [📸 Snapshot](#-snapshot) +- [⚡️ Performance](#️-performance) +- [🛳 Self Hosting](#-self-hosting) + - [`A` Deploying with Vercel](#a-deploying-with-vercel) + - [`B` Deploying with Docker](#b-deploying-with-docker) + - [Environment Variable](#environment-variable) +- [📦 Ecosystem](#-ecosystem) +- [🧩 Plugins](#-plugins) +- [⌨️ Local Development](#️-local-development) +- [🤝 Contributing](#-contributing) +- [🔗 More Products](#-more-products) + +#### + +
+ +
+ +## 👋🏻 Getting Started & Join Our Community + +Please be aware that LobeChat is currently under active development, and feedback is welcome for any [issues][issues-link] encountered. + +| [![][vercel-shield-badge]][vercel-link] | No installation or registration necessary! Visit our website to experience it firsthand. | +| :---------------------------------------- | :----------------------------------------------------------------------------------------------------------------- | +| [![][discord-shield-badge]][discord-link] | Join our Discord community! This is where you can connect with developers and other enthusiastic users of LobeHub. | + +> \[!IMPORTANT] +> +> **Star Us**, You will receive all release notifications from GitHub without any delay \~ ⭐️ + +![](https://gw.alipayobjects.com/zos/kitchen/0hcO8QiU9c/star.webp) + +
+ Star History + + + + +
+ +## ✨ Features + +- [x] 💎 **Exquisite UI Design**: With a carefully designed interface, it offers an elegant appearance and smooth interaction. It supports light and dark themes and is mobile-friendly. PWA support provides a more native-like experience. +- [x] 🗣️ **Smooth Conversation Experience**: Fluid responses ensure a smooth conversation experience. It fully supports Markdown rendering, including code highlighting, LaTex formulas, Mermaid flowcharts, and more. +- [x] 🤖 **Customizable Agent Roles**: Users can create, share, and debug personalized dialogue agent roles according to their needs, providing more flexible and customized dialogue functions. +- [x] 🧩 **Plugin Support & Custom Plugin Development**: Conversations are extendable with plugins. Users can install and use various plugins, such as search engines, web extraction, etc. It also supports the development of custom plugins to meet custom needs. +- [x] 🏬 **Agent Market**: A Agent Market is provided where users can select their preferred dialogue agent roles, enriching the content and style of the dialogue. +- [x] 👁️ **Visual Recognition**: With the integration of visual recognition capabilities, your agent can now analyze and understand images provided during the conversation. This allows for more interactive and context-aware conversations, enabling the dialogue agent to provide relevant and accurate responses based on visual content. +- [x] 📢 **TTS & STT Conversation**: LobeChat are supporting Text-to-Speech and Speech-to-Text technology, allowing users to have voice-based conversations with the dialogue agent. This feature enhances the user experience by providing a more natural and immersive conversation environment. Users can choose from a variety of voices and adjust the speech rate to suit their preferences. + +--- + +Beside these features, LobeChat also have much better basic technique underground: + +- [x] 💨 **Quick Deployment**: Using the Vercel platform or docker image, you can deploy with just one click and complete the process within 1 minute without any complex configuration. +- [x] 🌐 **Custom Domain**: If users have their own domain, they can bind it to the platform for quick access to the dialogue agent from anywhere. +- [x] 🔒 **Privacy Protection**: All data is stored locally in the user's browser, ensuring user privacy. + +> \[!NOTE] +> +> You can find our upcoming [Roadmap][github-project-link] plans in the Projects section. + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 📸 Snapshot + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/284072129-382bdf30-e3d6-4411-b5a0-249710b8ba08.png) + +#### `1` Visual Model Support + +LobeChat now supports OpenAI's latest [`gpt-4-vision`](https://platform.openai.com/docs/guides/vision) model with visual recognition capabilities, +a multimodal intelligence that can perceive visuals. Users can easily upload or drag and drop images into the dialogue box, +and the agent will be able to recognize the content of the images and engage in intelligent conversation based on this, +creating smarter and more diversified chat scenarios. + +This feature opens up new interactive methods, allowing communication to transcend text and include a wealth of visual elements. +Whether it's sharing images in daily use or interpreting images within specific industries, the agent provides an outstanding conversational experience. + +
+ +[![][back-to-top]](#readme-top) + +
+ +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/284072124-c9853d8d-f1b5-44a8-a305-45ebc0f6d19a.png) + +#### `2` TTS & STT Voice Speech + +LobeChat supports Text-to-Speech (TTS) and Speech-to-Text (STT) technologies, enabling our application to convert text messages into clear voice outputs, +allowing users to interact with our conversational agent as if they were talking to a real person. Users can choose from a variety of voices to pair with the agent. + +Moreover, TTS offers an excellent solution for those who prefer auditory learning or desire to receive information while busy. +In LobeChat, we have meticulously selected a range of high-quality voice options (OpenAI Audio, Microsoft Edge Speech) to meet the needs of users from different regions and cultural backgrounds. +Users can choose the voice that suits their personal preferences or specific scenarios, resulting in a personalized communication experience. + +> \[!NOTE] +> +> In the process of implementing this feature, we found that there was no satisfactory TTS (Text-to-Speech) frontend library available on the market. +> As a result, we invested a lot of effort, including data conversion, audio progress management, and speech visualization, among other tasks. + +> \[!IMPORTANT] +> +> Therefore, we decided to refine our implementation and make it open source, hoping to assist developers who wish to implement TTS. +> [@lobehub/tts][lobe-tts-github] is a high-quality TTS toolkit developed in TypeScript, which supports usage both on the server-side and in the browser. +> +> - **Server-side:** With just 15 lines of code, you can achieve high-quality voice generation capabilities comparable to OpenAI's TTS service. It currently supports EdgeSpeechTTS, MicrosoftTTS, OpenAITTS, and OpenAISTT. +> - **Browser-side:** It provides high-quality React Hooks and visual audio components, supporting common functions such as loading, playing, pausing, and dragging the timeline. Additionally, it offers a very rich set of capabilities for adjusting the audio track styles. + +
+ +[![][back-to-top]](#readme-top) + +
+ +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/268670883-33c43a5c-a512-467e-855c-fa299548cce5.png) + +#### `3` Function Calling Plugin System + +The plugin ecosystem of LobeChat is a significant extension of its core functionalities, greatly enhancing the practicality and flexibility of ChatGPT. +By leveraging plugins, ChatGPT can perform real-time information retrieval and processing, +such as automatically fetching the latest news headlines to provide users with immediate and relevant information. +Moreover, these plugins are not limited to news aggregation but can also extend to other practical functions, such as quick document retrieval, +e-commerce platform data access, and various third-party services. + +> \[!TIP] +> +> To aid developers in joining this ecosystem, we provide comprehensive development resources in the [🧩 Plugin System](#-plugins) section. +> This includes detailed component development documentation, +> a fully-featured software development kit (SDK), and template files—all designed to simplify the development process and lower the barrier to entry for developers. + +> \[!IMPORTANT] +> +> We welcome developers to use these resources to unleash their creativity and write feature-rich, user-friendly plugins. +> With collective efforts, we can continuously expand the boundaries of chat applications and explore a more intelligent and efficient creativity platform. + + + + + +| Official Plugin | Repository | Description | +| ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | +| [Clock Time](https://chat-preview.lobehub.com/settings/agent)
By **LobeHub** on **2023-11-01** | [lobehub/chat-plugin-clock-time](https://github.com/lobehub/chat-plugin-clock-time) | Display a clock to show current time
`clock` `time` | +| [Website Crawler](https://chat-preview.lobehub.com/settings/agent)
By **LobeHub** on **2023-08-17** | [lobehub/chat-plugin-web-crawler](https://github.com/lobehub/chat-plugin-web-crawler) | Extract content from web links
`web` `content-crawler` | +| [Search Engine](https://chat-preview.lobehub.com/settings/agent)
By **LobeHub** on **2023-08-15** | [lobehub/chat-plugin-search-engine](https://github.com/lobehub/chat-plugin-search-engine) | Query search engine to get information
`web` `search` | +| [Realtime Weather](https://chat-preview.lobehub.com/settings/agent)
By **LobeHub** on **2023-08-12** | [lobehub/chat-plugin-realtime-weather](https://github.com/lobehub/chat-plugin-realtime-weather) | Get realtime weather information
`weather` `realtime` | + +> 📊 Total plugins: [**4**](https://github.com/lobehub/lobe-chat-plugins) + + + +
+ +[![][back-to-top]](#readme-top) + +
+ +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/268670869-f1ffbf66-42b6-42cf-a937-9ce1f8328514.png) + +#### `4` Prompt Agent Market + +In the LobeChat Agent Marketplace, creators can discover a vibrant and innovative community that brings together a multitude of well-designed agents, +which not only play an important role in work scenarios but also offer great convenience in learning processes. +Our marketplace is not just a showcase platform but also a collaborative space. Here, everyone can contribute their wisdom and share the agents they have developed. + +> \[!TIP] +> +> By [🤖/🏪 Submit Agents][submit-agents-link], you can easily submit your agent creations to our platform. +> Importantly, LobeChat has established a sophisticated automated internationalization (i18n) workflow, +> capable of seamlessly translating your agent into multiple language versions. +> This means that no matter what language your users speak, they can experience your agent without barriers. + +> \[!IMPORTANT] +> +> We welcome all users to join this growing ecosystem and participate in the iteration and optimization of agents. +> Together, we can create more interesting, practical, and innovative agents, further enriching the diversity and practicality of the agent offerings. + + + +| Recent Submits | Description | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [JS Code Quality Optimization](https://chat-preview.lobehub.com/market?agent=js-code-quality)
By **[canisminor1990](https://github.com/canisminor1990)** on **2023-11-22** | Dedicated to clean and elegant code refactoring
`refactoring` `code-optimization` `code-quality` | +| [LobeChat Test Engineer](https://chat-preview.lobehub.com/market?agent=lobe-chat-unit-test-dev)
By **[arvinxx](https://github.com/arvinxx)** on **2023-11-22** | Proficient in writing frontend automation tests, especially comprehensive test coverage for TypeScript applications. Skilled in using the Vitest testing framework with a deep understanding of testing principles and strategies.
`automation-testing` `testing` `lobe-chat` `frontend` | +| [Q\&A Document Conversion Expert](https://chat-preview.lobehub.com/market?agent=q-a-helper)
By **[barryWang12138](https://github.com/barryWang12138)** on **2023-11-22** | Please provide your document content, and I will segment and clean it according to your requirements, and provide answers in a standardized format.
`q-a` `document` | +| [True Friend](https://chat-preview.lobehub.com/market?agent=ai-0x0-old-friends)
By **[mushan0x0](https://github.com/mushan0x0)** on **2023-11-21** | You can talk to me about anything. I can give you some thoughts and advice as a friend. Relax.
`friendship` `humor` `authentic` `simulation` | + +> 📊 Total agents: [**52** ](https://github.com/lobehub/lobe-chat-agents) + + + +
+ +[![][back-to-top]](#readme-top) + +
+ +![](https://gw.alipayobjects.com/zos/kitchen/69x6bllkX3/pwa.webp) + +#### `5` Progress Web App + +We deeply understand the importance of providing a seamless experience for users in today's multi-device environment. +Therefore, we have adopted Progressive Web Application ([PWA](https://support.google.com/chrome/answer/9658361)) technology, +a modern web technology that elevates web applications to an experience close to that of native apps. + +Through PWA, LobeChat can offer a highly optimized user experience on both desktop and mobile devices while maintaining its lightweight and high-performance characteristics. +Visually and in terms of feel, we have also meticulously designed the interface to ensure it is indistinguishable from native apps, +providing smooth animations, responsive layouts, and adapting to different device screen resolutions. + +> \[!NOTE] +> +> If you are unfamiliar with the installation process of PWA, you can add LobeChat as your desktop application (also applicable to mobile devices) by following these steps: +> +> - Launch the Chrome or Edge browser on your computer. +> - Visit the LobeChat webpage. +> - In the upper right corner of the address bar, click on the Install icon. +> - Follow the instructions on the screen to complete the PWA Installation. + +
+ +[![][back-to-top]](#readme-top) + +
+ +![](https://gw.alipayobjects.com/zos/kitchen/pvus1lo%26Z7/darkmode.webp) + +#### `6` Theme Mode Selection + +As a design-engineering-oriented application, LobeChat places great emphasis on users' personalized experiences, +hence introducing flexible and diverse theme modes, including a light mode for daytime and a dark mode for nighttime. +Beyond switching theme modes, a range of color customization options allow users to adjust the application's theme colors according to their preferences. +Whether it's a desire for a sober dark blue, a lively peach pink, or a professional gray-white, users can find their style of color choices in LobeChat. + +> \[!TIP] +> +> The default configuration can intelligently recognize the user's system color mode and automatically switch themes to ensure a consistent visual experience with the operating system. +> For users who like to manually control details, LobeChat also offers intuitive setting options and a choice between chat bubble mode and document mode for conversation scenarios. + +
+ +[![][back-to-top]](#readme-top) + +
+ +![](https://gw.alipayobjects.com/zos/kitchen/R441AuFS4W/mobile.webp) + +#### `7` Mobile Device Adaptation + +We have carried out a series of optimization designs for mobile devices to enhance the user's mobile experience. Currently, we are iterating on the mobile user experience to achieve smoother and more intuitive interactions. If you have any suggestions or ideas, we welcome you to provide feedback through GitHub Issues or Pull Requests. + +> 🚧 Additional snapshots and demonstrations are being progressively added... + +
+ +[![][back-to-top]](#readme-top) + +
+ +## ⚡️ Performance + +> \[!NOTE] +> +> The complete list of reports can be found in the [📘 Lighthouse Reports](https://github.com/lobehub/lobe-chat/wiki/Lighthouse) + +| Desktop | Mobile | +| :-----------------------------------------: | :----------------------------------------: | +| ![][chat-desktop] | ![][chat-mobile] | +| [📑 Lighthouse Report][chat-desktop-report] | [📑 Lighthouse Report][chat-mobile-report] | + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 🛳 Self Hosting + +LobeChat provides Self-Hosted Version with Vercel and [Docker Image][docker-release-link]. This allows you to deploy your own chatbot within a few minutes without any prior knowledge. + +### `A` Deploying with Vercel + +If you want to deploy this service yourself on Vercel, you can follow these steps: + +- Prepare your [OpenAI API Key](https://platform.openai.com/account/api-keys). +- Click the button below to start deployment: Deploy with Vercel. Log in directly with your GitHub account, and remember to fill in the `OPENAI_API_KEY`(required) and `ACCESS_CODE` (recommended) on the environment variable section. +- After deployment, you can start using it. +- Bind a custom domain (optional): The DNS of the domain assigned by Vercel is polluted in some areas; binding a custom domain can connect directly. + +
+ +[![][deploy-button-image]][deploy-link] + +
+ +#### Keep Updated + +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 detect updates accurately. + +> \[!TIP] +> +> We suggest you redeploy using the following steps, [📘 Maintaining Updates with LobeChat Self-Deployment](https://github.com/lobehub/lobe-chat/wiki/Upstream-Sync). + +
+ +### `B` Deploying with Docker + +[![][docker-release-shield]][docker-release-link] +[![][docker-size-shield]][docker-size-link] +[![][docker-pulls-shield]][docker-pulls-link] + +We provide a Docker image for deploying the LobeChat service on your own private device. Use the following command to start the LobeChat service: + +```fish +$ docker run -d -p 3210:3210 \ + -e OPENAI_API_KEY=sk-xxxx \ + -e ACCESS_CODE=lobe66 \ + lobehub/lobe-chat +``` + +> \[!TIP] +> +> If you need to use the OpenAI service through a proxy, you can configure the proxy address using the `OPENAI_PROXY_URL` environment variable: + +```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 \ + lobehub/lobe-chat +``` + +> \[!NOTE] +> +> For detailed instructions on deploying with Docker, please refer to the [📘 Docker Deployment Guide](https://github.com/lobehub/lobe-chat/wiki/Docker-Deployment) + +
+ +### Environment Variable + +This project provides some additional configuration items set with environment variables: + +| Environment Variable | Required | Description | Example | +| ------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | +| `OPENAI_API_KEY` | Yes | This is the API key you apply on the OpenAI account page | `sk-xxxxxx...xxxxxx` | +| `OPENAI_PROXY_URL` | No | If you manually configure the OpenAI interface proxy, you can use this configuration item to override the default OpenAI API request base URL | `https://api.chatanywhere.cn/v1`
The default value is
`https://api.openai.com/v1` | +| `OPENAI_FUNCTION_REGIONS` | No | When you deploy Lobe-Chat using Vercel and need to specify the region for the Edge Function that handles requests to the OpenAI API, you can use this configuration. The value should be a comma-separated array of strings. | `iad1,sfo1` | +| `ACCESS_CODE` | No | Add a password to access this service; the password should be a 6-digit number or letter | `awCT74` or `e3@09!` | + +> \[!NOTE] +> +> The complete list of environment variables can be found in the [📘 Environment Variables](https://github.com/lobehub/lobe-chat/wiki/Environment-Variable) + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 📦 Ecosystem + +| NPM | Repository | Description | Version | +| ------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | +| [@lobehub/ui][lobe-ui-link] | [lobehub/lobe-ui][lobe-ui-github] | Lobe UI is an open-source UI component library dedicated to building AIGC web applications. | [![][lobe-ui-shield]][lobe-ui-link] | +| [@lobehub/tts][lobe-tts-link] | [lobehub/lobe-tts][lobe-tts-github] | Lobe TTS is a high-quality & reliable TTS/STT React Hooks library | [![][lobe-tts-shield]][lobe-tts-link] | +| [@lobehub/lint][lobe-lint-link] | [lobehub/lobe-lint][lobe-lint-github] | LobeLint provides configurations for ESlint, Stylelint, Commitlint, Prettier, Remark, and Semantic Release for LobeHub. | [![][lobe-lint-shield]][lobe-lint-link] | +| @lobehub/assets | [lobehub/assets][lobe-assets-github] | Logo assets, favicons, webfonts for LobeHub. | | + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 🧩 Plugins + +Plugins provide a means to extend the [Function Calling][fc-link] capabilities of LobeChat. They can be used to introduce new function calls and even new ways to render message results. If you are interested in plugin development, please refer to our [📘 Plugin Development Guide](https://github.com/lobehub/lobe-chat/wiki/Plugin-Development) in the Wiki. + +- [lobe-chat-plugins][lobe-chat-plugins]: This is the plugin index for LobeChat. It accesses index.json from this repository to display a list of available plugins for LobeChat to the user. +- [chat-plugin-template][chat-plugin-template]: This is the plugin template for LobeChat plugin development. +- [@lobehub/chat-plugin-sdk][chat-plugin-sdk]: The LobeChat Plugin SDK assists you in creating exceptional chat plugins for Lobe Chat. +- [@lobehub/chat-plugins-gateway][chat-plugins-gateway]: The LobeChat Plugins Gateway is a backend service that provides a gateway for LobeChat plugins. We deploy this service using Vercel. The primary API POST /api/v1/runner is deployed as an Edge Function. + +> \[!NOTE] +> +> The plugin system is currently undergoing major development. You can learn more in the following issues: +> +> - [x] [**Plugin Phase 1**](https://github.com/lobehub/lobe-chat/issues/73): Implement separation of the plugin from the main body, split the plugin into an independent repository for maintenance, and realize dynamic loading of the plugin. +> - [x] [**Plugin Phase 2**](https://github.com/lobehub/lobe-chat/issues/97): The security and stability of the plugin's use, more accurately presenting abnormal states, the maintainability of the plugin architecture, and developer-friendly. +> - [ ] [**Plugin Phase 3**](https://github.com/lobehub/lobe-chat/issues/149): Higher-level and more comprehensive customization capabilities, support for plugin authentication, and examples. + +
+ +[![][back-to-top]](#readme-top) + +
+ +## ⌨️ Local Development + +You can use GitHub Codespaces for online development: + +[![][codespaces-shield]][codespaces-link] + +Or clone it for local development: + +[![][bun-shield]][bun-link] + +```fish +$ git clone https://github.com/lobehub/lobe-chat.git +$ cd lobe-chat +$ bun install +$ bun dev +``` + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 🤝 Contributing + +Contributions of all types are more than welcome; if you are interested in contributing code, feel free to check out our GitHub [Issues][github-issues-link] and [Projects][github-project-link] to get stuck in to show us what you’re made of. + +[![][pr-welcome-shield]][pr-welcome-link] +[![][submit-agents-shield]][submit-agents-link] +[![][submit-plugin-shield]][submit-plugin-link] + +[![][contributors-contrib]][contributors-link] + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 🔗 More Products + +- **[🤯 Lobe Theme][lobe-theme]:** The modern theme for Stable Diffusion WebUI, exquisite interface design, highly customizable UI, and efficiency-boosting features. +- **[🌏 Lobe i18n][lobe-i18n] :** Lobe i18n is an automation tool for the i18n (internationalization) translation process, powered by ChatGPT. It supports features such as automatic splitting of large files, incremental updates, and customization options for the OpenAI model, API proxy, and temperature. +- **[💌 Lobe Commit][lobe-commit]:** Lobe Commit is a CLI tool that leverages Langchain/ChatGPT to generate Gitmoji-based commit messages. + +
+ +[![][back-to-top]](#readme-top) + +
+ +--- + +

📝 License

+ +[![][fossa-license-shield]][fossa-license-link] + +
+ +Copyright © 2023 [LobeHub][profile-link].
+This project is [MIT](./LICENSE) licensed. + + + +[back-to-top]: https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square +[bun-link]: https://bun.sh +[bun-shield]: https://img.shields.io/badge/-speedup%20with%20bun-black?logo=bun&style=for-the-badge +[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 +[chat-plugin-sdk]: https://github.com/lobehub/chat-plugin-sdk +[chat-plugin-template]: https://github.com/lobehub/chat-plugin-template +[chat-plugins-gateway]: https://github.com/lobehub/chat-plugins-gateway +[codespaces-link]: https://codespaces.new/lobehub/lobe-chat +[codespaces-shield]: https://github.com/codespaces/badge.svg +[contributors-contrib]: https://contrib.rocks/image?repo=lobehub/lobe-chat +[contributors-link]: https://github.com/lobehub/lobe-chat/graphs/contributors +[deploy-button-image]: https://vercel.com/button +[deploy-link]: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat&env=OPENAI_API_KEY&envDescription=Find%20your%20OpenAI%20API%20Key%20by%20click%20the%20right%20Learn%20More%20button.&envLink=https%3A%2F%2Fplatform.openai.com%2Faccount%2Fapi-keys&project-name=lobe-chat&repository-name=lobe-chat +[discord-link]: https://discord.gg/AYFPHvv2jT +[discord-shield]: https://img.shields.io/discord/1127171173982154893?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square +[discord-shield-badge]: https://img.shields.io/discord/1127171173982154893?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge +[docker-pulls-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-pulls-shield]: https://img.shields.io/docker/pulls/lobehub/lobe-chat?color=45cc11&labelColor=black&style=flat-square +[docker-release-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-release-shield]: https://img.shields.io/docker/v/lobehub/lobe-chat?color=369eff&label=docker&labelColor=black&logo=docker&logoColor=white&style=flat-square +[docker-size-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-size-shield]: https://img.shields.io/docker/image-size/lobehub/lobe-chat?color=369eff&labelColor=black&style=flat-square +[fc-link]: https://sspai.com/post/81986 +[fossa-license-link]: https://app.fossa.com/projects/git%2Bgithub.com%2Flobehub%2Flobe-chat +[fossa-license-shield]: https://app.fossa.com/api/projects/git%2Bgithub.com%2Flobehub%2Flobe-chat.svg?type=large +[github-action-release-link]: https://github.com/actions/workflows/lobehub/lobe-chat/release.yml +[github-action-release-shield]: https://img.shields.io/github/actions/workflow/status/lobehub/lobe-chat/release.yml?label=release&labelColor=black&logo=githubactions&logoColor=white&style=flat-square +[github-action-test-link]: https://github.com/actions/workflows/lobehub/lobe-chat/test.yml +[github-action-test-shield]: https://img.shields.io/github/actions/workflow/status/lobehub/lobe-chat/test.yml?label=test&labelColor=black&logo=githubactions&logoColor=white&style=flat-square +[github-contributors-link]: https://github.com/lobehub/lobe-chat/graphs/contributors +[github-contributors-shield]: https://img.shields.io/github/contributors/lobehub/lobe-chat?color=c4f042&labelColor=black&style=flat-square +[github-forks-link]: https://github.com/lobehub/lobe-chat/network/members +[github-forks-shield]: https://img.shields.io/github/forks/lobehub/lobe-chat?color=8ae8ff&labelColor=black&style=flat-square +[github-issues-link]: https://github.com/lobehub/lobe-chat/issues +[github-issues-shield]: https://img.shields.io/github/issues/lobehub/lobe-chat?color=ff80eb&labelColor=black&style=flat-square +[github-license-link]: https://github.com/lobehub/lobe-chat/blob/main/LICENSE +[github-license-shield]: https://img.shields.io/github/license/lobehub/lobe-chat?color=white&labelColor=black&style=flat-square +[github-project-link]: https://github.com/lobehub/lobe-chat/projects +[github-release-link]: https://github.com/lobehub/lobe-chat/releases +[github-release-shield]: https://img.shields.io/github/v/release/lobehub/lobe-chat?color=369eff&labelColor=black&logo=github&style=flat-square +[github-releasedate-link]: https://github.com/lobehub/lobe-chat/releases +[github-releasedate-shield]: https://img.shields.io/github/release-date/lobehub/lobe-chat?labelColor=black&style=flat-square +[github-stars-link]: https://github.com/lobehub/lobe-chat/network/stargazers +[github-stars-shield]: https://img.shields.io/github/stars/lobehub/lobe-chat?color=ffcb47&labelColor=black&style=flat-square +[github-wiki-link]: https://github.com/lobehub/lobe-chat/wiki +[issues-link]: https://img.shields.io/github/issues/lobehub/lobe-chat.svg?style=flat +[lobe-assets-github]: https://github.com/lobehub/lobe-assets +[lobe-chat-plugins]: https://github.com/lobehub/lobe-chat-plugins +[lobe-commit]: https://github.com/lobehub/lobe-commit/tree/master/packages/lobe-commit +[lobe-i18n]: https://github.com/lobehub/lobe-commit/tree/master/packages/lobe-i18n +[lobe-lint-github]: https://github.com/lobehub/lobe-lint +[lobe-lint-link]: https://www.npmjs.com/package/@lobehub/lint +[lobe-lint-shield]: https://img.shields.io/npm/v/@lobehub/lint?color=369eff&labelColor=black&logo=npm&logoColor=white&style=flat-square +[lobe-theme]: https://github.com/lobehub/sd-webui-lobe-theme +[lobe-tts-github]: https://github.com/lobehub/lobe-tts +[lobe-tts-link]: https://www.npmjs.com/package/@lobehub/tts +[lobe-tts-shield]: https://img.shields.io/npm/v/@lobehub/tts?color=369eff&labelColor=black&logo=npm&logoColor=white&style=flat-square +[lobe-ui-github]: https://github.com/lobehub/lobe-ui +[lobe-ui-link]: https://www.npmjs.com/package/@lobehub/ui +[lobe-ui-shield]: https://img.shields.io/npm/v/@lobehub/ui?color=369eff&labelColor=black&logo=npm&logoColor=white&style=flat-square +[pr-welcome-link]: https://github.com/lobehub/lobe-chat/pulls +[pr-welcome-shield]: https://img.shields.io/badge/🤯_pr_welcome-%E2%86%92-ffcb47?labelColor=black&style=for-the-badge +[profile-link]: https://github.com/lobehub +[share-reddit-link]: https://www.reddit.com/submit?title=Check%20this%20GitHub%20repository%20out%20%F0%9F%A4%AF%20LobeChat%20-%20An%20open-source%2C%20extensible%20%28Function%20Calling%29%2C%20high-performance%20chatbot%20framework.%20It%20supports%20one-click%20free%20deployment%20of%20your%20private%20ChatGPT%2FLLM%20web%20application.%20%23chatbot%20%23chatGPT%20%23openAI&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat +[share-reddit-shield]: https://img.shields.io/badge/-share%20on%20reddit-black?labelColor=black&logo=reddit&logoColor=white&style=flat-square +[share-telegram-link]: https://t.me/share/url"?text=Check%20this%20GitHub%20repository%20out%20%F0%9F%A4%AF%20LobeChat%20-%20An%20open-source%2C%20extensible%20%28Function%20Calling%29%2C%20high-performance%20chatbot%20framework.%20It%20supports%20one-click%20free%20deployment%20of%20your%20private%20ChatGPT%2FLLM%20web%20application.%20%23chatbot%20%23chatGPT%20%23openAI&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat +[share-telegram-shield]: https://img.shields.io/badge/-share%20on%20telegram-black?labelColor=black&logo=telegram&logoColor=white&style=flat-square +[share-weibo-link]: http://service.weibo.com/share/share.php?sharesource=weibo&title=Check%20this%20GitHub%20repository%20out%20%F0%9F%A4%AF%20LobeChat%20-%20An%20open-source%2C%20extensible%20%28Function%20Calling%29%2C%20high-performance%20chatbot%20framework.%20It%20supports%20one-click%20free%20deployment%20of%20your%20private%20ChatGPT%2FLLM%20web%20application.%20%23chatbot%20%23chatGPT%20%23openAI&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat +[share-weibo-shield]: https://img.shields.io/badge/-share%20on%20weibo-black?labelColor=black&logo=sinaweibo&logoColor=white&style=flat-square +[share-whatsapp-link]: https://api.whatsapp.com/send?text=Check%20this%20GitHub%20repository%20out%20%F0%9F%A4%AF%20LobeChat%20-%20An%20open-source%2C%20extensible%20%28Function%20Calling%29%2C%20high-performance%20chatbot%20framework.%20It%20supports%20one-click%20free%20deployment%20of%20your%20private%20ChatGPT%2FLLM%20web%20application.%20https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat%20%23chatbot%20%23chatGPT%20%23openAI +[share-whatsapp-shield]: https://img.shields.io/badge/-share%20on%20whatsapp-black?labelColor=black&logo=whatsapp&logoColor=white&style=flat-square +[share-x-link]: https://x.com/intent/tweet?hashtags=chatbot%2CchatGPT%2CopenAI&text=Check%20this%20GitHub%20repository%20out%20%F0%9F%A4%AF%20LobeChat%20-%20An%20open-source%2C%20extensible%20%28Function%20Calling%29%2C%20high-performance%20chatbot%20framework.%20It%20supports%20one-click%20free%20deployment%20of%20your%20private%20ChatGPT%2FLLM%20web%20application.&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat +[share-x-shield]: https://img.shields.io/badge/-share%20on%20x-black?labelColor=black&logo=x&logoColor=white&style=flat-square +[submit-agents-link]: https://github.com/lobehub/lobe-chat-agents +[submit-agents-shield]: https://img.shields.io/badge/🤖/🏪_submit_agent-%E2%86%92-c4f042?labelColor=black&style=for-the-badge +[submit-plugin-link]: https://github.com/lobehub/lobe-chat-plugins +[submit-plugin-shield]: https://img.shields.io/badge/🧩/🏪_submit_plugin-%E2%86%92-95f3d9?labelColor=black&style=for-the-badge +[vercel-link]: https://chat-preview.lobehub.com +[vercel-shield]: https://img.shields.io/website?down_message=offline&label=vercel&labelColor=black&logo=vercel&style=flat-square&up_message=online&url=https%3A%2F%2Fchat-preview.lobehub.com +[vercel-shield-badge]: https://img.shields.io/website?down_message=offline&label=try%20lobechat&labelColor=black&logo=vercel&style=for-the-badge&up_message=online&url=https%3A%2F%2Fchat-preview.lobehub.com diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000000000..98cc29477b8e9 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,568 @@ + + +
+ + + + + +

Lobe Chat

+ +LobeChat 是开源的高性能聊天机器人框架,支持语音合成、多模态、可扩展的([Function Call][fc-link])插件系统。
支持一键免费部署私人 ChatGPT/LLM 网页应用程序。 + +[English](./README.md) · **简体中文** · [更新日志](./CHANGELOG.md) · [文档][github-wiki-link] · [报告问题][github-issues-link] · [请求功能][github-issues-link] + + + +[![][github-release-shield]][github-release-link] +[![][docker-release-shield]][docker-release-link] +[![][vercel-shield]][vercel-link] +[![][discord-shield]][discord-link]
+[![][github-action-test-shield]][github-action-test-link] +[![][github-action-release-shield]][github-action-release-link] +[![][github-releasedate-shield]][github-releasedate-link]
+[![][github-contributors-shield]][github-contributors-link] +[![][github-forks-shield]][github-forks-link] +[![][github-stars-shield]][github-stars-link] +[![][github-issues-shield]][github-issues-link] +[![][github-license-shield]][github-license-link] + +**分享 LobeChat 给你的好友** + +[![][share-x-shield]][share-x-link] +[![][share-telegram-shield]][share-telegram-link] +[![][share-whatsapp-shield]][share-whatsapp-link] +[![][share-reddit-shield]][share-reddit-link] +[![][share-weibo-shield]][share-weibo-link] + +![](https://gw.alipayobjects.com/zos/kitchen/RKnWrrfuMl/welcome.webp) + +
+ +
+目录树 + +#### TOC + +- [👋🏻 开始使用 & 交流](#-开始使用--交流) +- [✨ 功能特性](#-功能特性) +- [📸 快照预览](#-快照预览) +- [⚡️ 性能测试](#️-性能测试) +- [🛳 开箱即用](#-开箱即用) + - [`A` 使用 Vercel 部署](#a-使用-vercel-部署) + - [`B` 使用 Docker 部署](#b-使用-docker-部署) + - [环境变量](#环境变量) +- [📦 生态系统](#-生态系统) +- [🧩 插件体系](#-插件体系) +- [⌨️ 本地开发](#️-本地开发) +- [🤝 参与贡献](#-参与贡献) +- [🔗 更多工具](#-更多工具) + +#### + +
+ +
+ +## 👋🏻 开始使用 & 交流 + +我们是一群充满热情的设计工程师,希望为 AIGC 提供现代化的设计组件和工具,并以开源的方式分享,以促进它们在更广泛的社区中的发展和采用,LobeChat 目前正在积极开发中,有需求或者问题,欢迎提交 [issues][issues-link] + +| [![][vercel-shield-badge]][vercel-link] | 无需安装或注册!访问我们的网站,快速体验 | +| :---------------------------------------- | :--------------------------------------------------------------------------- | +| [![][discord-shield-badge]][discord-link] | 加入我们的 Discord 社区!这是你可以与开发者和其他 LobeHub 热衷用户交流的地方 | + +> \[!IMPORTANT] +> +> **收藏项目**,你将从 GitHub 上无延迟地接收所有发布通知~⭐️ + +![](https://gw.alipayobjects.com/zos/kitchen/0hcO8QiU9c/star.webp) + +
Star History + + + + +
+ +## ✨ 功能特性 + +- [x] 💎 **精致 UI 设计**:经过精心设计的界面,具有优雅的外观和流畅的交互效果,支持亮暗色主题,适配移动端。支持 PWA,提供更加接近原生应用的体验。 +- [x] 🗣️ **流畅的对话体验**:流式响应带来流畅的对话体验,并且支持完整的 Markdown 渲染,包括代码高亮、LaTex 公式、Mermaid 流程图等。 +- [x] 🧩 **支持插件与自定义插件开发**:会话支持插件扩展,用户可以安装和使用各种插件,例如搜索引擎、网页提取等,同时也支持自定义插件的开发,满足自定义需求。 +- [x] 🤖 **自定义助手角色**:用户可以根据自己的需求创建、分享和调试个性化的对话助手角色,提供更加灵活和个性化的对话功能 . +- [x] 🏬 **角色市场**:提供角色市场,用户可以在市场上选择自己喜欢的对话助手角色,丰富对话的内容和风格。 +- [x] 👁️ **视觉识别**: 通过集成视觉识别能力,AI 助手现在可以分析和理解对话过程中提供的图像。这使得对话代理能够进行更具交互性和上下文感知的对话,根据视觉内容提供相关和准确的回答。 +- [ ] 📢 **语音会话**: 我们支持文本转语音技术,允许用户与对话代理进行语音对话。这个功能通过提供更自然和沉浸式的对话环境来增强用户体验。用户可以选择多种声音并调整语速以适应自己的偏好。 + +--- + +除了上述功能特性以外,我们的底层技术方案为你带来了更多使用保障: + +- [x] 💨 **快速部署**:使用 Vercel 平台或者我们的 Docker 镜像,只需点击一键部署按钮,即可在 1 分钟内完成部署,无需复杂的配置过程。 +- [x] 🔒 **隐私安全**:所有数据保存在用户浏览器本地,保证用户的隐私安全。 +- [x] 🌐 **自定义域名**:如果用户拥有自己的域名,可以将其绑定到平台上,方便在任何地方快速访问对话助手。 + +> \[!NOTE] +> +> 你可以在 Projects 中找到我们后续的 [Roadmap][github-project-link] 计划 + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 📸 快照预览 + +#### `1` GPT 视觉认知 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/284072129-382bdf30-e3d6-4411-b5a0-249710b8ba08.png) + +LobeChat 已经支持 OpenAI 最新的 [`gpt-4-vsion`](https://platform.openai.com/docs/guides/vision) 支持视觉识别的模型,这是一个具备视觉识别能力的多模态智能。 +用户可以轻松上传图片或者拖拽图片到对话框中,助手将能够识别图片内容,并在此基础上进行智能对话,构建更智能、更多元化的聊天场景。 + +这一特性打开了新的互动方式,使得交流不再局限于文字,而是可以涵盖丰富的视觉元素。无论是日常使用中的图片分享,还是在特定行业内的图像解读,助手都能提供出色的对话体验。 + +
+ +[![][back-to-top]](#readme-top) + +
+ +#### `2` TTS & STT 语音会话 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/284072124-c9853d8d-f1b5-44a8-a305-45ebc0f6d19a.png) + +LobeChat 支持文字转语音(Text-to-Speech,TTS)和语音转文字(Speech-to-Text,STT)技术,我们的应用能够将文本信息转化为清晰的语音输出,用户可以像与真人交谈一样与我们的对话代理进行交流。 +用户可以从多种声音中选择,给助手搭配合适的音源。 同时,对于那些倾向于听觉学习或者想要在忙碌中获取信息的用户来说,TTS 提供了一个极佳的解决方案。 + +在 LobeChat 中,我们精心挑选了一系列高品质的声音选项 (OpenAI Audio, Microsoft Edge Speech),以满足不同地域和文化背景用户的需求。用户可以根据个人喜好或者特定场景来选择合适的语音,从而获得个性化的交流体验。 + +> \[!NOTE] +> +> 我们在实现该功能过程中,发现市面上并没有一款很好的 TTS 前端库。因此我们实现上耗费了很多精力,包括数据转换、音频进度管理、语音可视化等。 +> 于是我们决定把这套实现打磨并开源出来,希望能帮助到想要实现 TTS 的开发者们,[@lobehub/tts][lobe-tts-link] 是一个使用 TS 语言开发的,高质量 TTS 工具包,支持在服务端和浏览器中使用。 +> +> - **服务端**:只要使用 15 行代码,即可实现对标 OpenAI TTS 服务的高质量语音生成能力。目前支持 EdgeSpeechTTS 与 MicrosoftTTS 与 OpenAITTS、OpenAISTT。 +> - **浏览器**:提供了高质量的 React Hooks 与可视化音频组件,支持加载、播放、暂停、拖动时间轴等常用功能,且提供了非常丰富的音轨样式调整能力。 + +
+ +[![][back-to-top]](#readme-top) + +
+ +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/268670883-33c43a5c-a512-467e-855c-fa299548cce5.png) + +#### `3` Function Calling 插件系统 + +LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地增强了 ChatGPT 的实用性和灵活性。通过利用插件,ChatGPT 能够实现实时信息的获取和处理,例如自动获取最新新闻头条,为用户提供即时且相关的资讯。 +此外,这些插件不仅局限于新闻聚合,还可以扩展到其他实用的功能,如快速检索文档、获取电商平台数据、以及其他各式各样的第三方服务。 + +> \[!TIP] +> +> 为了帮助开发者更好地参与到这个生态中来,我们在 [🧩 插件体系](#-插件体系) 部分提供了全面的开发资源。 +> 这包括详尽的组件开发文档、功能齐全的软件开发工具包(SDK),以及样板文件,这些都是为了简化开发过程,降低开发者的入门门槛。 + +> \[!IMPORTANT] +> +> 我们欢迎开发者利用这些资源,发挥创造力,编写出功能丰富、用户友好的插件。通过共同的努力,我们可以不断扩展聊天应用的功能界限,探索一个更加智能、高效的创造力平台。 + + + + + +| 官方插件 | 仓库 | 插件描述 | +| ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | -------------------------------------------- | +| [时钟时间](https://chat-preview.lobehub.com/settings/agent)
By **LobeHub** on **2023-11-01** | [lobehub/chat-plugin-clock-time](https://github.com/lobehub/chat-plugin-clock-time) | 显示一个时钟来展示当前时间
`时钟` `时间` | +| [网站爬虫](https://chat-preview.lobehub.com/settings/agent)
By **LobeHub** on **2023-08-17** | [lobehub/chat-plugin-web-crawler](https://github.com/lobehub/chat-plugin-web-crawler) | 从网页链接中提取内容
`网页` `内容爬取器` | +| [搜索引擎](https://chat-preview.lobehub.com/settings/agent)
By **LobeHub** on **2023-08-15** | [lobehub/chat-plugin-search-engine](https://github.com/lobehub/chat-plugin-search-engine) | 查询搜索引擎以获取信息
`网络` `搜索` | +| [实时天气](https://chat-preview.lobehub.com/settings/agent)
By **LobeHub** on **2023-08-12** | [lobehub/chat-plugin-realtime-weather](https://github.com/lobehub/chat-plugin-realtime-weather) | 获取实时天气信息
`天气` `实时` | + +> 📊 Total plugins: [**4**](https://github.com/lobehub/lobe-chat-plugins) + + + +
+ +[![][back-to-top]](#readme-top) + +
+ +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/268670869-f1ffbf66-42b6-42cf-a937-9ce1f8328514.png) + +#### `4` 助手市场 + +在 LobeChat 的助手市场中,创作者们可以发现一个充满活力和创新的社区,它汇聚了众多精心设计的助手,这些助手不仅在工作场景中发挥着重要作用,也在学习过程中提供了极大的便利。 +我们的市场不仅是一个展示平台,更是一个协作的空间。在这里,每个人都可以贡献自己的智慧,分享个人开发的助手。 + +> \[!TIP] +> +> 通过 [🤖/🏪 提交助手][submit-agents-link] ,你可以轻松地将你的助手作品提交到我们的平台。我们特别强调的是,LobeChat 建立了一套精密的自动化国际化(i18n)工作流程, 它的强大之处在于能够无缝地将你的助手转化为多种语言版本。 +> 这意味着,不论你的用户使用何种语言,他们都能无障碍地体验到你的助手。 + +> \[!IMPORTANT] +> +> 我欢迎所有用户加入这个不断成长的生态系统,共同参与到助手的迭代与优化中来。共同创造出更多有趣、实用且具有创新性的助手,进一步丰富助手的多样性和实用性。 + + + +| 最近新增 | 助手说明 | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [JS 代码质量优化](https://chat-preview.lobehub.com/market?agent=js-code-quality)
By **[canisminor1990](https://github.com/canisminor1990)** on **2023-11-22** | 致力于干净和优雅的代码重构
`重构` `代码优化` `代码质量` | +| [LobeChat 测试工程师](https://chat-preview.lobehub.com/market?agent=lobe-chat-unit-test-dev)
By **[arvinxx](https://github.com/arvinxx)** on **2023-11-22** | 擅长编写前端自动化测试,特别是 TypeScript 应用的全面测试覆盖。熟练使用 Vitest 测试框架,具备深入的测试原理和策略理解。
`自动化测试` `测试` `lobe-chat` `前端` | +| [问答文档转换专家](https://chat-preview.lobehub.com/market?agent=q-a-helper)
By **[barryWang12138](https://github.com/barryWang12138)** on **2023-11-22** | 请提供您的文档内容,我将根据您的要求进行分段和清洗,并按照规范的格式回答。
`q-a` `文档` | +| [真实的老友](https://chat-preview.lobehub.com/market?agent=ai-0x0-old-friends)
By **[mushan0x0](https://github.com/mushan0x0)** on **2023-11-21** | 可以跟我谈论一切,我可以给你作为老友的一些想法和建议,放轻松
`友情` `幽默` `真实` `模拟` | + +> 📊 Total agents: [**52** ](https://github.com/lobehub/lobe-chat-agents) + + + +
+ +[![][back-to-top]](#readme-top) + +
+ +![](https://gw.alipayobjects.com/zos/kitchen/69x6bllkX3/pwa.webp) + +#### `5` PWA 渐进式 Web 应用 + +我们利深知在当今多设备环境下为用户提供无缝体验的重要性。为此,我们采用了渐进式 Web 应用 [PWA](https://support.google.com/chrome/answer/9658361) 技术, +这是一种能够将网页应用提升至接近原生应用体验的现代 Web 技术。通过 PWA,LobeChat 能够在桌面和移动设备上提供高度优化的用户体验,同时保持轻量级和高性能的特点。 +在视觉和感觉上,我们也经过精心设计,以确保它的界面与原生应用无差别,提供流畅的动画、响应式布局和适配不同设备的屏幕分辨率。 + +> \[!NOTE] +> +> 若您未熟悉 PWA 的安装过程,您可以按照以下步骤将 LobeChat 添加为您的桌面应用(也适用于移动设备): +> +> - 在电脑上运行 Chrome 或 Edge 浏览器 . +> - 访问 LobeChat 网页 . +> - 在地址栏的右上角,单击 安装 图标 . +> - 根据屏幕上的指示完成 PWA 的安装 . + +
+ +[![][back-to-top]](#readme-top) + +
+ +![](https://gw.alipayobjects.com/zos/kitchen/pvus1lo%26Z7/darkmode.webp) + +#### `6` 主题模式选择 + +作为设计工程师出身 LobeChat 在界面设计上十分考虑用户的个性化体验,因此引入了灵活多变的主题模式,其中包括日间的亮色模式和夜间的深色模式。 +除了主题模式的切换,提供了一系列的颜色定制选项,允许用户根据自己的喜好来调整应用的主题色彩。无论是想要沉稳的深蓝,还是希望活泼的桃粉,或者是专业的灰白,用户都能够在 LobeChat 中找到匹配自己风格的颜色选择。 + +> \[!TIP] +> +> 默认配置能够智能地识别用户系统的颜色模式,自动进行主题切换,以确保应用界面与操作系统保持一致的视觉体验。对于喜欢手动调控细节的用户,LobeChat 同样提供了直观的设置选项,针对聊天场景也提供了对话气泡模式和文档模式的选择。 + +
+ +[![][back-to-top]](#readme-top) + +
+ +![](https://gw.alipayobjects.com/zos/kitchen/R441AuFS4W/mobile.webp) + +#### `7` 移动设备适配 + +针对移动设备进行了一系列的优化设计,以提升用户的移动体验。目前,我们正在对移动端的用户体验进行版本迭代,以实现更加流畅和直观的交互。如果您有任何建议或想法,我们非常欢迎您通过 GitHub Issues 或者 Pull Requests 提供反馈。 + +> 🚧 更多快照和演示正在陆续添加中... + +
+ +[![][back-to-top]](#readme-top) + +
+ +## ⚡️ 性能测试 + +> \[!NOTE] +> +> 完整测试报告可见 [📘 Lighthouse 性能测试](https://github.com/lobehub/lobe-chat/wiki/Lighthouse.zh-CN) + +| Desktop | Mobile | +| :-------------------------------------------: | :------------------------------------------: | +| ![][chat-desktop] | ![][chat-mobile] | +| [📑 Lighthouse 测试报告][chat-desktop-report] | [📑 Lighthouse 测试报告][chat-mobile-report] | + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 🛳 开箱即用 + +LobeChat 提供了 Vercel 的 自托管版本 和 [Docker 镜像][docker-release-link],这使你可以在几分钟内构建自己的聊天机器人,无需任何基础知识。 + +
+ +### `A` 使用 Vercel 部署 + +如果想在 Vercel 上部署该服务,可以按照以下步骤进行操作: + +- 准备好你的 [OpenAI API Key](https://platform.openai.com/account/api-keys) 。 +- 点击下方按钮开始部署: Deploy with Vercel,直接使用 GitHub 账号登录即可,记得在环境变量页填入 `OPENAI_API_KEY` (必填) and `ACCESS_CODE`(推荐); +- 部署完毕后,即可开始使用; +- 绑定自定义域名(可选):Vercel 分配的域名 DNS 在某些区域被污染了,绑定自定义域名即可直连。 + +
+ +[![][deploy-button-image]][deploy-link] + +
+ +#### 保持更新 + +如果你根据 README 中的一键部署步骤部署了自己的项目,你可能会发现总是被提示 “有可用更新”。这是因为 Vercel 默认为你创建新项目而非 fork 本项目,这将导致无法准确检测更新。 + +> \[!TIP] +> +> 我们建议按照 [📘 LobeChat 自部署保持更新](https://github.com/lobehub/lobe-chat/wiki/Upstream-Sync.zh-CN) 步骤重新部署。 + +
+ +### `B` 使用 Docker 部署 + +[![][docker-release-shield]][docker-release-link] +[![][docker-size-shield]][docker-size-link] +[![][docker-pulls-shield]][docker-pulls-link] + +我们提供了 Docker 镜像,供你在自己的私有设备上部署 LobeChat 服务。使用以下命令即可使用一键启动 LobeChat 服务: + +```fish +$ docker run -d -p 3210:3210 \ + -e OPENAI_API_KEY=sk-xxxx \ + -e ACCESS_CODE=lobe66 \ + lobehub/lobe-chat +``` + +> \[!TIP] +> +> 如果你需要通过代理使用 OpenAI 服务,你可以使用 `OPENAI_PROXY_URL` 环境变量来配置代理地址: + +```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 \ + lobehub/lobe-chat +``` + +> \[!NOTE] +> +> 有关 Docker 部署的详细说明,详见 [📘 使用 Docker 部署](https://github.com/lobehub/lobe-chat/wiki/Docker-Deployment.zh-CN) + +
+ +### 环境变量 + +本项目提供了一些额外的配置项,使用环境变量进行设置: + +| 环境变量 | 类型 | 描述 | 示例 | +| ------------------------- | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | +| `OPENAI_API_KEY` | 必选 | 这是你在 OpenAI 账户页面申请的 API 密钥 | `sk-xxxxxx...xxxxxx` | +| `OPENAI_PROXY_URL` | 可选 | 如果你手动配置了 OpenAI 接口代理,可以使用此配置项来覆盖默认的 OpenAI API 请求基础 URL | `https://api.chatanywhere.cn/v1`
默认值:
`https://api.openai.com/v1` | +| `OPENAI_FUNCTION_REGIONS` | 可选 | 当你使用 Vercel 部署 Lobe-Chat,而且有需求指定响应调用 OpenAI 接口的请求的 Edge Function 的 Region 时,可以使用该配置进行配置,该值的类型为逗号分隔的字符串数组 | `iad1,sfo1` | +| `ACCESS_CODE` | 可选 | 添加访问此服务的密码,密码应为 6 位数字或字母 | `awCT74` 或 `e3@09!` | + +> \[!NOTE] +> +> 完整环境变量可见 [📘环境变量](https://github.com/lobehub/lobe-chat/wiki/Environment-Variable.zh-CN) + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 📦 生态系统 + +| NPM | 仓库 | 描述 | 版本 | +| ------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------- | +| [@lobehub/ui][lobe-ui-link] | [lobehub/lobe-ui][lobe-ui-github] | Lobe UI 是一个专为构建 AIGC 网页应用程序而设计的开源 UI 组件库。 | [![][lobe-ui-shield]][lobe-ui-link] | +| [@lobehub/tts][lobe-tts-link] | [lobehub/lobe-tts][lobe-tts-github] | Lobe TTS 是一个专为 TTS/STT 建设的语音合成 / 识别 React Hooks 库 | [![][lobe-tts-shield]][lobe-tts-link] | +| [@lobehub/lint][lobe-lint-link] | [lobehub/lobe-lint][lobe-lint-github] | LobeLint 为 LobeHub 提供 ESlint,Stylelint,Commitlint,Prettier,Remark 和 Semantic Release 的配置。 | [![][lobe-lint-shield]][lobe-lint-link] | +| @lobehub/assets | [lobehub/assets][lobe-assets-github] | LobeHub 的 Logo 资源、favicon、网页字体。 | | + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 🧩 插件体系 + +插件提供了扩展 LobeChat [Function Calling][fc-link] 能力的方法。可以用于引入新的 Function Calling,甚至是新的消息结果渲染方式。如果你对插件开发感兴趣,请在 Wiki 中查阅我们的 [📘 插件开发指引](https://github.com/lobehub/lobe-chat/wiki/Plugin-Development.zh-CN) 。 + +- [lobe-chat-plugins][lobe-chat-plugins]:这是 LobeChat 的插件索引。它从该仓库的 index.json 中获取插件列表并显示给用户。 +- [chat-plugin-template][chat-plugin-template]: Chat Plugin 插件开发模版,你可以通过项目模版快速新建插件项目。 +- [@lobehub/chat-plugin-sdk][chat-plugin-sdk]:LobeChat 插件 SDK 可帮助您创建出色的 Lobe Chat 插件。 +- [@lobehub/chat-plugins-gateway][chat-plugins-gateway]:LobeChat 插件网关是一个后端服务,作为 LobeChat 插件的网关。我们使用 Vercel 部署此服务。主要的 API POST /api/v1/runner 被部署为 Edge Function。 + +> \[!NOTE] +> +> 插件系统目前正在进行重大开发。您可以在以下 Issues 中了解更多信息: +> +> - [x] [**插件一期**](https://github.com/lobehub/lobe-chat/issues/73): 实现插件与主体分离,将插件拆分为独立仓库维护,并实现插件的动态加载 +> - [x] [**插件二期**](https://github.com/lobehub/lobe-chat/issues/97): 插件的安全性与使用的稳定性,更加精准地呈现异常状态,插件架构的可维护性与开发者友好 +> - [ ] [**插件三期**](https://github.com/lobehub/lobe-chat/issues/149):更高阶与完善的自定义能力,支持插件鉴权与示例 + +
+ +[![][back-to-top]](#readme-top) + +
+ +## ⌨️ 本地开发 + +可以使用 GitHub Codespaces 进行在线开发: + +[![][codespaces-shield]][codespaces-link] + +或者使用以下命令进行本地开发: + +[![][bun-shield]][bun-link] + +```fish +$ git clone https://github.com/lobehub/lobe-chat.git +$ cd lobe-chat +$ bun install +$ bun run dev +``` + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 🤝 参与贡献 + +我们非常欢迎各种形式的贡献。如果你对贡献代码感兴趣,可以查看我们的 GitHub [Issues][github-issues-link] 和 [Projects][github-project-link],大展身手,向我们展示你的奇思妙想。 + +[![][pr-welcome-shield]][pr-welcome-link] +[![][submit-agents-shield]][submit-agents-link] +[![][submit-plugin-shield]][submit-plugin-link] + +[![][contributors-contrib]][contributors-link] + +
+ +[![][back-to-top]](#readme-top) + +
+ +## 🔗 更多工具 + +- [🤯 Lobe Theme][lobe-theme] : Stable Diffusion WebUI 的现代主题,精致的界面设计,高度可定制的 UI,以及提高效率的功能。 +- [🌏 Lobe i18n][lobe-i18n] : Lobe i18n 是一个由 ChatGPT 驱动的 i18n(国际化)翻译过程的自动化工具。它支持自动分割大文件、增量更新,以及为 OpenAI 模型、API 代理和温度提供定制选项的功能。 +- [💌 Lobe Commit][lobe-commit] : Lobe Commit 是一个 CLI 工具,它利用 Langchain/ChatGPT 生成基于 Gitmoji 的提交消息。 + +
+ +[![][back-to-top]](#readme-top) + +
+ +--- + +

📝 License

+ +[![][fossa-license-shield]][fossa-license-link] + +
+ +Copyright © 2023 [LobeHub][profile-link].
+This project is [MIT](./LICENSE) licensed. + + + +[back-to-top]: https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square +[bun-link]: https://bun.sh +[bun-shield]: https://img.shields.io/badge/-speedup%20with%20bun-black?logo=bun&style=for-the-badge +[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 +[chat-plugin-sdk]: https://github.com/lobehub/chat-plugin-sdk +[chat-plugin-template]: https://github.com/lobehub/chat-plugin-template +[chat-plugins-gateway]: https://github.com/lobehub/chat-plugins-gateway +[codespaces-link]: https://codespaces.new/lobehub/lobe-chat +[codespaces-shield]: https://github.com/codespaces/badge.svg +[contributors-contrib]: https://contrib.rocks/image?repo=lobehub/lobe-chat +[contributors-link]: https://github.com/lobehub/lobe-chat/graphs/contributors +[deploy-button-image]: https://vercel.com/button +[deploy-link]: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat&env=OPENAI_API_KEY&envDescription=Find%20your%20OpenAI%20API%20Key%20by%20click%20the%20right%20Learn%20More%20button.&envLink=https%3A%2F%2Fplatform.openai.com%2Faccount%2Fapi-keys&project-name=lobe-chat&repository-name=lobe-chat +[discord-link]: https://discord.gg/AYFPHvv2jT +[discord-shield]: https://img.shields.io/discord/1127171173982154893?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square +[discord-shield-badge]: https://img.shields.io/discord/1127171173982154893?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge +[docker-pulls-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-pulls-shield]: https://img.shields.io/docker/pulls/lobehub/lobe-chat?color=45cc11&labelColor=black&style=flat-square +[docker-release-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-release-shield]: https://img.shields.io/docker/v/lobehub/lobe-chat?color=369eff&label=docker&labelColor=black&logo=docker&logoColor=white&style=flat-square +[docker-size-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-size-shield]: https://img.shields.io/docker/image-size/lobehub/lobe-chat?color=369eff&labelColor=black&style=flat-square +[fc-link]: https://sspai.com/post/81986 +[fossa-license-link]: https://app.fossa.com/projects/git%2Bgithub.com%2Flobehub%2Flobe-chat +[fossa-license-shield]: https://app.fossa.com/api/projects/git%2Bgithub.com%2Flobehub%2Flobe-chat.svg?type=large +[github-action-release-link]: https://github.com/lobehub/lobe-chat/actions/workflows/release.yml +[github-action-release-shield]: https://img.shields.io/github/actions/workflow/status/lobehub/lobe-chat/release.yml?label=release&labelColor=black&logo=githubactions&logoColor=white&style=flat-square +[github-action-test-link]: https://github.com/lobehub/lobe-chat/actions/workflows/test.yml +[github-action-test-shield]: https://img.shields.io/github/actions/workflow/status/lobehub/lobe-chat/test.yml?label=test&labelColor=black&logo=githubactions&logoColor=white&style=flat-square +[github-contributors-link]: https://github.com/lobehub/lobe-chat/graphs/contributors +[github-contributors-shield]: https://img.shields.io/github/contributors/lobehub/lobe-chat?color=c4f042&labelColor=black&style=flat-square +[github-forks-link]: https://github.com/lobehub/lobe-chat/network/members +[github-forks-shield]: https://img.shields.io/github/forks/lobehub/lobe-chat?color=8ae8ff&labelColor=black&style=flat-square +[github-issues-link]: https://github.com/lobehub/lobe-chat/issues +[github-issues-shield]: https://img.shields.io/github/issues/lobehub/lobe-chat?color=ff80eb&labelColor=black&style=flat-square +[github-license-link]: https://github.com/lobehub/lobe-chat/blob/main/LICENSE +[github-license-shield]: https://img.shields.io/github/license/lobehub/lobe-chat?color=white&labelColor=black&style=flat-square +[github-project-link]: https://github.com/lobehub/lobe-chat/projects +[github-release-link]: https://github.com/lobehub/lobe-chat/releases +[github-release-shield]: https://img.shields.io/github/v/release/lobehub/lobe-chat?color=369eff&labelColor=black&logo=github&style=flat-square +[github-releasedate-link]: https://github.com/lobehub/lobe-chat/releases +[github-releasedate-shield]: https://img.shields.io/github/release-date/lobehub/lobe-chat?labelColor=black&style=flat-square +[github-stars-link]: https://github.com/lobehub/lobe-chat/network/stargazers +[github-stars-shield]: https://img.shields.io/github/stars/lobehub/lobe-chat?color=ffcb47&labelColor=black&style=flat-square +[github-wiki-link]: https://github.com/lobehub/lobe-chat/wiki +[issues-link]: https://img.shields.io/github/issues/lobehub/lobe-chat.svg?style=flat +[lobe-assets-github]: https://github.com/lobehub/lobe-assets +[lobe-chat-plugins]: https://github.com/lobehub/lobe-chat-plugins +[lobe-commit]: https://github.com/lobehub/lobe-commit/tree/master/packages/lobe-commit +[lobe-i18n]: https://github.com/lobehub/lobe-commit/tree/master/packages/lobe-i18n +[lobe-lint-github]: https://github.com/lobehub/lobe-lint +[lobe-lint-link]: https://www.npmjs.com/package/@lobehub/lint +[lobe-lint-shield]: https://img.shields.io/npm/v/@lobehub/lint?color=369eff&labelColor=black&logo=npm&logoColor=white&style=flat-square +[lobe-theme]: https://github.com/lobehub/sd-webui-lobe-theme +[lobe-tts-github]: https://github.com/lobehub/lobe-tts +[lobe-tts-link]: https://www.npmjs.com/package/@lobehub/tts +[lobe-tts-shield]: https://img.shields.io/npm/v/@lobehub/tts?color=369eff&labelColor=black&logo=npm&logoColor=white&style=flat-square +[lobe-ui-github]: https://github.com/lobehub/lobe-ui +[lobe-ui-link]: https://www.npmjs.com/package/@lobehub/ui +[lobe-ui-shield]: https://img.shields.io/npm/v/@lobehub/ui?color=369eff&labelColor=black&logo=npm&logoColor=white&style=flat-square +[pr-welcome-link]: https://github.com/lobehub/lobe-chat/pulls +[pr-welcome-shield]: https://img.shields.io/badge/🤯_pr_welcome-%E2%86%92-ffcb47?labelColor=black&style=for-the-badge +[profile-link]: https://github.com/lobehub +[share-reddit-link]: https://www.reddit.com/submit?title=%E6%8E%A8%E8%8D%90%E4%B8%80%E4%B8%AA%20GitHub%20%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%20%F0%9F%A4%AF%20LobeChat%20-%20%E5%BC%80%E6%BA%90%E7%9A%84%E3%80%81%E5%8F%AF%E6%89%A9%E5%B1%95%E7%9A%84%EF%BC%88Function%20Calling%EF%BC%89%E9%AB%98%E6%80%A7%E8%83%BD%E8%81%8A%E5%A4%A9%E6%9C%BA%E5%99%A8%E4%BA%BA%E6%A1%86%E6%9E%B6%E3%80%82%0A%E5%AE%83%E6%94%AF%E6%8C%81%E4%B8%80%E9%94%AE%E5%85%8D%E8%B4%B9%E9%83%A8%E7%BD%B2%E7%A7%81%E4%BA%BA%20ChatGPT%2FLLM%20%E7%BD%91%E9%A1%B5%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%20%23chatbot%20%23chatGPT%20%23openAI&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat +[share-reddit-shield]: https://img.shields.io/badge/-share%20on%20reddit-black?labelColor=black&logo=reddit&logoColor=white&style=flat-square +[share-telegram-link]: https://t.me/share/url"?text=%E6%8E%A8%E8%8D%90%E4%B8%80%E4%B8%AA%20GitHub%20%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%20%F0%9F%A4%AF%20LobeChat%20-%20%E5%BC%80%E6%BA%90%E7%9A%84%E3%80%81%E5%8F%AF%E6%89%A9%E5%B1%95%E7%9A%84%EF%BC%88Function%20Calling%EF%BC%89%E9%AB%98%E6%80%A7%E8%83%BD%E8%81%8A%E5%A4%A9%E6%9C%BA%E5%99%A8%E4%BA%BA%E6%A1%86%E6%9E%B6%E3%80%82%0A%E5%AE%83%E6%94%AF%E6%8C%81%E4%B8%80%E9%94%AE%E5%85%8D%E8%B4%B9%E9%83%A8%E7%BD%B2%E7%A7%81%E4%BA%BA%20ChatGPT%2FLLM%20%E7%BD%91%E9%A1%B5%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%20%23chatbot%20%23chatGPT%20%23openAI&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat +[share-telegram-shield]: https://img.shields.io/badge/-share%20on%20telegram-black?labelColor=black&logo=telegram&logoColor=white&style=flat-square +[share-weibo-link]: http://service.weibo.com/share/share.php?sharesource=weibo&title=%E6%8E%A8%E8%8D%90%E4%B8%80%E4%B8%AA%20GitHub%20%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%20%F0%9F%A4%AF%20LobeChat%20-%20%E5%BC%80%E6%BA%90%E7%9A%84%E3%80%81%E5%8F%AF%E6%89%A9%E5%B1%95%E7%9A%84%EF%BC%88Function%20Calling%EF%BC%89%E9%AB%98%E6%80%A7%E8%83%BD%E8%81%8A%E5%A4%A9%E6%9C%BA%E5%99%A8%E4%BA%BA%E6%A1%86%E6%9E%B6%E3%80%82%0A%E5%AE%83%E6%94%AF%E6%8C%81%E4%B8%80%E9%94%AE%E5%85%8D%E8%B4%B9%E9%83%A8%E7%BD%B2%E7%A7%81%E4%BA%BA%20ChatGPT%2FLLM%20%E7%BD%91%E9%A1%B5%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%20%23chatbot%20%23chatGPT%20%23openAI&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat +[share-weibo-shield]: https://img.shields.io/badge/-share%20on%20weibo-black?labelColor=black&logo=sinaweibo&logoColor=white&style=flat-square +[share-whatsapp-link]: https://api.whatsapp.com/send?text=%E6%8E%A8%E8%8D%90%E4%B8%80%E4%B8%AA%20GitHub%20%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%20%F0%9F%A4%AF%20LobeChat%20-%20%E5%BC%80%E6%BA%90%E7%9A%84%E3%80%81%E5%8F%AF%E6%89%A9%E5%B1%95%E7%9A%84%EF%BC%88Function%20Calling%EF%BC%89%E9%AB%98%E6%80%A7%E8%83%BD%E8%81%8A%E5%A4%A9%E6%9C%BA%E5%99%A8%E4%BA%BA%E6%A1%86%E6%9E%B6%E3%80%82%0A%E5%AE%83%E6%94%AF%E6%8C%81%E4%B8%80%E9%94%AE%E5%85%8D%E8%B4%B9%E9%83%A8%E7%BD%B2%E7%A7%81%E4%BA%BA%20ChatGPT%2FLLM%20%E7%BD%91%E9%A1%B5%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%20https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat%20%23chatbot%20%23chatGPT%20%23openAI +[share-whatsapp-shield]: https://img.shields.io/badge/-share%20on%20whatsapp-black?labelColor=black&logo=whatsapp&logoColor=white&style=flat-square +[share-x-link]: https://x.com/intent/tweet?hashtags=chatbot%2CchatGPT%2CopenAI&text=%E6%8E%A8%E8%8D%90%E4%B8%80%E4%B8%AA%20GitHub%20%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%20%F0%9F%A4%AF%20LobeChat%20-%20%E5%BC%80%E6%BA%90%E7%9A%84%E3%80%81%E5%8F%AF%E6%89%A9%E5%B1%95%E7%9A%84%EF%BC%88Function%20Calling%EF%BC%89%E9%AB%98%E6%80%A7%E8%83%BD%E8%81%8A%E5%A4%A9%E6%9C%BA%E5%99%A8%E4%BA%BA%E6%A1%86%E6%9E%B6%E3%80%82%0A%E5%AE%83%E6%94%AF%E6%8C%81%E4%B8%80%E9%94%AE%E5%85%8D%E8%B4%B9%E9%83%A8%E7%BD%B2%E7%A7%81%E4%BA%BA%20ChatGPT%2FLLM%20%E7%BD%91%E9%A1%B5%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat +[share-x-shield]: https://img.shields.io/badge/-share%20on%20x-black?labelColor=black&logo=x&logoColor=white&style=flat-square +[submit-agents-link]: https://github.com/lobehub/lobe-chat-agents +[submit-agents-shield]: https://img.shields.io/badge/🤖/🏪_submit_agent-%E2%86%92-c4f042?labelColor=black&style=for-the-badge +[submit-plugin-link]: https://github.com/lobehub/lobe-chat-plugins +[submit-plugin-shield]: https://img.shields.io/badge/🧩/🏪_submit_plugin-%E2%86%92-95f3d9?labelColor=black&style=for-the-badge +[vercel-link]: https://chat-preview.lobehub.com +[vercel-shield]: https://img.shields.io/website?down_message=offline&label=vercel&labelColor=black&logo=vercel&style=flat-square&up_message=online&url=https%3A%2F%2Fchat-preview.lobehub.com +[vercel-shield-badge]: https://img.shields.io/website?down_message=offline&label=try%20lobechat&labelColor=black&logo=vercel&style=for-the-badge&up_message=online&url=https%3A%2F%2Fchat-preview.lobehub.com diff --git a/__mocks__/zustand/traditional.ts b/__mocks__/zustand/traditional.ts new file mode 100644 index 0000000000000..262acd02a7762 --- /dev/null +++ b/__mocks__/zustand/traditional.ts @@ -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)); diff --git a/docs/Analytics.zh-CN.md b/docs/Analytics.zh-CN.md new file mode 100644 index 0000000000000..aed5465041a5f --- /dev/null +++ b/docs/Analytics.zh-CN.md @@ -0,0 +1,15 @@ +# 数据统计 + +为更好地帮助分析 LobeChat 的用户使用情况,我们在 LobeChat 中集成了若干免费 / 开源的数据统计服务,用于收集用户的使用情况,你可以按需开启。 + +## Vercel Analytics + +[Vercel Analytics](https://vercel.com/analytics) 是 Vercel 推出的一款数据分析服务,它可以帮助你收集网站的访问情况,包括访问量、访问来源、访问设备等等。 + +我们在代码中集成了 Vercel Analytics,你可以通过设置环境变量 `NEXT_PUBLIC_ANALYTICS_VERCEL=1` 来开启它,并打开 Vercel 部署项目中 Analytics tab 查看你的应用访问情况。 + +Vercel Analytics 提供了 2500 次 / 月的免费 Web Analytics Events (可以理解为 PV),对于个人部署自用的产品来说基本够用。 + +如果你需要了解 Vercel Analytics 的详细使用教程,请查阅[Vercel Web Analytics 快速开始](https://vercel.com/docs/analytics/quickstart) + +## 🚧 Posthog diff --git a/docs/Deploy-with-Azure-OpenAI.md b/docs/Deploy-with-Azure-OpenAI.md new file mode 100644 index 0000000000000..0a2ae347575da --- /dev/null +++ b/docs/Deploy-with-Azure-OpenAI.md @@ -0,0 +1,54 @@ +# Deploying with Azure OpenAI + +LobeChat supports using [Azure OpenAI][azure-openai-url] as the model service provider for OpenAI. This document will guide you through the configuration of Azure OpenAI. + +#### TOC + +- [Usage Limitations](#usage-limitations) +- [Configuration in the Interface](#configuration-in-the-interface) +- [Configuration at Deployment](#configuration-at-deployment) + +## Usage Limitations + +Considering development costs ([#178][rfc]), the current version of LobeChat does not fully conform to Azure OpenAI's implementation model. Instead, it adopts a solution based on `openai` that is compatible with Azure OpenAI. This brings about the following limitations: + +- You can only choose one between OpenAI and Azure OpenAI. Once you enable Azure OpenAI, you will not be able to use OpenAI as the model service provider. +- LobeChat requires deployment names to be the same as the model names in order to function properly. For example, the deployment name for the `gpt-35-turbo` model must be `gpt-35-turbo`, otherwise LobeChat will not be able to match the model correctly. + ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/267082091-d89d53d3-1c8c-40ca-ba15-0a9af2a79264.png) +- Due to the complexity of integrating the Azure OpenAI SDK, it is currently impossible to query the model list of configured resources. + +## Configuration in the Interface + +Click on "Operation" - "Settings" in the bottom left corner, switch to the "Language Model" tab and enable the "Azure OpenAI" switch to start using Azure OpenAI. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/267083420-422a3714-627e-4bef-9fbc-141a2a8ca916.png) + +You can fill in the corresponding configuration items as needed: + +- **APIKey**: The API key you applied for on the Azure OpenAI account page, which can be found in the "Keys and Endpoints" section. +- **API Address**: Azure API address, which can be found in the "Keys and Endpoints" section when checking resources from the Azure portal. +- **Azure Api Version**: The API version of Azure, which follows the YYYY-MM-DD format, refer to the [latest version][azure-api-version-url]. + +After completing the above field configuration, click on "Check". If the prompt says "Check Passed", it means the configuration was successful. + +
+ +## Configuration at Deployment + +If you want the deployed version to be directly configured with Azure OpenAI for end users to use immediately, you need to configure the following environment variables at deployment: + +| Environment Variable | Required | Description | Default Value | Example | +| -------------------- | -------- | --------------------------------------------------------------------------------- | ------------------ | -------------------------------------------------------------- | +| `USE_AZURE_OPENAI` | Yes | Set this value to `1` to enable Azure OpenAI configuration | - | `1` | +| `AZURE_API_KEY` | Yes | This is the API key you applied for on the Azure OpenAI account page | - | `c55168be3874490ef0565d9779ecd5a6` | +| `OPENAI_PROXY_URL` | Yes | Azure API address, can be found in the "Keys and Endpoints" section | - | `https://docs-test-001.openai.azure.com` | +| `AZURE_API_VERSION` | No | Azure's API version, follows the YYYY-MM-DD format | 2023-08-01-preview | `2023-05-15`, refer to [latest version][azure-api-version-url] | +| `ACCESS_CODE` | No | Add a password to access this service, the password should be 6 digits or letters | - | `awCT74` or `e3@09!` | + +> \[!NOTE] +> +> When you enable `USE_AZURE_OPENAI` on the server side, users will not be able to modify and use the OpenAI key in the front-end configuration. + +[azure-api-version-url]: https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions +[azure-openai-url]: https://learn.microsoft.com/zh-cn/azure/ai-services/openai/concepts/models +[rfc]: https://github.com/lobehub/lobe-chat/discussions/178 diff --git a/docs/Deploy-with-Azure-OpenAI.zh-CN.md b/docs/Deploy-with-Azure-OpenAI.zh-CN.md new file mode 100644 index 0000000000000..45cd148755af3 --- /dev/null +++ b/docs/Deploy-with-Azure-OpenAI.zh-CN.md @@ -0,0 +1,54 @@ +# 使用 Azure OpenAI 部署 + +LobeChat 支持使用 [Azure OpenAI][azure-openai-url] 作为 OpenAI 的模型服务商,本文将介绍如何配置 Azure OpenAI。 + +#### TOC + +- [使用限制](#使用限制) +- [在界面中配置](#在界面中配置) +- [在部署时配置](#在部署时配置) + +## 使用限制 + +从研发成本考虑 ([#178][rfc]),目前阶段的 LobeChat 并没有 100% 完全符合 Azure OpenAI 的实现模型,采用了以 `openai` 为基座,兼容 Azure OpeAI 的解决方案。因此会带来以下局限性: + +- OpenAI 与 Azure OpenAI 只能二选一,当你开启使用 Azure OpenAI 后,将无法使用 OpenAI 作为模型服务商; +- LobeChat 约定了与模型同名的部署名才能正常使用,比如 `gpt-35-turbo` 模型的部署名,必须为 `gpt-35-turbo`,否则 LobeChat 将无法正常正确匹配到相应模型 + ![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/267082091-d89d53d3-1c8c-40ca-ba15-0a9af2a79264.png) +- 由于 Azure OpenAI 的 SDK 接入复杂度,当前无法查询配置资源的模型列表; + +## 在界面中配置 + +点击左下角「操作」 -「设置」,切到 「语言模型」 Tab 后通过开启「Azure OpenAI」开关,即可开启使用 Azure OpenAI。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/267083420-422a3714-627e-4bef-9fbc-141a2a8ca916.png) + +你按需填写相应的配置项: + +- **APIKey**:你在 Azure OpenAI 账户页面申请的 API 密钥,可在 “密钥和终结点” 部分中找到此值 +- **API 地址**:Azure API 地址,从 Azure 门户检查资源时,可在 “密钥和终结点” 部分中找到此值 +- **Azure Api Version**: Azure 的 API 版本,遵循 YYYY-MM-DD 格式,查阅[最新版本][azure-api-verion-url] + +完成上述字段配置后,点击「检查」,如果提示「检查通过」,则说明配置成功。 + +
+ +## 在部署时配置 + +如果你希望部署的版本直接配置好 Azure OpenAI,让终端用户直接使用,那么你需要在部署时配置以下环境变量: + +| 环境变量 | 类型 | 描述 | 默认值 | 示例 | +| ------------------- | ---- | --------------------------------------------------------------------------- | ------------------ | -------------------------------------------------- | +| `USE_AZURE_OPENAI` | 必选 | 设置改值为 `1` 开启 Azure OpenAI 配置 | - | `1` | +| `AZURE_API_KEY` | 必选 | 这是你在 Azure OpenAI 账户页面申请的 API 密钥 | - | `c55168be3874490ef0565d9779ecd5a6` | +| `OPENAI_PROXY_URL` | 必选 | Azure API 地址,从 Azure 门户检查资源时,可在 “密钥和终结点” 部分中找到此值 | - | `https://docs-test-001.openai.azure.com` | +| `AZURE_API_VERSION` | 可选 | Azure 的 API 版本,遵循 YYYY-MM-DD 格式 | 2023-08-01-preview | `2023-05-15`,查阅[最新版本][azure-api-verion-url] | +| `ACCESS_CODE` | 可选 | 添加访问此服务的密码,密码应为 6 位数字或字母 | - | `awCT74` 或 `e3@09!` | + +> \[!NOTE] +> +> 当你在服务端开启 `USE_AZURE_OPENAI` 后,用户将无法在前端配置中修改并使用 OpenAI key。 + +[azure-api-verion-url]: https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions +[azure-openai-url]: https://learn.microsoft.com/zh-cn/azure/ai-services/openai/concepts/models +[rfc]: https://github.com/lobehub/lobe-chat/discussions/178 diff --git a/docs/Development-Guide/Architecture.zh-CN.md b/docs/Development-Guide/Architecture.zh-CN.md new file mode 100644 index 0000000000000..e1d9482e12538 --- /dev/null +++ b/docs/Development-Guide/Architecture.zh-CN.md @@ -0,0 +1,37 @@ +## 架构设计 + +LobeChat 是一个基于 Next.js 框架构建的 AI 会话应用,旨在提供一个 AI 生产力平台,使用户能够与 AI 进行自然语言交互。以下是 LobeChat 的架构设计介稿: + +## 应用架构概览 + +LobeChat 的整体架构由前端、EdgeRuntime API、Agents 市场、插件市场和独立插件组成。这些组件相互协作,以提供完整的 AI 体验。 + +## 前端架构 + +LobeChat 的前端采用 Next.js 框架,利用其强大的 SSR(服务器端渲染)能力和路由功能。前端使用了一系列技术栈,包括 antd 组件库和 lobe-ui AIGC 组件库、zustand 状态管理、swr 请求库、i18next 国际化库等。这些技术栈共同支持了 LobeChat 的功能和特性。 + +前端架构中的组件包括 app、components、config、const、features、helpers、hooks、layout、locales、migrations、prompts、services、store、styles、types 和 utils。每个组件都有特定的职责,并与其他组件协同工作,以实现不同的功能。 + +## Edge Runtime API + +Edge Runtime API 是 LobeChat 的核心组件之一,负责处理 AI 会话的核心逻辑。它提供了与 AI 引擎的交互接口,包括自然语言处理、意图识别和回复生成等。EdgeRuntime API 与前端进行通信,接收用户的输入并返回相应的回复。 + +## Agents 市场 + +Agents 市场是 LobeChat 的一个重要组成部分,它提供了各种不同场景的 AI Agent,用于处理特定的任务和领域。Agents 市场还提供了使用和上传 Agent 的功能,使用户能够发现其他人制作的 Agent ,也可以一键分享自己的 Agent 到市场上。 + +## 插件市场 + +插件市场是 LobeChat 的另一个关键组件,它提供了各种插件,用于扩展 LobeChat 的功能和特性。插件可以是独立的功能模块,也可以与 Agents 市场的 Agent 进行集成。在会话中,助手将自动识别用户的输入,并识别适合的插件并传递给相应的插件进行处理,并返回处理结果。 + +## 安全性和性能优化 + +LobeChat 的安全性策略包括身份验证和权限管理。用户需要进行身份验证后才能使用 LobeChat,同时根据用户的权限进行相应的操作限制。 + +为了优化性能,LobeChat 使用了 Next.js 的 SSR 功能,实现了快速的页面加载和响应时间。此外,还采用了一系列的性能优化措施,包括代码分割、缓存和资源压缩等。 + +## 开发和部署流程 + +LobeChat 的开发流程包括版本控制、测试、持续集成和持续部署。开发团队使用版本控制系统进行代码管理,并进行单元测试和集成测试以确保代码质量。持续集成和持续部署流程确保了代码的快速交付和部署。 + +以上是 LobeChat 的架构设计介绍简介,详细解释了各个组件的职责和协作方式,以及设计决策对应用功能和性能的影响。 diff --git a/docs/Development-Guide/Chat-API.zh-CN.md b/docs/Development-Guide/Chat-API.zh-CN.md new file mode 100644 index 0000000000000..bf0bf0b3b0270 --- /dev/null +++ b/docs/Development-Guide/Chat-API.zh-CN.md @@ -0,0 +1,127 @@ +# LobeChat 会话 API 实现逻辑 + +LobeChat 的大模型 AI 实现主要依赖于 OpenAI 的 API,包括后端的核心会话 API 和前端的集成 API。接下来,我们将分别介绍后端和前端的实现思路和代码。 + +## 后端实现 + +以下代码中移除了鉴权、错误处理等逻辑,仅保留了核心的主要功能逻辑。 + +### 核心会话 API + +在 `src/app/api/openai/chat/handler.ts` 文件中,我们定义了 `POST` 方法,该方法首先从请求中解析出 payload 数据(即客户端发送的会话内容),然后从请求中获取 OpenAI 的授权信息。之后,我们创建一个 `openai` 对象,并调用 `createChatCompletion` 方法,该方法负责发送会话请求到 OpenAI 并返回结果。 + +```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 }); +}; +``` + +### 会话结果处理 + +在 `src/app/api/openai/chat/createChatCompletion.ts` 文件中,我们定义了 `createChatCompletion` 方法,该方法首先对 payload 数据进行预处理,然后调用 OpenAI 的 `chat.completions.create` 方法发送请求,并使用 [Vercel AI SDK](https://sdk.vercel.ai/docs) 中的 `OpenAIStream` 将返回的结果转化为流式响应。 + +```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); +}; +``` + +## 前端实现 + +### 前端集成 + +在 `src/services/chatModel.ts` 文件中,我们定义了 `fetchChatModel` 方法,该方法首先对 payload 数据进行前置处理,然后发送 POST 请求到后端的 `/chat` 接口,并将请求结果返回。 + +```ts +export const fetchChatModel = ( + { plugins: enabledPlugins, ...params }: Partial, + 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, + }); +}; +``` + +### 使用流式获取结果 + +在 `src/utils/fetch.ts` 文件中,我们定义了 `fetchSSE` 方法,该方法使用流式方法获取数据,当读取到新的数据块时,会调用 `onMessageHandle` 回调函数处理数据块,进而实现打字机输出效果。 + +```ts +export const fetchSSE = async (fetchFn: () => Promise, 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; +}; +``` + +以上就是 LobeChat 会话 API 的核心实现。在理解了这些核心代码的基础上,便可以进一步扩展和优化 LobeChat 的 AI 功能。 diff --git a/docs/Development-Guide/Data-Store/Selectors.zh-CN.md b/docs/Development-Guide/Data-Store/Selectors.zh-CN.md new file mode 100644 index 0000000000000..d317d5009a3e9 --- /dev/null +++ b/docs/Development-Guide/Data-Store/Selectors.zh-CN.md @@ -0,0 +1,68 @@ +## Selector + +selectors 是 LobeChat 数据流研发框架下的取数模块,它的作用是从 store 中以特定特务逻辑取出数据,供组件消费使用。 + +以 `src/store/plugin/selectors.ts` 为例: + +这个 TypeScript 代码段定义了一个名为 `pluginSelectors` 的对象,该对象包含一系列用于从插件存储状态中检索数据的选择器函数。选择器是一种从 Redux store(或类似的状态管理库)中提取和派生数据的函数。这个特定的例子是为了管理与前端应用程序的插件系统相关的状态。 + +下面是一些关键点的说明: + +- `enabledSchema`: 一个函数,返回一个基于启用插件列表 `enabledPlugins` 过滤后的 `ChatCompletionFunctions` 数组。它将插件标识符作为前缀添加到 API 名称,以确保唯一性,并使用 `uniqBy` 函数从 Lodash 库中删除重复项。 +- `onlinePluginStore`: 返回当前在线插件列表。 +- `pluginList`: 返回插件列表,包括自定义插件和标准插件。 +- `getPluginMetaById`: 根据插件 ID 返回插件元数据。 +- `getDevPluginById`: 返回开发中的自定义插件信息。 +- `getPluginManifestById`: 根据插件 ID 返回插件清单。 +- `getPluginSettingsById`: 根据插件 ID 返回插件设置。 +- `getPluginManifestLoadingStatus`: 根据插件 ID 返回插件清单的加载状态(加载中、成功或错误)。 +- `isCustomPlugin`: 检查给定 ID 的插件是否为自定义插件。 +- `displayPluginList`: 返回一个处理过的插件列表,包括作者、头像、创建时间、描述、首页 URL、标识符和标题。 +- `hasPluginUI`: 根据插件 ID 确定插件是否有 UI 组件。 + +selectors 是高度模块化和可维护的,它通过将复杂的状态选择逻辑封装在单独的函数中,使得在应用程序的其他部分调用状态数据时,代码更加简洁和直观。此外,由于使用了 TypeScript,每个函数都可以具有明确的输入和输出类型,这有助于提高代码的可靠性和开发效率。 + +以 `displayPluginList` 方法为例。其代码如下: + +```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` 方法:用于从插件状态存储 PluginStoreState 中获取所有插件的列表。 它通过结合两个数组:pluginList 和 customPluginList 来创建一个新的插件列表; +- `displayPluginList` 方法:调用 pluginList 方法来获取合并后的插件列表,转换其中的 title 和 desc 变成显示在 UI 上的文本。 + +在组件中,只需引入便可直接获取最终消费的数据: + +```tsx | pure +import { usePluginStore } from '@/store/plugin'; +import { pluginSelectors } from '@/store/plugin/selectors'; + +const Render = ({ plugins }) => { + const list = usePluginStore(pluginSelectors.displayPluginList); + + return <> ... ; +}; +``` + +这样实现的好处在于: + +1. **解耦和重用**:通过将选择器独立于组件,我们可以在多个组件之间复用这些选择器而不需要重写取数逻辑。这减少了重复代码,提高了开发效率,并且使得代码库更加干净和易于维护。 +2. **性能优化**:选择器可以用来计算派生数据,这样可以避免在每个组件中重复计算相同的数据。当状态发生变化时,只有依赖于这部分状态的选择器才会重新计算,从而减少不必要的渲染和计算。 +3. **易于测试**:选择器是纯函数,它们仅依赖于传入的参数。这意味着它们可以在隔离的环境中进行测试,无需模拟整个 store 或组件树。 +4. **类型安全**:由于 LobeChat 使用 TypeScript,每个选择器都有明确的输入和输出类型定义。这为开发者提供了自动完成和编译时检查的优势,减少了运行时错误。 +5. **可维护性**:选择器集中了状态的读取逻辑,使得跟踪状态的变化和管理更加直观。如果状态结构发生变化,我们只需要更新相应的选择器,而不是搜索和替换整个代码库中的多个位置。 +6. **可组合性**:选择器可以组合其他选择器,以创建更复杂的选择逻辑。这种模式允许开发者构建一个选择器层次结构,使得状态选择更加灵活和强大。 +7. **简化组件逻辑**:组件不需要知道状态的结构或如何获取和计算需要的数据。组件只需调用选择器即可获取渲染所需的数据,这使得组件逻辑变得更简单和清晰。 + +通过这样的设计,LobeChat 的开发者可以更专注于构建用户界面和业务逻辑,而不必担心数据的获取和处理细节。这种模式也为未来可能的状态结构变更提供了更好的适应性和扩展性。 diff --git a/docs/Development-Guide/Feature-Development.zh-CN.md b/docs/Development-Guide/Feature-Development.zh-CN.md new file mode 100644 index 0000000000000..69c0053edcf47 --- /dev/null +++ b/docs/Development-Guide/Feature-Development.zh-CN.md @@ -0,0 +1,118 @@ +## 如何开发一个新功能 + +LobeChat 基于 Next.js 框架构建,使用 TypeScript 作为主要开发语言。在开发新功能时,我们需要遵循一定的开发流程,以确保代码的质量和稳定性。大致的流程分为以下五步: + +1. 路由:定义路由 (`src/app`) +2. 数据结构: 定义数据结构 ( `src/types` ) +3. 业务功能实现: zustand store (`src/store`) +4. 页面展示:书写静态组件 / 页面 (`src/app//features/.tsx`) +5. 功能绑定:绑定 store 与页面的触发 (`const [state,function]= useNewStore(s=>[s.state,s.function])`) + +我们以 "会话消息" 功能为例,以下是实现这个功能的简要步骤: + +## 1. 定义路由 + +在 `src/app` 目录下,我们需要定义一个新的路由来承载 "会话消息" 页面。一般来说,我们会在 `src/app` 下创建一个新的文件夹,例如 `chat`,并且在这个文件夹中创建 `page.tsx`文件,在该文件中导出 React 组件作为页面的主体。 + +```tsx +// src/app/chat/page.tsx +import ChatPage from './features/chat'; + +export default ChatPage; +``` + +## 2. 定义数据结构 + +在 `src/types` 目录下,我们需要定义 "会话消息" 的数据结构。例如,我们创建一个 `chat.ts` 文件,并在其中定义 `ChatMessage` 类型: + +```ts +// src/types/chat.ts + +export type ChatMessage = { + id: string; + content: string; + timestamp: number; + sender: 'user' | 'bot'; +}; +``` + +## 3. 创建 Zustand Store + +在 `src/store` 目录下,我们需要创建一个新的 Zustand Store 来管理 "会话消息" 的状态。例如,我们创建一个 `chatStore.ts` 文件,并在其中定义一个 Zustand Store: + +```ts +// src/store/chatStore.ts +import create from 'zustand'; + +type ChatState = { + messages: ChatMessage[]; + addMessage: (message: ChatMessage) => void; +}; + +export const useChatStore = create((set) => ({ + messages: [], + addMessage: (message) => set((state) => ({ messages: [...state.messages, message] })), +})); +``` + +## 4. 创建页面与组件 + +在 `src/app//features/.tsx` 中,我们需要创建一个新的页面或组件来显示 "会话消息"。在这个文件中,我们可以使用上面创建的 Zustand Store,以及 Ant Design 的组件来构建 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 ( + ( + + {message.content} + + )} + /> + ); +}; + +export default ChatPage; +``` + +## 5. 功能绑定 + +在页面或组件中,我们需要将 Zustand Store 的状态和方法绑定到 UI 上。在上面的示例中,我们已经将 `messages` 状态绑定到了列表的 `dataSource` 属性上。现在,我们还需要一个方法来添加新的消息。我们可以在 Zustand Store 中定义这个方法,然后在页面或组件中使用它: + +```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 ( + <> + ( + + {message.content} + + )} + /> + + + ); +}; + +export default ChatPage; +``` + +以上就是在 LobeChat 中实现 "会话消息" 功能的步骤。当然,在 LobeChat 的实际开发中,真实场景所面临的业务诉求和场景远比上述 demo 复杂,请根据实际情况进行开发。 diff --git a/docs/Development-Guide/Folder-Structure.zh-CN.md b/docs/Development-Guide/Folder-Structure.zh-CN.md new file mode 100644 index 0000000000000..0368a94714cf9 --- /dev/null +++ b/docs/Development-Guide/Folder-Structure.zh-CN.md @@ -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 # 此为页面的主入口文件,用于根据设备类型选择加载桌面端或移动端的代码 +``` + +通过这种方式,我们可以清晰地区分和管理桌面端和移动端的代码,同时也能方便地复用在两种设备上都需要的代码,从而提高开发效率并保持代码的整洁和可维护性。 diff --git a/docs/Development-Guide/Resources.zh-CN.md b/docs/Development-Guide/Resources.zh-CN.md new file mode 100644 index 0000000000000..305ca12b4f269 --- /dev/null +++ b/docs/Development-Guide/Resources.zh-CN.md @@ -0,0 +1,19 @@ +# 资源与参考 + +LobeChat 的设计和开发离不开社区和生态中的优秀项目。我们在设计和开发过程中使用或参考了一些优秀的资源和指南。以下是一些主要的参考资源,供开发者在开发和学习过程中参考: + +1. **OpenAI API 指南**:我们使用 OpenAI 的 API 来获取和处理 AI 的会话数据。你可以查看 [OpenAI API 指南](https://platform.openai.com/docs/api-reference/introduction) 了解更多详情。 + +2. **OpenAI SDK**:我们使用 OpenAI 的 Node.js SDK 来与 OpenAI 的 API 交互。你可以在 [OpenAI SDK](https://github.com/openai/openai-node) 的 GitHub 仓库中查看源码和文档。 + +3. **AI SDK**:我们使用 Vercel 的 AI SDK 来获取和处理 AI 的会话数据。你可以查看 [AI SDK](https://sdk.vercel.ai/docs) 的文档来了解更多详情。 + +4. **LangChain**:我们早期的会话功能是基于 LangChain 实现的。你可以访问 [LangChain](https://langchain.com) 来了解更多关于它的信息。 + +5. **Chat-Next-Web**:Chat Next Web 是一个优秀的项目,LobeChat 的部分功能、Workflow 等参考了它的实现。你可以在 [Chat-Next-Web](https://github.com/Yidadaa/ChatGPT-Next-Web) 的 GitHub 仓库中查看源码和文档。 + +6. **Next.js 文档**:我们的项目是基于 Next.js 构建的,你可以查看 [Next.js 文档](https://nextjs.org/docs) 来了解更多关于 Next.js 的信息。 + +7. **FlowGPT**:FlowGPT 是目前全球最大的 Prompt 社区,LobeChat 中的一些 Agent 来自 FlowGPT 的活跃作者。你可以访问 [FlowGPT](https://flowgpt.com/) 来了解更多关于它的信息。 + +我们会持续更新和补充这个列表,为开发者提供更多的参考资源。 diff --git a/docs/Development-Guide/Steup-Development.zh-CN.md b/docs/Development-Guide/Steup-Development.zh-CN.md new file mode 100644 index 0000000000000..0c82f03aebaeb --- /dev/null +++ b/docs/Development-Guide/Steup-Development.zh-CN.md @@ -0,0 +1,62 @@ +# LobeChat 环境设置指南 + +欢迎阅读 LobeChat 的开发环境设置指南。 + +## 在线开发 + +如果你有 GitHub Codespaces 的使用权限,可以点击下方按钮一键进入在线开发环境: + +[![][codespaces-shield]][codespaces-link] + +## 本地开发 + +在开始开发 LobeChat 之前,你需要在本地环境中安装和配置一些必要的软件和工具。本文档将指导你完成这些步骤。 + +### 开发环境需求 + +首先,你需要安装以下软件: + +- Node.js:LobeChat 是基于 Node.js 构建的,因此你需要安装 Node.js。我们建议安装最新的稳定版。 +- Bun:我们使用 Bun 作为首选包管理器。你可以从 Bun 的官方网站上下载并安装。 +- PNPM:我们使用 PNPM 作为辅助包管理器。你可以从 pnpm 的官方网站上下载并安装。 +- Git:我们使用 Git 进行版本控制。你可以从 Git 的官方网站上下载并安装。 +- IDE:你可以选择你喜欢的集成开发环境(IDE)。我们推荐使用 WebStorm,它是一款功能强大的 IDE,特别适合 TypeScript 开发。 + +### 项目设置 + +完成上述软件的安装后,你可以开始设置 LobeChat 项目了。 + +1. **获取代码**:首先,你需要从 GitHub 上克隆 LobeChat 的代码库。在终端中运行以下命令: + +```bash +git clone https://github.com/lobehub/lobe-chat.git +``` + +2. **安装依赖**:然后,进入项目目录,并使用 bun 安装项目的依赖包: + +```bash +cd lobe-chat +bun i +``` + +如果你使用 pnpm ,可以执行: + +```bash +cd lobe-chat +pnpm i +``` + +3. **启动开发服务器**:安装完依赖后,你可以启动开发服务器: + +```bash +bun run dev +``` + +现在,你可以在浏览器中打开 `http://localhost:3010`,你应该能看到 LobeChat 的欢迎页面。这表明你已经成功地设置了开发环境。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/274655364-414bc31e-8511-47a3-af17-209b530effc7.png) + +在开发过程中,如果你在环境设置上遇到任何问题,或者有任何关于 LobeChat 开发的问题,欢迎随时向我们提问。我们期待看到你的贡献! + +[codespaces-link]: https://codespaces.new/lobehub/lobe-chat +[codespaces-shield]: https://github.com/codespaces/badge.svg diff --git a/docs/Development-Guide/Test.zh-CN.md b/docs/Development-Guide/Test.zh-CN.md new file mode 100644 index 0000000000000..175c9aadb9463 --- /dev/null +++ b/docs/Development-Guide/Test.zh-CN.md @@ -0,0 +1,79 @@ +# LobeChat 测试指南 + +LobeChat 的测试策略包括单元测试和端到端 (E2E) 测试。下面是每种测试的详细说明: + +## 单元测试 + +单元测试用于测试应用中的独立单元(如组件、函数、工具函数等)的功能。我们使用 [vitest][vitest-url] 进行单元测试。 + +要运行单元测试,可以使用以下命令: + +``` +npm run test +``` + +这将运行所有的单元测试,并生成测试报告。 + +我们鼓励开发者在编写代码时,同时编写对应的单元测试,以确保代码的质量和稳定性。 + +## 🚧 端到端测试 + +端到端测试用于测试应用在真实环境中的功能和性能。它模拟用户的真实操作,并验证应用在不同场景下的表现。 + +在 LobeChat 中,目前暂时没有集成端到端测试,我们会在后续迭代中逐步引入端到端测试。 + +## 开发测试 + +### 1. 单元测试 + +单元测试是针对应用中的最小可测试单元进行的测试,通常是针对函数、组件或模块进行的测试。在 LobeChat 中,我们使用 [vitest][vitest-url] 进行单元测试。 + +#### 编写测试用例 + +在编写单元测试之前,您需要创建一个与被测试文件相同的目录,并将测试文件命名为 `.test.ts`。例如,如果要测试 `src/utils/formatDate.ts` 文件,测试文件应命名为 `src/utils/formatDate.test.ts`。 + +在测试文件中,您可以使用 `describe` 和 `it` 函数来组织和编写测试用例。`describe` 函数用于创建测试套件,`it` 函数用于编写具体的测试用例。 + +```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'); + }); +}); +``` + +在测试用例中,您可以使用 `expect` 函数来断言测试结果是否符合预期。`expect` 函数可以与各种匹配器(matchers)一起使用,例如 `toBe`、`toEqual`、`toBeTruthy` 等。 + +#### 运行单元测试 + +通过运行以下命令来执行单元测试: + +``` +npm run test +``` + +这将运行所有的单元测试,并输出测试结果。 + +## 测试策略 + +为了编写有效的测试用例,您可以考虑以下测试策略: + +- **边界条件测试**:测试输入的边界条件,例如最小值、最大值、空值等。 +- **异常情况测试**:测试处理异常情况的代码,例如错误处理、异常情况下的回退等。 +- **功能测试**:测试应用的各个功能模块是否正常工作,包括用户交互、数据处理等。 +- **兼容性测试**:测试应用在不同浏览器和设备上的兼容性。 +- **性能测试**:测试应用在不同负载下的性能表现,例如响应时间、资源占用等。 + +同时,请确保您的测试用例具有良好的覆盖率,覆盖到应用中的关键代码和功能。 + +通过合理编写和执行单元测试、集成测试和端到端测试,您可以提高应用的质量和稳定性,并及时发现和修复潜在的问题。 + +[vitest-url]: https://vitest.dev/ diff --git a/docs/Development-Guide/index.zh-CN.md b/docs/Development-Guide/index.zh-CN.md new file mode 100644 index 0000000000000..8a3e9aaf7f0ff --- /dev/null +++ b/docs/Development-Guide/index.zh-CN.md @@ -0,0 +1,38 @@ +# LobeChat 技术开发上手指南 + +欢迎来到 LobeChat 技术开发上手指南。LobeChat 是一款基于 Next.js 框架构建的 AI 会话应用,它汇集了一系列的技术栈,以实现多样化的功能和特性。本指南将详细介绍 LobeChat 的主要技术组成,以及如何在你的开发环境中配置和使用这些技术。 + +## 基础技术栈 + +LobeChat 的核心技术栈如下: + +- **框架**:我们选择了 [Next.js](https://nextjs.org/),这是一款强大的 React 框架,为我们的项目提供了服务端渲染、路由框架、Router Handler 等关键功能。 +- **组件库**:我们使用了 [Ant Design (antd)](https://ant.design/) 作为基础组件库,同时引入了 [lobe-ui](https://github.com/lobehub/lobe-ui) 作为我们的业务组件库。 +- **状态管理**:我们选用了 [zustand](https://github.com/pmndrs/zustand),一款轻量级且易于使用的状态管理库。 +- **网络请求**:我们采用 [swr](https://swr.vercel.app/),这是一款用于数据获取的 React Hooks 库。 +- **路由**:路由管理我们直接使用 [Next.js](https://nextjs.org/) 自身提供的解决方案。 +- **国际化**:我们使用 [i18next](https://www.i18next.com/) 来实现应用的多语言支持。 +- **样式**:我们使用 [antd-style](https://github.com/ant-design/antd-style),这是一款与 Ant Design 配套的 CSS-in-JS 库。 +- **单元测试**:我们使用 [vitest](https://github.com/vitejs/vitest) 进行单元测试。 + +## 文件夹目录架构 + +LobeChat 的文件夹目录架构如下: + +```bash +src +├── app # 应用主要逻辑和状态管理相关的代码 +├── components # 可复用的 UI 组件 +├── config # 应用的配置文件,包含客户端环境变量与服务端环境变量 +├── const # 用于定义常量,如 action 类型、路由名等 +├── features # 与业务功能相关的功能模块,如 Agent 设置、插件开发弹窗等 +├── hooks # 全应用复用自定义的工具 Hooks +├── layout # 应用的布局组件,如导航栏、侧边栏等 +├── locales # 国际化的语言文件 +├── services # 封装的后端服务接口,如 HTTP 请求 +├── store # 用于状态管理的 zustand store +├── types # TypeScript 的类型定义文件 +└── utils # 通用的工具函数 +``` + +有关目录架构的详细介绍,详见: [文件夹目录架构](Folder-Structure.zh-CN.md) diff --git a/docs/Docker-Deployment.md b/docs/Docker-Deployment.md new file mode 100644 index 0000000000000..eff263995fadb --- /dev/null +++ b/docs/Docker-Deployment.md @@ -0,0 +1,87 @@ +# Docker Deployment Guide + +[![][docker-release-shield]][docker-release-link] +[![][docker-size-shield]][docker-size-link] +[![][docker-pulls-shield]][docker-pulls-link] + +We provide [Docker Images][docker-release-link] for you to deploy LobeChat service on your private device. + +## Install Docker container environment + +If already installed, skip this step. + +**Ubuntu:** + +```fish +$ apt install docker.io +``` + +**CentOS:** + +```fish +$ yum install docker +``` + +## Deploy container image + +### `A` Command deployment (recommended) + +Use the following command to start LobeChat service with one click: + +```fish +$ docker run -d -p 3210:3210 \ + -e OPENAI_API_KEY=sk-xxxx \ + -e ACCESS_CODE=lobe66 \ + lobehub/lobe-chat +``` + +> \[!NOTE] +> +> - The default mapped port is `3210`. Make sure it is not occupied or manually change the port mapping. +> - Replace `sk-xxxx` in the above command with your own OpenAI API Key. +> - The password set in the official Docker image is `lobe66` by default. Replace it with your own password to improve security. +> - For a complete list of environment variables supported by LobeChat, please refer to the [Environment Variables](https://github.com/lobehub/lobe-chat/wiki/Environment-Variable.zh-CN) section. + +#### Use a proxy address + +If you need to use OpenAI service through a proxy, you can use the `OPENAI_PROXY_URL` environment variable to configure the proxy address: + +```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 \ + lobehub/lobe-chat +``` + +> \[!NOTE] +> +> As the official Docker image build takes about half an hour, if there is a "update available" prompt after updating deployment, wait for the image to finish building before deploying again. + +### `B` Docker Compose + +The configuration file for using `docker-compose` is as follows: + +```yml +version: '3.8' + +services: + lobe-chat: + image: lobehub/lobe-chat + container_name: lobe-chat + ports: + - '3210:3210' + environment: + OPENAI_API_KEY: sk-xxxx + OPENAI_PROXY_URL: https://api-proxy.com/v1 + ACCESS_CODE: lobe66 +``` + + + +[docker-pulls-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-pulls-shield]: https://img.shields.io/docker/pulls/lobehub/lobe-chat?color=45cc11&labelColor=black&style=flat-square +[docker-release-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-release-shield]: https://img.shields.io/docker/v/lobehub/lobe-chat?color=369eff&label=docker&labelColor=black&logo=docker&logoColor=white&style=flat-square +[docker-size-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-size-shield]: https://img.shields.io/docker/image-size/lobehub/lobe-chat?color=369eff&labelColor=black&style=flat-square diff --git a/docs/Docker-Deployment.zh-CN.md b/docs/Docker-Deployment.zh-CN.md new file mode 100644 index 0000000000000..6510eb78add2a --- /dev/null +++ b/docs/Docker-Deployment.zh-CN.md @@ -0,0 +1,85 @@ +# Docker 部署指引 + +[![][docker-release-shield]][docker-release-link] +[![][docker-size-shield]][docker-size-link] +[![][docker-pulls-shield]][docker-pulls-link] + +我们提供了 [Docker 镜像][docker-release-link],供你在自己的私有设备上部署 LobeChat 服务 + +## 安装 Docker 容器环境 + +如果已安装,请跳过此步 + +**Ubuntu** + +```fish +$ apt install docker.io +``` + +**CentOS** + +```fish +$ yum install docker +``` + +## 部署容器镜像 + +### `A` 指令部署(推荐) + +使用以下命令即可使用一键启动 LobeChat 服务: + +```fish +$ docker run -d -p 3210:3210 \ + -e OPENAI_API_KEY=sk-xxxx \ + -e ACCESS_CODE=lobe66 \ + lobehub/lobe-chat +``` + +> \[!NOTE] +> +> - 默认映射端口为 `3210`, 请确保未被占用或手动更改端口映射 +> - 使用你的 OpenAI API Key 替换上述命令中的 `sk-xxxx` +> - 官方 Docker 镜像中设定的密码默认为 `lobe66`,请将其替换为自己的密码以提升安全性 +> - LobeChat 支持的完整环境变量列表请参考 [环境变量](https://github.com/lobehub/lobe-chat/wiki/Environment-Variable.zh-CN) 部分 + +#### 使用代理地址 + +如果你需要通过代理使用 OpenAI 服务,你可以使用 `OPENAI_PROXY_URL` 环境变量来配置代理地址: + +```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 \ + lobehub/lobe-chat +``` + +> \[!NOTE] +> +> 由于官方的 Docker 镜像构建大约需要半小时左右,如果在更新部署后会出现「存在更新」的提示,可以等待镜像构建完成后再次部署。 + +### `B` Docker Compose + +使用 `docker-compose` 时配置文件如下: + +```yml +version: '3.8' + +services: + lobe-chat: + image: lobehub/lobe-chat + container_name: lobe-chat + ports: + - '3210:3210' + environment: + OPENAI_API_KEY: sk-xxxx + OPENAI_PROXY_URL: https://api-proxy.com/v1 + ACCESS_CODE: lobe66 +``` + +[docker-pulls-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-pulls-shield]: https://img.shields.io/docker/pulls/lobehub/lobe-chat?color=45cc11&labelColor=black&style=flat-square +[docker-release-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-release-shield]: https://img.shields.io/docker/v/lobehub/lobe-chat?color=369eff&label=docker&labelColor=black&logo=docker&logoColor=white&style=flat-square +[docker-size-link]: https://hub.docker.com/r/lobehub/lobe-chat +[docker-size-shield]: https://img.shields.io/docker/image-size/lobehub/lobe-chat?color=369eff&labelColor=black&style=flat-square diff --git a/docs/Environment-Variable.md b/docs/Environment-Variable.md new file mode 100644 index 0000000000000..0405ade595c7e --- /dev/null +++ b/docs/Environment-Variable.md @@ -0,0 +1,157 @@ +# LobeChat Environment Variables + +LobeChat provides additional configuration options during deployment, which can be set using environment variables + +#### TOC + +- [General Variables](#general-variables) + - [`ACCESS_CODE`](#access_code) + - [`NEXT_PUBLIC_CUSTOM_MODELS`](#next_public_custom_models) +- [OpenAI](#openai) + - [`OPENAI_API_KEY`](#openai_api_key) + - [`OPENAI_PROXY_URL`](#openai_proxy_url) +- [Azure OpenAI](#azure-openai) + - [`USE_AZURE_OPENAI`](#use_azure_openai) + - [`AZURE_API_KEY`](#azure_api_key) + - [`AZURE_API_VERSION`](#azure_api_version) +- [Plugin Service](#plugin-service) + - [`PLUGINS_INDEX_URL`](#plugins_index_url) +- [Agent Service](#agent-service) + - [`AGENTS_INDEX_URL`](#agents_index_url) +- [Data Analytics](#data-analytics) + - [Vercel Analytics](#vercel-analytics) + - [Posthog Analytics](#posthog-analytics) + +## General Variables + +### `ACCESS_CODE` + +- Type: Optional +- Description: Add a password to access the LobeChat service, the password should be 6 digits or letters +- Default: `-` +- Example: `awCT74` or `e3@09!` + +### `NEXT_PUBLIC_CUSTOM_MODELS` + +- Type: Optional +- Description: add your custom model name, multi model seperate by comma. for example: `gpt-3.5-1106,gpt-4-1106` +- Default: `-` +- Example: `model1,model2,model3` + +## OpenAI + +### `OPENAI_API_KEY` + +- Type: Required +- Description: This is the API key you apply for on the OpenAI account page, you can go [here][openai-api-page] to view +- Default: `-` +- Example: `sk-xxxxxx...xxxxxx` + +### `OPENAI_PROXY_URL` + +- Type: Optional +- Description: If you manually configure the OpenAI interface proxy, you can use this configuration item to override the default OpenAI API request base URL +- Default: `https://api.openai.com` +- Example: `https://api.chatanywhere.cn` + +
+ +## Azure OpenAI + +If you need to use Azure OpenAI to provide model services, you can refer to the [Deploy with Azure OpenAI](./Deploy-with-Azure-OpenAI.zh-CN.md) section for detailed steps. Here are the environment variables related to Azure OpenAI. + +### `USE_AZURE_OPENAI` + +- Type: Optional +- Description: Set this value to `1` to enable Azure OpenAI configuration +- Default: `-` +- Example: `1` + +### `AZURE_API_KEY` + +- Type: Optional +- Description: This is the API key you apply for on the Azure OpenAI account page +- Default: `-` +- Example: `c55168be3874490ef0565d9779ecd5a6` + +### `AZURE_API_VERSION` + +- Type: Optional +- Description: Azure's API version, following the YYYY-MM-DD format +- Default: `2023-08-01-preview` +- Example: `2023-05-15`, refer to [latest version][azure-api-verion-url] + +
+ +## Plugin Service + +### `PLUGINS_INDEX_URL` + +- Type: Optional +- Description: The index address of the LobeChat plugin market. If you have deployed the plugin market service yourself, you can use this variable to override the default plugin market address +- Default: `https://chat-plugins.lobehub.com` + +
+ +## Agent Service + +### `AGENTS_INDEX_URL` + +- Type: Optional +- Description: The index address of the LobeChat role market. If you have deployed the role market service yourself, you can use this variable to override the default plugin market address +- Default: `https://chat-agents.lobehub.com` + +
+ +## Data Analytics + +### Vercel Analytics + +#### `NEXT_PUBLIC_ANALYTICS_VERCEL` + +- Type: Optional +- Description: Environment variable to enable [Vercel Analytics][vercel-analytics-url]. Set to `1` to enable Vercel Analytics. +- Default: `-` +- Example: `1` + +#### `NEXT_PUBLIC_VERCEL_DEBUG` + +- Type: Optional +- Description: Enable debug mode for Vercel Analytics. +- Default: `-` +- Example: `1` + +### Posthog Analytics + +#### `NEXT_PUBLIC_ANALYTICS_POSTHOG` + +- Type: Optional +- Description: Environment variable to enable [PostHog Analytics][posthog-analytics-url]. Set to `1` to enable PostHog Analytics. +- Default: `-` +- Example: `1` + +#### `NEXT_PUBLIC_POSTHOG_KEY` + +- Type: Optional +- Description: Set the PostHog project key. +- Default: - +- Example: `phc_xxxxxxxx` + +#### `NEXT_PUBLIC_POSTHOG_HOST` + +- Type: Optional +- Description: Set the deployment address of the PostHog service. Default is the official SAAS address. +- Default: `https://app.posthog.com` +- Example: `https://example.com` + +#### `NEXT_PUBLIC_POSTHOG_DEBUG` + +- Type: Optional +- Description: Enable debug mode for PostHog. +- Default: - +- Example: `1` + +[azure-api-verion-url]: https://docs.microsoft.com/zh-cn/azure/developer/javascript/api-reference/es-modules/azure-sdk/ai-translation/translationconfiguration?view=azure-node-latest#api-version +[openai-api-page]: https://platform.openai.com/account/api-keys +[posthog-analytics-url]: https://posthog.com +[vercel-analytics-url]: https://vercel.com/analytics diff --git a/docs/Environment-Variable.zh-CN.md b/docs/Environment-Variable.zh-CN.md new file mode 100644 index 0000000000000..c533f8cda1f67 --- /dev/null +++ b/docs/Environment-Variable.zh-CN.md @@ -0,0 +1,150 @@ +# LobeChat 环境变量 + +LobeChat 在部署时提供了一些额外的配置项,使用环境变量进行设置 + +#### TOC + +- [通用变量](#通用变量) + - [`ACCESS_CODE`](#access_code) + - [`NEXT_PUBLIC_CUSTOM_MODELS`](#next_public_custom_models) +- [OpenAI](#openai) + - [`OPENAI_API_KEY`](#openai_api_key) + - [`OPENAI_PROXY_URL`](#openai_proxy_url) +- [Azure OpenAI](#azure-openai) + - [`USE_AZURE_OPENAI`](#use_azure_openai) + - [`AZURE_API_KEY`](#azure_api_key) + - [`AZURE_API_VERSION`](#azure_api_version) +- [插件服务](#插件服务) + - [`PLUGINS_INDEX_URL`](#plugins_index_url) +- [角色服务](#角色服务) + - [`AGENTS_INDEX_URL`](#agents_index_url) +- [数据统计](#数据统计) + - [Vercel Analytics](#vercel-analytics) + - [Posthog Analytics](#posthog-analytics) + +## 通用变量 + +### `ACCESS_CODE` + +- 类型:可选 +- 描述:添加访问 LobeChat 服务的密码,密码应为 6 位数字或字母 +- 默认值:- +- 示例:`awCT74` 或 `e3@09!` + +### `NEXT_PUBLIC_CUSTOM_MODELS` + +- 类型:可选 +- 描述:添加自定义模型名称,多个模型需要使用逗号 `,` 隔开。 比如: `gpt-3.5-1106,gpt-4-1106` +- 默认值:`-` +- 示例:`model1,model2,model3` + +## OpenAI + +### `OPENAI_API_KEY` + +- 类型:必选 +- 描述:这是你在 OpenAI 账户页面申请的 API 密钥,可以前往[这里][openai-api-page]查看 +- 默认值:- +- 示例:`sk-xxxxxx...xxxxxx` + +### `OPENAI_PROXY_URL` + +- 类型:可选 +- 描述:如果你手动配置了 OpenAI 接口代理,可以使用此配置项来覆盖默认的 OpenAI API 请求基础 URL +- 默认值:`https://api.openai.com` +- 示例:`https://api.chatanywhere.cn` + +
+ +## Azure OpenAI + +如果你需要使用 Azure OpenAI 来提供模型服务,可以查阅 [使用 Azure OpenAI 部署](./Deploy-with-Azure-OpenAI.zh-CN.md) 章节查看详细步骤,这里将列举和 Azure OpenAI 相关的环境变量。 + +### `USE_AZURE_OPENAI` + +- 类型:可选 +- 描述:设置该值为 `1` 开启 Azure OpenAI 配置 +- 默认值:- +- 示例:`1` + +### `AZURE_API_KEY` + +- 类型:可选 +- 描述:这是你在 Azure OpenAI 账户页面申请的 API 密钥 +- 默认值:- +- 示例:`c55168be3874490ef0565d9779ecd5a6` + +### `AZURE_API_VERSION` + +- 类型:可选 +- 描述:Azure 的 API 版本,遵循 YYYY-MM-DD 格式 +- 默认值:`2023-08-01-preview` +- 示例:`2023-05-15`,查阅[最新版本][azure-api-verion-url] + +## 插件服务 + +### `PLUGINS_INDEX_URL` + +- 类型:可选 +- 描述:LobeChat 插件市场的索引地址,如果你自行部署了插件市场的服务,可以使用该变量来覆盖默认的插件市场地址 +- 默认值:`https://chat-plugins.lobehub.com` + +## 角色服务 + +### `AGENTS_INDEX_URL` + +- 类型:可选 +- 描述:LobeChat 角色市场的索引地址,如果你自行部署了角色市场的服务,可以使用该变量来覆盖默认的插件市场地址 +- 默认值:`https://chat-agents.lobehub.com` + +## 数据统计 + +### Vercel Analytics + +#### `NEXT_PUBLIC_ANALYTICS_VERCEL` + +- 类型:可选 +- 描述:用于配置 Vercel Analytics 的环境变量,当设为 `1` 时开启 Vercel Analytics +- 默认值: `-` +- 示例:`1` + +#### `NEXT_PUBLIC_VERCEL_DEBUG` + +- 类型:可选 +- 描述:用于开启 Vercel Analytics 的调试模式 +- 默认值: `-` +- 示例:`1` + +### Posthog Analytics + +#### `NEXT_PUBLIC_ANALYTICS_POSTHOG` + +- 类型:可选 +- 描述:用于开启 [PostHog Analytics][posthog-analytics-url] 的环境变量,设为 `1` 时开启 PostHog Analytics +- 默认值: `-` +- 示例:`1` + +#### `NEXT_PUBLIC_POSTHOG_KEY` + +- 类型:可选 +- 描述:设置 PostHog 项目 Key +- 默认值: `-` +- 示例:`phc_xxxxxxxx` + +#### `NEXT_PUBLIC_POSTHOG_HOST` + +- 类型:可选 +- 描述:设置 PostHog 服务的部署地址,默认为官方的 SAAS 地址 +- 默认值:`https://app.posthog.com` +- 示例:`https://example.com` + +#### `NEXT_PUBLIC_POSTHOG_DEBUG` + +- 类型:可选 +- 描述:开启 PostHog 的调试模式 +- 默认值: `-` +- 示例:`1` + +[azure-api-verion-url]: https://docs.microsoft.com/zh-cn/azure/developer/javascript/api-reference/es-modules/azure-sdk/ai-translation/translationconfiguration?view=azure-node-latest#api-version +[openai-api-page]: https://platform.openai.com/account/api-keys +[posthog-analytics-url]: https://posthog.com diff --git a/docs/Home.md b/docs/Home.md new file mode 100644 index 0000000000000..bda5865148e40 --- /dev/null +++ b/docs/Home.md @@ -0,0 +1,72 @@ +
+ + + + + +

Lobe Chat Wiki

+ +LobeChat is a open-source, extensible ([Function Calling][fc-url]), high-performance chatbot framework.
It supports one-click free deployment of your private ChatGPT/LLM web application. + +
+ +![](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png) + +### 🤯 LobeChat Usage + +- [Custom Agents Guide](Usage-Agents) | [自定义助手指南](Usage-Agents.zh-CN) +- [Topics Guide](Usage-Topics) | [话题指南](Usage-Topics.zh-CN) + +--- + +#### 🛳 Self Hosting + +- [Environment Variables](Environment-Variable) | [环境变量](Environment-Variable.zh-CN) +- [Maintaining Updates with LobeChat Self-Deployment](Upstream-Sync) | [自部署保持更新](Upstream-Sync.zh-CN) +- [Deploying with Azure OpenAI](Deploy-with-Azure-OpenAI) | [使用 Azure OpenAI 部署](Deploy-with-Azure-OpenAI.zh-CN) +- [Docker Deployment Guide](Docker-Deployment) | [Docker 部署指引](Docker-Deployment.zh-CN) + +--- + +### 🤖 Agents + +- [Agent Index and Submit][agent-index] | [助手索引与提交][agent-index-cn] + +--- + +### 🧩 Plugins + +- [Plugin Index and Submit][plugin-index] | [插件索引与提交][plugin-index-cn] +- [Plugin Development](Plugin-Development) | [插件开发](Plugin-Development.zh-CN) +- [Plugin SDK Docs][plugin-sdk] | [插件 SDK 文档][plugin-skd-cn] + +--- + +#### 📊 Other + +- [Lighthouse Report](Lighthouse) | [性能测试](Lighthouse.zh-CN) + +--- + +

📝 License

+ +[![][fossa-license-shield]][fossa-license-url] + +
+ +Copyright © 2023 [LobeHub][profile-url].
+This project is [MIT][license-url] licensed. + + + +[agent-index]: https://github.com/lobehub/lobe-chat-agents +[agent-index-cn]: https://github.com/lobehub/lobe-chat-agents/blob/main/README.zh-CN.md +[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 +[plugin-index]: https://github.com/lobehub/lobe-chat-plugins +[plugin-index-cn]: https://github.com/lobehub/lobe-chat-plugins/blob/main/README.zh-CN.md +[plugin-sdk]: https://chat-plugin-sdk.lobehub.com +[plugin-skd-cn]: https://chat-plugin-sdk.lobehub.com +[profile-url]: https://github.com/lobehub diff --git a/docs/Lighthouse.md b/docs/Lighthouse.md new file mode 100644 index 0000000000000..8cd92f74a213e --- /dev/null +++ b/docs/Lighthouse.md @@ -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**\ +> + +| Desktop | Mobile | +| :---------------------------------------------: | :--------------------------------------------: | +| ![][welcome-desktop] | ![][welcome-mobile] | +| [⚡️ Lighthouse Report][welcome-desktop-report] | [⚡️ Lighthouse Report][welcome-mobile-report] | + +## Chat Page + +> **Info**\ +> + +| Desktop | Mobile | +| :------------------------------------------: | :-----------------------------------------: | +| ![][chat-desktop] | ![][chat-mobile] | +| [⚡️ Lighthouse Report][chat-desktop-report] | [⚡️ Lighthouse Report][chat-mobile-report] | + +## Market Page + +> **Info**\ +> + +| Desktop | Mobile | +| :--------------------------------------------: | :-------------------------------------------: | +| ![][market-desktop] | ![][market-mobile] | +| [⚡️ Lighthouse Report][market-desktop-report] | [⚡️ Lighthouse Report][market-mobile-report] | + +## Settings Page + +> **Info**\ +> + +| 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 diff --git a/docs/Lighthouse.zh-CN.md b/docs/Lighthouse.zh-CN.md new file mode 100644 index 0000000000000..95d67416a1019 --- /dev/null +++ b/docs/Lighthouse.zh-CN.md @@ -0,0 +1,65 @@ +# Lighthouse 测试报告 + +#### TOC + +- [Welcome 欢迎页面](#welcome-欢迎页面) +- [Chat 聊天页面](#chat-聊天页面) +- [Market 市场页面](#market-市场页面) +- [Settings 设置页面](#settings-设置页面) + +## Welcome 欢迎页面 + +> **Info**\ +> + +| Desktop | Mobile | +| :---------------------------------------------: | :--------------------------------------------: | +| ![][welcome-desktop] | ![][welcome-mobile] | +| [⚡️ Lighthouse Report][welcome-desktop-report] | [⚡️ Lighthouse Report][welcome-mobile-report] | + +## Chat 聊天页面 + +> **Info**\ +> + +| Desktop | Mobile | +| :------------------------------------------: | :-----------------------------------------: | +| ![][chat-desktop] | ![][chat-mobile] | +| [⚡️ Lighthouse Report][chat-desktop-report] | [⚡️ Lighthouse Report][chat-mobile-report] | + +## Market 市场页面 + +> **Info**\ +> + +| Desktop | Mobile | +| :--------------------------------------------: | :-------------------------------------------: | +| ![][market-desktop] | ![][market-mobile] | +| [⚡️ Lighthouse Report][market-desktop-report] | [⚡️ Lighthouse Report][market-mobile-report] | + +## Settings 设置页面 + +> **Info**\ +> + +| 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 diff --git a/docs/Plugin-Development.md b/docs/Plugin-Development.md new file mode 100644 index 0000000000000..d92c3d4ab0fde --- /dev/null +++ b/docs/Plugin-Development.md @@ -0,0 +1,287 @@ +# LobeChat Plugin Development + +#### TOC + +- [Plugin Composition](#plugin-composition) +- [Custom Plugin Workflow](#custom-plugin-workflow) + - [**`1`** Create and Start a Plugin Project](#1-create-and-start-a-plugin-project) + - [**`2`** Add the Local Plugin in LobeChat Role Settings](#2-add-the-local-plugin-in-lobechat-role-settings) + - [**`3`** Test the Plugin Functionality in a Session](#3-test-the-plugin-functionality-in-a-session) +- [Local Plugin Development](#local-plugin-development) + - [Manifest](#manifest) + - [Project Structure](#project-structure) + - [Server-side](#server-side) + - [Plugin UI Interface](#plugin-ui-interface) +- [Plugin Deployment and Publication](#plugin-deployment-and-publication) + - [Plugin Shield](#plugin-shield) +- [Link](#link) + +## Plugin Composition + +A LobeChat plugin consists of the following components: + +1. **Plugin Index**: Used to display basic information about the plugin, including the plugin name, description, author, version, and a link to the plugin manifest. The official plugin index can be found at [lobe-chat-plugins](https://github.com/lobehub/lobe-chat-plugins). To submit a plugin to the official plugin marketplace, you need to submit a PR to this repository. +2. **Plugin Manifest**: Used to describe the functionality of the plugin, including the server-side description, frontend display information, and version number. For more details about the manifest, please refer to the [manifest][manifest-docs-url]. +3. **Plugin Services**: Used to implement the server-side and frontend modules described in the manifest: + +- **Server-side**: Implement the API capabilities described in the manifest. +- **Frontend UI** (optional): Implement the interface described in the manifest, which will be displayed in plugin messages to provide richer information display than plain text. + +
+ +## Custom Plugin Workflow + +To integrate a plugin into LobeChat, you need to add and use a custom plugin in LobeChat. This section will guide you through the process. + +### **`1`** Create and Start a Plugin Project + +First, you need to create a plugin project locally. You can use the [lobe-chat-plugin-template][lobe-chat-plugin-template-url] template we have prepared: + +```bash +$ git clone https://github.com/lobehub/chat-plugin-template.git +$ cd chat-plugin-template +$ npm i +$ npm run dev +``` + +When you see `ready started server on 0.0.0.0:3400, url: http://localhost:3400`, it means that the plugin service has been successfully started locally. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259526-9ef25272-4312-429b-93bc-a95515727ed3.png) + +### **`2`** Add the Local Plugin in LobeChat Role Settings + +Next, go to LobeChat, create a new assistant, and go to its session settings page: + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259643-1a9cc34a-76f3-4ccf-928b-129654670efd.png) + +Click the Add button on the right side of "Plugin List" to open the custom plugin add dialog: + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259748-2ef6a244-39bb-483c-b359-f156ffcbe1a4.png) + +Enter `http://localhost:3400/manifest-dev.json` in the `Plugin Manifest URL` field, which is the URL of the locally started plugin manifest. + +At this point, you should see that the identifier of the plugin has been automatically recognized as `chat-plugin-template`. Then fill in the remaining form fields (only the title is required) and click the Save button to complete the custom plugin addition. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259964-59f4906d-ae2e-4ec0-8b43-db36871d0869.png) + +After adding the plugin, you can see the newly added plugin in the plugin list. If you need to modify the plugin's configuration, you can click the Settings button to make changes. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260093-a0363c74-0b5b-48dd-b103-2db6b4a8262e.png) + +### **`3`** Test the Plugin Functionality in a Session + +Next, we need to test the functionality of the custom plugin. + +Click the Back button to go back to the session area, and then send a message to the assistant: "What should I wear?" The assistant will try to ask you about your gender and current mood. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260291-f0aa0e7c-0ffb-486c-a834-08e73d49896f.png) + +After answering, the assistant will make a plugin call to retrieve recommended clothing data based on your gender and mood from the server and push it to you. Finally, it will summarize the information in a text response. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260461-c22ae797-2809-464b-96fc-d0c020f4807b.png) + +After completing these steps, you have learned the basic process of adding and using a custom plugin in LobeChat. + +
+ +## Local Plugin Development + +In the previous workflow, we have learned how to add and use a plugin. Now let's focus on the development process of custom plugins. + +### Manifest + +The manifest aggregates information about how the plugin's functionality is implemented. The core fields are `api` and `ui`, which describe the server-side API capabilities and the frontend rendering interface address of the plugin, respectively. + +Taking the manifest in our template as an example: + +```json +{ + "api": [ + { + "url": "http://localhost:3400/api/clothes", + "name": "recommendClothes", + "description": "Recommend clothes based on the user's mood", + "parameters": { + "properties": { + "mood": { + "description": "The user's current mood, with optional values: happy, sad, anger, fear, surprise, disgust", + "enums": ["happy", "sad", "anger", "fear", "surprise", "disgust"], + "type": "string" + }, + "gender": { + "type": "string", + "enum": ["man", "woman"], + "description": "The gender of the user, which needs to be asked before knowing this information" + } + }, + "required": ["mood", "gender"], + "type": "object" + } + } + ], + "gateway": "http://localhost:3400/api/gateway", + "identifier": "chat-plugin-template", + "ui": { + "url": "http://localhost:3400", + "height": 200 + }, + "version": "1" +} +``` + +In this manifest, the following parts are included: + +1. `identifier`: This is the unique identifier of the plugin, used to distinguish different plugins. This field needs to be globally unique. +2. `api`: This is an array that contains all the API interface information provided by the plugin. Each interface includes the `url`, `name`, `description`, and `parameters` fields, all of which are required. The `description` and `parameters` fields will be sent to GPT as the `functions` parameter of the [Function Call](https://sspai.com/post/81986). The parameters need to comply with the [JSON Schema](https://json-schema.org/) specification. In this example, the API interface is named `recommendClothes`, which recommends clothes based on the user's mood and gender. The parameters of the interface include the user's mood and gender, both of which are required. +3. `ui`: This field contains information about the plugin's user interface, indicating where LobeChat loads the frontend interface of the plugin from. Since the plugin interface loading in LobeChat is implemented based on `iframe`, you can specify the height and width of the plugin interface as needed. +4. `gateway`: This field specifies the gateway for LobeChat to query API interfaces. The default plugin gateway in LobeChat is a cloud service, but for custom plugins, the requests need to be sent to the local service. Therefore, by specifying the gateway in the manifest, LobeChat will directly request this address and access the local plugin service. The gateway field does not need to be specified for plugins published online. +5. `version`: This is the version number of the plugin, which is currently not used. + +In actual development, you can modify the plugin's manifest according to your needs to declare the functionality you want to implement. For a complete introduction to each field in the manifest, please refer to: [manifest][manifest-docs-url]. + +### Project Structure + +The [lobe-chat-plugin-template][lobe-chat-plugin-template-url] template project uses Next.js as the development framework. Its core directory structure is as follows: + +``` +➜ chat-plugin-template +├── public +│ └── manifest-dev.json # Manifest file +├── src +│ └── pages +│ │ ├── api # Next.js server-side folder +│ │ │ ├── clothes.ts # Implementation of the recommendClothes interface +│ │ │ └── gateway.ts # Local plugin proxy gateway +│ │ └── index.tsx # Frontend display interface +``` + +Of course, using Next.js as the development framework in the template is just because we are familiar with Next.js and it is convenient for development. You can use any frontend framework and programming language you are familiar with as long as it can implement the functionality described in the manifest. + +We also welcome contributions of plugin templates in more frameworks and languages. + +### Server-side + +The server-side only needs to implement the API interfaces described in the manifest. In the template, we use Vercel's [Edge Runtime](https://nextjs.org/docs/pages/api-reference/edge) as the server, which eliminates the need for operational maintenance. + +#### API Implementation + +For Edge Runtime, we provide the `createErrorResponse` method in `@lobehub/chat-plugin-sdk` to quickly return error responses. The currently provided error types can be found at: [PluginErrorType][plugin-error-type-url]. + +Here is an example of the clothes API implementation in the template: + +```ts +export default async (req: Request) => { + if (req.method !== 'POST') return createErrorResponse(PluginErrorType.MethodNotAllowed); + + const { gender, mood } = (await req.json()) as RequestData; + + const clothes = gender === 'man' ? manClothes : womanClothes; + + const result: ResponseData = { + clothes: clothes[mood] || [], + mood, + today: Date.now(), + }; + + return new Response(JSON.stringify(result)); +}; +``` + +In this example, `manClothes` and `womanClothes` are hardcoded mock data. In actual scenarios, they can be replaced with database queries. + +#### Gateway + +Since the default plugin gateway in LobeChat is a cloud service (\), which sends requests to the API addresses specified in the manifest to solve the cross-origin issue. + +For custom plugins, the requests need to be sent to the local service. Therefore, by specifying the gateway in the manifest (), LobeChat will directly request this address. Then you only need to create a gateway implementation at this address. + +```ts +import { createLobeChatPluginGateway } from '@lobehub/chat-plugins-gateway'; + +export const config = { + runtime: 'edge', +}; + +export default async createLobeChatPluginGateway(); +``` + +[`@lobehub/chat-plugins-gateway`](https://github.com/lobehub/chat-plugins-gateway) includes the implementation of the plugin gateway in LobeChat, which you can use to create a gateway. This allows LobeChat to access the local plugin service. + +### Plugin UI Interface + +For a plugin, the UI interface is optional. For example, the [Web Crawler](https://github.com/lobehub/chat-plugin-web-crawler) plugin does not provide a corresponding user interface. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263241-0e765fdc-3463-4c36-a398-aef177a30df9.png) + +If you want to display richer information in plugin messages or include some rich interactions, you can define a user interface for the plugin. For example, the following image shows the user interface of a search engine plugin. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263427-9bdc03d5-aa61-4f62-a2ce-88683f3308d8.png) + +#### Plugin UI Interface Implementation + +LobeChat uses `iframe` + `postMessage` to load and communicate with plugin UI. Therefore, the implementation of the plugin UI is the same as normal web development. You can use any frontend framework and programming language you are familiar with. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263653-4ea87abc-249a-49f3-a241-7ed93ddb1ddf.png) + +In our template, we use React + Next.js + antd as the frontend framework. You can find the implementation of the user interface in `src/pages/index.tsx`. + +Regarding plugin communication, we provide related methods in [`@lobehub/chat-plugin-sdk`](https://github.com/lobehub/chat-plugin-sdk) to simplify the communication between the plugin and LobeChat. You can use the `fetchPluginMessage` method to actively retrieve the data of the current message from LobeChat. For a detailed description of this method, please refer to: [fetchPluginMessage][fetch-plugin-message-url]. + +```tsx +import { fetchPluginMessage } from '@lobehub/chat-plugin-sdk'; +import { memo, useEffect, useState } from 'react'; + +import { ResponseData } from '@/type'; + +const Render = memo(() => { + const [data, setData] = useState(); + + useEffect(() => { + // Retrieve the current plugin message from LobeChat + fetchPluginMessage().then((e: ResponseData) => { + setData(e); + }); + }, []); + + return <>...; +}); + +export default Render; +``` + +
+ +## Plugin Deployment and Publication + +After completing the plugin development, you can deploy the plugin using your preferred method. For example, you can use Vercel or package it as a Docker image for publication. + +If you want more people to use your plugin, you are welcome to submit it for review in the plugin marketplace. + +[![][submit-plugin-shield]][submit-plugin-url] + +### Plugin Shield + +[![lobe-chat-plugin](https://img.shields.io/badge/%F0%9F%A4%AF%20%26%20%F0%9F%A7%A9%20LobeHub-Plugin-95f3d9?labelColor=black&style=flat-square)](https://github.com/lobehub/lobe-chat-plugins) + +```markdown +[![lobe-chat-plugin](https://img.shields.io/badge/%F0%9F%A4%AF%20%26%20%F0%9F%A7%A9%20LobeHub-Plugin-95f3d9?labelColor=black&style=flat-square)](https://github.com/lobehub/lobe-chat-plugins) +``` + +
+ +## Link + +- **📘 Pluging SDK Docs**: +- **🚀 chat-plugin-template**: +- **🧩 chat-plugin-sdk**: +- **🚪 chat-plugin-sdk**: +- **🏪 lobe-chat-plugins**: + + + +[fetch-plugin-message-url]: https://github.com/lobehub/chat-plugin-template +[lobe-chat-plugin-template-url]: https://github.com/lobehub/chat-plugin-template +[manifest-docs-url]: https://chat-plugin-sdk.lobehub.com/guides/plugin-manifest +[plugin-error-type-url]: https://github.com/lobehub/chat-plugin-template +[submit-plugin-shield]: https://img.shields.io/badge/🧩/🏪_submit_plugin-%E2%86%92-95f3d9?labelColor=black&style=for-the-badge +[submit-plugin-url]: https://github.com/lobehub/lobe-chat-plugins diff --git a/docs/Plugin-Development.zh-CN.md b/docs/Plugin-Development.zh-CN.md new file mode 100644 index 0000000000000..80de1afadf155 --- /dev/null +++ b/docs/Plugin-Development.zh-CN.md @@ -0,0 +1,286 @@ +# LobeChat 插件开发 + +#### TOC + +- [插件构成](#插件构成) +- [自定义插件流程](#自定义插件流程) + - [**`1`** 创建并启动插件项目](#1-创建并启动插件项目) + - [**`2`** 在 LobeChat 角色设置中添加本地插件](#2-在-lobechat-角色设置中添加本地插件) + - [**`3`** 会话测试插件功能](#3-会话测试插件功能) +- [本地插件开发](#本地插件开发) + - [manifest](#manifest) + - [项目结构](#项目结构) + - [服务端](#服务端) + - [插件 UI 界面](#插件-ui-界面) +- [插件部署与发布](#插件部署与发布) + - [插件 Shield](#插件-shield) +- [链接](#链接) + +## 插件构成 + +一个 LobeChat 的插件由以下几个部分组成: + +1. **插件索引**:用于展示插件的基本信息,包括插件名称、描述、作者、版本、插件描述清单的链接,官方的插件索引地址:[lobe-chat-plugins](https://github.com/lobehub/lobe-chat-plugins)。若想上架插件到官方插件市场,需要 [提交 PR](https://github.com/lobehub/lobe-chat-plugins/pulls) 到该仓库; +2. **插件描述清单 (manifest)**:用于描述插件的功能实现,包含了插件的服务端描述、前端展示信息、版本号等。关于 manifest 的详细介绍,详见 [manifest][manifest-docs-url]; +3. **插件服务**:用于实现插件描述清单中所描述的服务端和前端模块,分别如下: + - **服务端**:需要实现 manifest 中描述的 `api` 部分的接口能力; + - **前端 UI**(可选):需要实现 manifest 中描述的 `ui` 部分的界面,该界面将会在插件消息中透出,进而实现比文本更加丰富的信息展示方式。 + +
+ +## 自定义插件流程 + +本节将会介绍如何在 LobeChat 中添加和使用一个自定义插件。 + +### **`1`** 创建并启动插件项目 + +你需要先在本地创建一个插件项目,可以使用我们准备好的模板 [lobe-chat-plugin-template][lobe-chat-plugin-template-url] + +```bash +$ git clone https://github.com/lobehub/chat-plugin-template.git +$ cd chat-plugin-template +$ npm i +$ npm run dev +``` + +当出现`ready started server on 0.0.0.0:3400, url: http://localhost:3400` 时,说明插件服务已经在本地启动成功。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259526-9ef25272-4312-429b-93bc-a95515727ed3.png) + +### **`2`** 在 LobeChat 角色设置中添加本地插件 + +接下来进入到 LobeChat 中,创建一个新的助手,并进入它的会话设置页: + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259643-1a9cc34a-76f3-4ccf-928b-129654670efd.png) + +点击插件列表右侧的 添加 按钮,打开自定义插件添加弹窗: + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259748-2ef6a244-39bb-483c-b359-f156ffcbe1a4.png) + +在 **插件描述文件 Url** 地址 中填入 `http://localhost:3400/manifest-dev.json` ,这是我们本地启动的插件描述清单地址。 + +此时,你应该可以看到看到插件的标识符一栏已经被自动识别为 `chat-plugin-template`。接下来你需要填写剩下的表单字段(只有标题必填),然后点击 保存 按钮,即可完成自定义插件添加。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265259964-59f4906d-ae2e-4ec0-8b43-db36871d0869.png) + +完成添加后,在插件列表中就能看到刚刚添加的插件,如果需要修改插件的配置,可以点击最右侧的 设置 按钮进行修改。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260093-a0363c74-0b5b-48dd-b103-2db6b4a8262e.png) + +### **`3`** 会话测试插件功能 + +接来下我们需要测试这个插件的功能是否正常。 + +点击 返回 按钮回到会话区,然后向助手发送消息:「我应该穿什么? 」此时助手将会尝试向你询问,了解你的性别与当前的心情。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260291-f0aa0e7c-0ffb-486c-a834-08e73d49896f.png) + +当回答完毕后,助手将会发起插件的调用,根据你的性别、心情,从服务端获取推荐的衣服数据,并推送给你。最后基于这些信息做一轮文本总结。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265260461-c22ae797-2809-464b-96fc-d0c020f4807b.png) + +当完成这些操作后,你已经了解了添加自定义插件,并在 LobeChat 中使用的基础流程。 + +
+ +## 本地插件开发 + +在上述流程中,我们已经了解插件的添加和使用的方式,接下来重点介绍自定义插件开发的过程。 + +### manifest + +`manifest` 聚合了插件功能如何实现的信息。核心字段为 `api` 与 `ui`,分别描述了插件的服务端接口能力与前端渲染的界面地址。 + +以我们提供的模板中的 `manifest` 为例: + +```json +{ + "api": [ + { + "url": "http://localhost:3400/api/clothes", + "name": "recommendClothes", + "description": "根据用户的心情,给用户推荐他有的衣服", + "parameters": { + "properties": { + "mood": { + "description": "用户当前的心情,可选值有:开心(happy), 难过(sad),生气 (anger),害怕(fear),惊喜( surprise),厌恶 (disgust)", + "enums": ["happy", "sad", "anger", "fear", "surprise", "disgust"], + "type": "string" + }, + "gender": { + "type": "string", + "enum": ["man", "woman"], + "description": "对话用户的性别,需要询问用户后才知道这个信息" + } + }, + "required": ["mood", "gender"], + "type": "object" + } + } + ], + "gateway": "http://localhost:3400/api/gateway", + "identifier": "chat-plugin-template", + "ui": { + "url": "http://localhost:3400", + "height": 200 + }, + "version": "1" +} +``` + +在这份 manifest 中,主要包含了以下几个部分: + +1. `identifier`:这是插件的唯一标识符,用来区分不同的插件,这个字段需要全局唯一。 +2. `api`:这是一个数组,包含了插件的所有 API 接口信息。每个接口都包含了 url、name、description 和 parameters 字段,均为必填项。其中 `description` 和 `parameters` 两个字段,将会作为 [Function Call](https://sspai.com/post/81986) 的 `functions` 参数发送给 gpt, parameters 需要符合 [JSON Schema](https://json-schema.org/) 规范。 在这个例子中,api 接口名为 `recommendClothes` ,这个接口的功能是根据用户的心情和性别来推荐衣服。接口的参数包括用户的心情和性别,这两个参数都是必填项。 +3. `ui`:这个字段包含了插件的用户界面信息,指明了 LobeChat 从哪个地址加载插件的前端界面。由于 LobeChat 插件界面加载是基于 iframe 实现的,因此可以按需指定插件界面的高度、宽度。 +4. `gateway`:这个字段指定了 LobeChat 查询 api 接口的网关。LobeChat 默认的插件网关是云端服务,而自定义插件的请求需要发给本地启动的服务,远端调用本地地址,一般调用不通。gateway 字段解决了该问题。通过在 manifest 中指定 gateway,LobeChat 将会向该地址发送插件请求,本地的网关地址将会调度请求到本地的插件服务。发布到线上的插件可以不用指定该字段。 +5. `version`:这是插件的版本号,现阶段暂时没有作用; + +在实际开发中,你可以根据自己的需求,修改插件的描述清单,声明想要实现的功能。 关于 manifest 各个字段的完整介绍,参见:[manifest][manifest-docs-url]。 + +### 项目结构 + +[lobe-chat-plugin-template][lobe-chat-plugin-template-url] 这个模板项目使用了 Next.js 作为开发框架,它的核心目录结构如下: + +``` +➜ chat-plugin-template +├── public +│ └── manifest-dev.json # 描述清单文件 +├── src +│ └── pages +│ │ ├── api # nextjs 服务端文件夹 +│ │ │ ├── clothes.ts # recommendClothes 接口实现 +│ │ │ └── gateway.ts # 本地插件代理网关 +│ │ └── index.tsx # 前端展示界面 +``` + +本模板使用 Next.js 作为开发框架。你可以使用任何你熟悉的开发框架与开发语言,只要能够实现 manifest 中描述的功能即可。 + +同时也欢迎大家贡献更多框架与语言的插件模板。 + +### 服务端 + +服务端需要实现 manifest 中描述的 api 接口。在模板中,我们使用了 vercel 的 [Edge Runtime](https://nextjs.org/docs/pages/api-reference/edge),免去运维。 + +#### API 实现 + +针对 Edge Runtime ,我们在 `@lobehub/chat-plugin-sdk` 提供了 `createErrorResponse` 方法,用于快速返回错误响应。目前提供的错误类型详见:[PluginErrorType][plugin-error-type-url]。 + +模板中的 clothes 接口实现如下: + +```ts +export default async (req: Request) => { + if (req.method !== 'POST') return createErrorResponse(PluginErrorType.MethodNotAllowed); + + const { gender, mood } = (await req.json()) as RequestData; + + const clothes = gender === 'man' ? manClothes : womanClothes; + + const result: ResponseData = { + clothes: clothes[mood] || [], + mood, + today: Date.now(), + }; + + return new Response(JSON.stringify(result)); +}; +``` + +其中 `maniClothes` 和 `womanClothes` 是 mock 数据,在实际场景中,可以替换为数据库查询等。 + +#### Plugin Gateway + +由于 LobeChat 默认的插件网关是云端服务 `/api/plugins`,云端服务通过 manifest 上的 `api.url` 地址发送请求,以解决跨域问题。 + +针对自定义插件,插件请求需要发送给本地服务, 因此通过在 manifest 中指定网关 (),LobeChat 将会直接请求该地址,然后只需要在该地址下创建对应的网关即可。 + +```ts +import { createLobeChatPluginGateway } from '@lobehub/chat-plugins-gateway'; + +export const config = { + runtime: 'edge', +}; + +export default async createLobeChatPluginGateway(); +``` + +[`@lobehub/chat-plugins-gateway`](https://github.com/lobehub/chat-plugins-gateway) 包含了 LobeChat 中插件网关的[实现](https://github.com/lobehub/lobe-chat/blob/main/src/pages/api/plugins.api.ts),你可以直接使用该包创建网关,进而让 LobeChat 访问到本地的插件服务。 + +### 插件 UI 界面 + +自定义插件的 UI 界面是一个可选项。例如 官方插件 [「🧩 / 🕸 网页内容提取」](https://github.com/lobehub/chat-plugin-web-crawler),没有实现相应的用户界面。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263241-0e765fdc-3463-4c36-a398-aef177a30df9.png) + +如果你希望在插件消息中展示更加丰富的信息,或者包含一些富交互操作,你可以为插件定制一个用户界面。例如下图则为[「搜索引擎」](https://github.com/lobehub/chat-plugin-search-engine)插件的用户界面。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263427-9bdc03d5-aa61-4f62-a2ce-88683f3308d8.png) + +#### 插件 UI 界面实现 + +LobeChat 通过 `iframe` 实现插件 ui 的加载,使用 `postMessage` 实现主体与插件的通信。因此, 插件 UI 的实现方式与普通的网页开发一致,你可以使用任何你熟悉的前端框架与开发语言。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/265263653-4ea87abc-249a-49f3-a241-7ed93ddb1ddf.png) + +在我们提供的模板中使用了 React + Next.js + [antd](https://ant.design/) 作为前端界面框架,你可以在 [`src/pages/index.tsx`](https://github.com/lobehub/chat-plugin-template/blob/main/src/pages/index.tsx) 中找到用户界面的实现。 + +其中关于插件通信,我们在 [`@lobehub/chat-plugin-sdk`](https://github.com/lobehub/chat-plugin-sdk) 提供了相关方法,用于简化插件与 LobeChat 的通信。你可以通过 `fetchPluginMessage` 方法主动向 LobeChat 获取当前消息的数据。关于该方法的详细介绍,参见:[fetchPluginMessage][fetch-plugin-message-url]。 + +```tsx +import { fetchPluginMessage } from '@lobehub/chat-plugin-sdk'; +import { memo, useEffect, useState } from 'react'; + +import { ResponseData } from '@/type'; + +const Render = memo(() => { + const [data, setData] = useState(); + + useEffect(() => { + // 从 LobeChat 获取当前插件的消息 + fetchPluginMessage().then((e: ResponseData) => { + setData(e); + }); + }, []); + + return <>...; +}); + +export default Render; +``` + +
+ +## 插件部署与发布 + +当你完成插件的开发后,你可以使用你习惯的方式进行插件的部署。例如使用 vercel ,或者打包成 docker 发布等等。 + +如果你希望插件被更多人使用,欢迎将你的插件 [提交上架](https://github.com/lobehub/lobe-chat-plugins) 到插件市场。 + +[![][submit-plugin-shield]][submit-plugin-url] + +### 插件 Shield + +[![lobe-chat-plugin](https://img.shields.io/badge/%F0%9F%A4%AF%20%26%20%F0%9F%A7%A9%20LobeHub-Plugin-95f3d9?labelColor=black&style=flat-square)](https://github.com/lobehub/lobe-chat-plugins) + +```markdown +[![lobe-chat-plugin](https://img.shields.io/badge/%F0%9F%A4%AF%20%26%20%F0%9F%A7%A9%20LobeHub-Plugin-95f3d9?labelColor=black&style=flat-square)](https://github.com/lobehub/lobe-chat-plugins) +``` + +
+ +## 链接 + +- **📘 Pluging SDK 文档**: +- **🚀 chat-plugin-template**: +- **🧩 chat-plugin-sdk**: +- **🚪 chat-plugin-gateway**: +- **🏪 lobe-chat-plugins**: + + + +[fetch-plugin-message-url]: https://github.com/lobehub/chat-plugin-template +[lobe-chat-plugin-template-url]: https://github.com/lobehub/chat-plugin-template +[manifest-docs-url]: https://chat-plugin-sdk.lobehub.com/guides/plugin-manifest +[plugin-error-type-url]: https://github.com/lobehub/chat-plugin-template +[submit-plugin-shield]: https://img.shields.io/badge/🧩/🏪_submit_plugin-%E2%86%92-95f3d9?labelColor=black&style=for-the-badge +[submit-plugin-url]: https://github.com/lobehub/lobe-chat-plugins diff --git a/docs/Upstream-Sync.md b/docs/Upstream-Sync.md new file mode 100644 index 0000000000000..a9fe4510a1422 --- /dev/null +++ b/docs/Upstream-Sync.md @@ -0,0 +1,18 @@ +# Maintaining Updates with LobeChat Self-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 Fork 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. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/266985117-4d48fe7b-0412-4667-8129-b25ebcf2c9de.png) +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/266985177-7677b4ce-c348-4145-9f60-829d448d5be6.png) diff --git a/docs/Upstream-Sync.zh-CN.md b/docs/Upstream-Sync.zh-CN.md new file mode 100644 index 0000000000000..f806f34433421 --- /dev/null +++ b/docs/Upstream-Sync.zh-CN.md @@ -0,0 +1,18 @@ +# LobeChat 自部署保持更新 + +如果你根据 README 中的一键部署步骤部署了自己的项目,你可能会发现总是被提示 “有可用更新”。这是因为 Vercel 默认为你创建新项目而非 fork 本项目,这将导致无法准确检测更新。我们建议按照以下步骤重新部署: + +- 删除原有的仓库; +- 使用页面右上角的 Fork 按钮,Fork 本项目; +- 在 `Vercel` 上重新选择并部署。 + +## 启动自动更新 + +> \[!NOTE] +> +> 如果你在执行 `Upstream Sync` 时遇到错误,请手动执再行一次 + +当你 Fork 了项目后,由于 Github 的限制,你需要手动在你 Fork 的项目的 Actions 页面启用 Workflows,并启动 Upstream Sync Action。启用后,你可以设置每小时进行一次自动更新。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/266985117-4d48fe7b-0412-4667-8129-b25ebcf2c9de.png) +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/266985177-7677b4ce-c348-4145-9f60-829d448d5be6.png) diff --git a/docs/Usage-Agents.md b/docs/Usage-Agents.md new file mode 100644 index 0000000000000..b01f13f03701f --- /dev/null +++ b/docs/Usage-Agents.md @@ -0,0 +1,201 @@ +# Custom Agents Guide + +#### TOC + +- [Adding Custom Agents](#adding-custom-agents) + - [`A` Add through the Agent Marketplace](#a-add-through-the-agent-marketplace) + - [`B` Create a Custom Agent](#b-create-a-custom-agent) +- [Basic Concepts of Prompts](#basic-concepts-of-prompts) + - [How to write a structured prompt](#how-to-write-a-structured-prompt) + - [How to improve quality and effectiveness](#how-to-improve-quality-and-effectiveness) +- [Model Concepts](#model-concepts) + - [ChatGPT](#chatgpt) +- [Model Parameter Concepts](#model-parameter-concepts) + - [`temperature`](#temperature) + - [`top_p`](#top_p) + - [`presence_penalty`](#presence_penalty) + - [`frequency_penalty`](#frequency_penalty) +- [Further Reading](#further-reading) + +## Adding Custom Agents + +As the fundamental unit of LobeChat, adding and iterating on agents is crucial. Now you can add agents to your favorites list in two ways: + +### `A` Add through the Agent Marketplace + +If you're new to writing prompts, you might want to browse the Agent Marketplace in LobeChat. Here, you can find commonly used agents submitted by others and add them to your list with just one click, making it very convenient. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279588466-4c32041b-a8e6-4703-ba4a-f91b7800e359.png) + +### `B` Create a Custom Agent + +When you need to handle specific tasks, you'll want to consider creating a custom agent to help you solve the problem. You can add and configure the agent in detail using the following steps: + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279587283-a3ea8dfd-70fb-47ee-ab00-e3911ac6a939.png) +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279587292-a3d102c6-f61e-4578-91f1-c0a4c97588e1.png) + +> \[!NOTE] +> +> Quick setting tip: You can conveniently modify the prompt by using the quick edit button in the sidebar. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279587294-388d1877-193e-4a50-9fe8-8fbcc3ccefa0.png) +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279587298-333da153-13b8-4557-a0a2-cff55e7bc1c0.png) + +Continue reading to understand the writing techniques and common model parameter settings for prompts. + +
+ +## Basic Concepts of Prompts + +Generative AI is very useful, but it requires human guidance. In most cases, generative AI is like a capable intern who needs clear instructions to perform well. Being able to guide generative AI correctly is a powerful skill. You can guide generative AI by sending a prompt, which is typically a text instruction. The prompt is the input you provide to the agent, and it will influence the output. A good prompt should be structured, clear, concise, and directive. + +### How to write a structured prompt + +> \[!TIP] +> +> A structured prompt refers to the construction of the prompt having clear logic and structure. For example, if you want the model to generate an article, your prompt may need to include the topic of the article, its outline, and its style. + +Let's look at a basic example of a discussion question: + +> _"What are the most urgent environmental issues our planet faces, and what can individuals do to help address these problems?"_ + +We can turn this into a simple prompt by answering the following question upfront. + +``` +Answer the following question: +What are the most urgent environmental issues our planet faces, and what can individuals do to help address these problems? +``` + +Since the results generated by this prompt are inconsistent, with some only consisting of one or two sentences, it is not ideal for a typical discussion answer that should have multiple paragraphs. A good prompt should provide specific formatting and content instructions. You need to eliminate ambiguity in the language to improve consistency and quality. Here's a better prompt: + +``` +Write an in-depth essay that includes an introduction, body paragraphs, and a conclusion, answering the following question: +What are the most urgent environmental issues our planet faces, and what can individuals do to help address these problems? +``` + +The second prompt generates longer outputs with better structure. The use of the word "essay" in the prompt is intentional because agent can understand the definition of an essay, making it more likely to generate coherent and structured answers. + +
+ +### How to improve quality and effectiveness + +> \[!TIP] +> +> There are several ways to improve the quality and effectiveness of prompts: +> +> - Be as clear as possible about your needs. The model will try to fulfill your requirements, so if your requirements are not clear, the output may not meet your expectations. +> - Use correct grammar and spelling. The model will try to mimic your language style, so if your language style is problematic, the output may also be problematic. +> - Provide sufficient contextual information. The model will generate output based on the contextual information you provide, so if you provide insufficient contextual information, it may not be able to generate the desired results. + +After formulating effective prompts for discussion questions, you now need to refine the generated results. This may involve adjusting the output to fit constraints such as word count or combining concepts from different generated results. + +A simple iteration method is to generate multiple outputs and examine them to understand the concepts and structure used by agent. Once the outputs have been evaluated, you can select the most suitable ones and combine them into a coherent answer. Another iterative approach is to start gradually and then expand step by step. This requires more than one prompt: an initial prompt for writing the first one or two paragraphs, followed by additional prompts to expand on the content already written. Here's a potential philosophical discussion prompt: + +> _"Is mathematics invented or discovered? Explain your answer with careful reasoning."_ + +Add it to a simple prompt like this: + +``` +Write an opening paragraph answering the following question: +Is mathematics invented or discovered? Explain your answer with careful reasoning. +``` + +I generated a few answers and found one that I liked: + +``` +Philosophers and mathematicians have debated whether mathematics is invented or discovered. +Some argue that the concepts and principles of mathematics exist independently of human thought, so they can be considered discovered rather than invented. +For example, the concepts of numbers, ratios, and geometric shapes are observed in the natural world and can be abstracted and studied systematically. +``` + +It's a good start. Then I used another prompt to expand: + +``` +I'm writing a detailed essay answering the following prompt: +Is mathematics invented or discovered? Explain your answer with careful reasoning. Here's where I'm at so far: Philosophers and mathematicians have debated whether mathematics is invented or discovered. +Some argue that the concepts and principles of mathematics exist independently of human thought, so they can be considered discovered rather than invented. +For example, the concepts of numbers, ratios, and geometric shapes are observed in the natural world and can be abstracted and studied systematically. Write the next paragraph of my essay. +``` + +I used this prompt to generate several expansions and selected one that I liked, resulting in the following: + +``` +Philosophers and mathematicians have debated whether mathematics is invented or discovered. +Some argue that the concepts and principles of mathematics exist independently of human thought, so they can be considered discovered rather than invented. +For example, the concepts of numbers, ratios, and geometric shapes are observed in the natural world and can be abstracted and studied systematically. +On the other hand, some argue that mathematics is largely an invention of human thought. +Mathematical principles are based on logical reasoning, which is a characteristic of human thought. +For example, Euclidean geometry is based on abstract axioms and assumptions that are accepted as true without needing to be proven. +Therefore, geometry can be seen as an invention of human thought rather than a discovery. +Similarly, mathematical formulas and equations are used to model and predict physical phenomena, which are the result of human reasoning. +``` + +Using expansion prompts, we can gradually write and iterate at each step. This is useful for situations where you need to generate higher-quality output and want to make incremental modifications. + +
+ +## Model Concepts + +### ChatGPT + +- **gpt-3.5-turbo**: The fastest generating chatgpt model currently available, but it may sacrifice some text quality. The context length is 4k. +- **gpt-3.5-turbo-16k**: Same as gpt-4, but with an increased context limit of 16k tokens and a higher cost rate. +- **gpt-4**: ChatGPT 4.0 has improved language understanding and generation capabilities compared to 3.5. It has a better understanding of context and can generate more accurate and natural responses. This is due to improvements in the GPT-4 model, including better language modeling and deeper semantic understanding, but it may be slower than other models. The context length is 8k. +- **gpt-4-32k**: Same as gpt-4, but with an increased context limit of 32k tokens and a higher cost rate. + +
+ +## Model Parameter Concepts + +LLM may seem magical, but it is essentially a probability problem. The neural network generates a set of candidate words from the pre-trained model based on the input text and selects the highest probability as the output. Most of the related parameters are about sampling (i.e., how to select the output from the candidate words). + +### `temperature` + +Controls the randomness of the model's output. Higher values increase randomness. In general, if you input the same prompt multiple times, the model's output will be different each time. + +- Set to 0 for a fixed output for each prompt. +- Lower values make the output more focused and deterministic. +- Higher values make the output more random and creative. + +> \[!NOTE] +> +> Generally, the longer and clearer the prompt, the better the quality and confidence of the generated output. In this case, you can increase the temperature value. Conversely, if the prompt is short and ambiguous, setting a higher temperature value will make the model's output less stable. + +
+ +### `top_p` + +Top-p nucleus sampling is another sampling parameter that is different from temperature. Before the model generates the output, it generates a set of tokens. In top-p sampling mode, the candidate word list is dynamic and selected from the tokens based on a percentage. Top-p introduces randomness to the selection of tokens, allowing other high-scoring tokens to have a chance of being selected instead of always choosing the highest-scoring one. + +> \[!NOTE] +> +> Top-p is similar to randomness. In general, it is not recommended to change it together with the randomness parameter, temperature. + +
+ +### `presence_penalty` + +The presence penalty parameter can be seen as a punishment for repetitive content in the generated text. When this parameter is set high, the generative model will try to avoid generating repeated words, phrases, or sentences. Conversely, if the presence penalty parameter is low, the generated text may contain more repeated content. By adjusting the value of the presence penalty parameter, you can control the originality and diversity of the generated text. The importance of this parameter is mainly reflected in the following aspects: + +- Increasing the originality and diversity of the generated text: In some application scenarios, such as creative writing or generating news headlines, it is desirable for the generated text to have high originality and diversity. By increasing the value of the presence penalty parameter, the probability of generating repeated content in the generated text can be effectively reduced, thereby improving its originality and diversity. +- Preventing generation loops and meaningless content: In some cases, the generative model may produce repetitive and meaningless text that fails to convey useful information. By appropriately increasing the value of the presence penalty parameter, the probability of generating this type of meaningless content can be reduced, thereby improving the readability and usefulness of the generated text. + +> \[!NOTE] +> +> It is worth noting that the presence penalty parameter, along with other parameters such as temperature and top-p, collectively affect the quality of the generated text. Compared to other parameters, the presence penalty parameter focuses more on the originality and repetitiveness of the text, while the temperature and top-p parameters have a greater impact on the randomness and determinism of the generated text. By adjusting these parameters properly, comprehensive control of the quality of the generated text can be achieved. + +
+ +### `frequency_penalty` + +Frequency penalty is a mechanism that penalizes frequent occurrences of new vocabulary in the generated text, reducing the likelihood of the model repeating the same words. The higher the value, the more likely it is to reduce repeated words. + +- `-2.0` When the morning news starts playing, I noticed that my TV now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now _(The most frequent word is "now" with a percentage of 44.79%)_ +- `-1.0` He always watches the news in the morning, watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching watching _(The most frequent word is "watching" with a percentage of 57.69%)_ +- `0.0` When the morning sun shines into the small restaurant, a tired mailman appears at the door, holding a bag of mail in his hand. The owner warmly prepares breakfast for him, and he starts sorting the mail while enjoying his breakfast. **_(The most frequent word is "the" with a percentage of 8.45%)_** +- `1.0` A deep sleep girl is awakened by a warm sunbeam. She sees the first ray of sunlight in the morning, surrounded by the sounds of birds and the fragrance of flowers, everything is full of vitality. _(The most frequent word is "the" with a percentage of 5.45%)_ +- `2.0` Every morning, he sits on the balcony to have breakfast. In the gentle sunset, everything looks very peaceful. However, one day, as he was about to pick up his breakfast, an optimistic little bird flew by, bringing him a good mood for the day. _(The most frequent word is "the" with a percentage of 4.94%)_ + +## Further Reading + +- **Learn Prompting** - diff --git a/docs/Usage-Agents.zh-CN.md b/docs/Usage-Agents.zh-CN.md new file mode 100644 index 0000000000000..11064e5cb173a --- /dev/null +++ b/docs/Usage-Agents.zh-CN.md @@ -0,0 +1,202 @@ +# 自定义助手指南 + +#### TOC + +- [添加自定义助手](#添加自定义助手) + - [`A` 通过角色市场添加](#a-通过角色市场添加) + - [`B` 通过新建自定义助手](#b-通过新建自定义助手) +- [Prompt 基本概念](#prompt-基本概念) + - [如何写好一个结构化 prompt](#如何写好一个结构化-prompt) + - [如何提升其质量和效果](#如何提升其质量和效果) +- [模型的概念](#模型的概念) + - [ChatGPT](#chatgpt) +- [模型参数概念](#模型参数概念) + - [`temperature`](#temperature) + - [`top_p`](#top_p) + - [`presence_penalty`](#presence_penalty) + - [`frequency_penalty`](#frequency_penalty) +- [扩展阅读](#扩展阅读) + +## 添加自定义助手 + +作为 LobeChat 的基础职能单位,助手的添加和迭代是非常重要的。现在你可以通过两种方式将助手添加到你的常用列表中 + +### `A` 通过角色市场添加 + +如果你是一个 Prompt 编写的新手,不妨先浏览一下 LobeChat 的助手市场。在这里,你可以找到其他人提交的常用助手,并且只需一键添加到你的列表中,非常方便。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279588466-4c32041b-a8e6-4703-ba4a-f91b7800e359.png) + +### `B` 通过新建自定义助手 + +当你需要处理一些特定的任务时,你就需要考虑创建一个自定义助手来帮助你解决问题。可以通过以下方式添加并进行助手的详细配置 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279587283-a3ea8dfd-70fb-47ee-ab00-e3911ac6a939.png) +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279587292-a3d102c6-f61e-4578-91f1-c0a4c97588e1.png) + +> \[!NOTE] +> +> 快捷设置技巧:可以通过侧边栏的快捷编辑按钮进行 Prompt 的便捷修改 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279587294-388d1877-193e-4a50-9fe8-8fbcc3ccefa0.png) +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279587298-333da153-13b8-4557-a0a2-cff55e7bc1c0.png) + +请继续阅读下文,理解 Prompt 编写技巧和常见的模型参数设置 + +
+ +## Prompt 基本概念 + +生成式 AI 非常有用,但它需要人类指导。通常情况下,生成式 AI 能就像公司新来的实习生一样,非常有能力,但需要清晰的指示才能做得好。能够正确地指导生成式 AI 是一项非常强大的技能。你可以通过发送一个 prompt 来指导生成式 AI,这通常是一个文本指令。Prompt 是向助手提供的输入,它会影响输出结果。一个好的 Prompt 应该是结构化的,清晰的,简洁的,并且具有指向性。 + +### 如何写好一个结构化 prompt + +> \[!TIP] +> +> 结构化 prompt 是指 prompt 的构造应该有明确的逻辑和结构。例如,如果你想让模型生成一篇文章,你的 prompt 可能需要包括文章的主题,文章的大纲,文章的风格等信息。 + +让我们看一个基本的讨论问题的例子: + +> _"我们星球面临的最紧迫的环境问题是什么,个人可以采取哪些措施来帮助解决这些问题?"_ + +我们可以将其转化为简单的助手提示,将回答以下问题:放在前面。 + +``` +回答以下问题: +我们星球面临的最紧迫的环境问题是什么,个人可以采取哪些措施来帮助解决这些问题? +``` + +由于这个提示生成的结果并不一致,有些只有一两个句子。一个典型的讨论回答应该有多个段落,因此这些结果并不理想。一个好的提示应该给出**具体的格式和内容指令**。您需要消除语言中的歧义以提高一致性和质量。这是一个更好的提示。 + +``` +写一篇高度详细的论文,包括引言、正文和结论段,回答以下问题: +我们星球面临的最紧迫的环境问题是什么, +个人可以采取哪些措施来帮助解决这些问题? +``` + +第二个提示生成了更长的输出和更好的结构。提示中使用 “论文” 一词是有意的,因为助手可以理解论文的定义,因此更有可能生成连贯的、结构化的回答。 + +
+ +### 如何提升其质量和效果 + +> \[!TIP] +> +> 提升 prompt 质量和效果的方法主要有以下几点: +> +> - 尽量明确你的需求。模型的输出会尽可能满足你的需求,所以如果你的需求不明确,输出可能会不如预期。 +> - 使用正确的语法和拼写。模型会尽可能模仿你的语言风格,所以如果你的语言风格有问题,输出可能也会有问题。 +> - 提供足够的上下文信息。模型会根据你提供的上下文信息生成输出,所以如果你提供的上下文信息不足,可能无法生成你想要的结果。 + +在为讨论问题制定有效的提示后,您现在需要细化生成的结果。这可能涉及到调整输出以符合诸如字数等限制,或将不同生成的结果的概念组合在一起。 + +迭代的一个简单方法是生成多个输出并查看它们,以了解正在使用的概念和结构。一旦评估了输出,您就可以选择最合适的输出并将它们组合成一个连贯的回答。另一种迭代的方法是逐步开始,然后**逐步扩展**。这需要不止一个提示:一个起始提示,用于撰写最初的一两段,然后是其他提示,以扩展已经写过的内容。以下是一个潜在的哲学讨论问题: + +> _"数学是发明还是发现?用仔细的推理来解释你的答案。"_ + +将其添加到一个简单的提示中,如下所示: + +``` +写一个起始段回答以下问题: +数学是发明还是发现?用仔细的推理来解释你的答案。 +``` + +我生成了一些回答,找到了一个我喜欢的: + +``` +哲学家和数学家之间争论不休,数学是发明还是发现。 +一些人认为,数学的概念和原则独立于人类思维存在,因此可以被认为是被发现而不是被发明的。 +例如,数字、比率和几何形状的概念在自然界中被观察到,可以被抽象化和系统化地研究。 +``` + +是一个不错的开端。然后我使用另一个提示来扩展: + +``` +我正在撰写一篇详细的短文,回答以下提示: +数学是发明还是发现?用仔细的推理来解释你的答案。这是我目前的情况: 哲学家和数学家之间争论不休,数学是发明还是发现。 +一些人认为,数学的概念和原则独立于人类思维存在,因此可以被认为是被发现而不是被发明的。 +例如,数字、比率和几何形状的概念在自然界中被观察到,可以被抽象化和系统化地研究。写下我文章的下一段。 +``` + +我使用此提示生成了几个扩展,并选择了一个我喜欢的,最终得到了以下结果: + +``` +哲学家和数学家之间争论不休,数学是发明还是发现。 +一些人认为,数学的概念和原则独立于人类思维存在,因此可以被认为是被发现而不是被发明的。 +例如,数字、比率和几何形状的概念在自然界中被观察到,可以被抽象化和系统化地研究。 +另一方面,有人认为数学在很大程度上是人类思维的发明。 +数学原理基于逻辑推理,这是人类思维的一个特征。 +例如,欧几里德几何基于抽象的公理和前提,被接受为真实而无需证明。 +因此,可以认为几何是人类思维的发明,而不是一种发现。 +同样,数学公式和方程用于模拟和预测物理现象,这又是人类推理的结果。 +``` + +使用扩展提示,我们可以逐步地写作并在每个步骤上进行迭代。这对于需要**生成更高质量的输出并希望逐步修改**的情况非常有用。 + +
+ +## 模型的概念 + +### ChatGPT + +- **gpt-3.5-turbo**:目前最生成速度最快的 chatgpt 模型更快,但可能会牺牲一些生成文本的质量,上下文长度为 4k。 +- **gpt-3.5-turbo-16k**:同 gpt-4,上下文限制增加到 16k token,同时费率更高。 +- **gpt-4**:ChatGPT 4.0 在语言理解和生成能力方面相对于 3.5 有所提升。它可以更好地理解上下文和语境,并生成更准确、自然的回答。这得益于 GPT-4 模型的改进,包括更好的语言建模和更深入的语义理解,但它的速度可能比其他模型慢,上下文长度为 8k。 +- **gpt-4-32k**:同 gpt-4,上下文限制增加到 32k token,同时费率更高。 + +
+ +## 模型参数概念 + +LLM 看似很神奇,但本质还是一个概率问题,神经网络根据输入的文本,从预训练的模型里面生成一堆候选词,选择概率高的作为输出,相关的参数,大多都是跟采样有关(也就是要如何从候选词里选择输出)。 + +### `temperature` + +用于控制模型输出的结果的随机性,这个值越大随机性越大。一般我们多次输入相同的 prompt 之后,模型的每次输出都不一样。 + +- 设置为 0,对每个 prompt 都生成固定的输出 +- 较低的值,输出更集中,更有确定性 +- 较高的值,输出更随机(更有创意 ) + +> \[!NOTE] +> +> 一般来说,prompt 越长,描述得越清楚,模型生成的输出质量就越好,置信度越高,这时可以适当调高 temperature 的值;反过来,如果 prompt 很短,很含糊,这时再设置一个比较高的 temperature 值,模型的输出就很不稳定了。 + +
+ +### `top_p` + +核采样 top_p 也是采样参数,跟 temperature 不一样的采样方式。模型在输出之前,会生成一堆 token,这些 token 根据质量高低排名,核采样模式中候选词列表是动态的,从 tokens 里按百分比选择候选词。 top-p 为选择 token 引入了随机性,让其他高分的 token 有被选择的机会,不会总是选最高分的。 + +> \[!NOTE] +> +> top_p 与随机性类似,一般来说不建议和随机性 temperature 一起更改 + +
+ +### `presence_penalty` + +Presence Penalty 参数可以看作是对生成文本中重复内容的一种惩罚。当该参数设置较高时,生成模型会尽量避免产生重复的词语、短语或句子。相反,如果 Presence Penalty 参数较低,则生成的文本可能会包含更多重复的内容。通过调整 Presence Penalty 参数的值,可以实现对生成文本的原创性和多样性的控制。参数的重要性主要体现在以下几个方面: + +- 提高生成文本的独创性和多样性:在某些应用场景下,如创意写作、生成新闻标题等,需要生成的文本具有较高的独创性和多样性。通过增加 Presence Penalty 参数的值,可以有效减少生成文本中的重复内容,从而提高文本的独创性和多样性。 +- 防止生成循环和无意义的内容:在某些情况下,生成模型可能会产生循环、重复的文本,这些文本通常无法传达有效的信息。通过适当增加 Presence Penalty 参数的值,可以降低生成这类无意义内容的概率,提高生成文本的可读性和实用性。 + +> \[!NOTE] +> +> 值得注意的是,Presence Penalty 参数与其他参数(如 Temperature 和 top-p)共同影响着生成文本的质量。对比其他参数,Presence Penalty 参数主要关注文本的独创性和重复性,而 Temperature 和 top-p 参数则更多地影响着生成文本的随机性和确定性。通过合理地调整这些参数,可以实现对生成文本质量的综合控制 + +
+ +### `frequency_penalty` + +是一种机制,通过对文本中频繁出现的新词汇施加惩罚,以减少模型重复同一词语的可能性,值越大,越有可能降低重复字词。 + +- `-2.0` 当早间新闻开始播出,我发现我家电视现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在现在 _(频率最高的词是 “现在”,占比 44.79%)_ +- `-1.0` 他总是在清晨看新闻,在电视前看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看看 _(频率最高的词是 “看”,占比 57.69%)_ +- `0.0` 当清晨的阳光洒进小餐馆时,一名疲倦的邮递员出现在门口,他的手中提着一袋信件。店主热情地为他准备了一份早餐,他在享用早餐的同时开始整理邮件。**(频率最高的词是 “的”,占比 8.45%)** +- `1.0` 一个深度睡眠的女孩被一阵温暖的阳光唤醒,她看到了早晨的第一缕阳光,周围是鸟语花香,一切都充满了生机。_(频率最高的词是 “的”,占比 5.45%)_ +- `2.0` 每天早上,他都会在阳台上坐着吃早餐。在柔和的夕阳照耀下,一切看起来都非常宁静。然而有一天,当他准备端起早餐的时候,一只乐观的小鸟飞过,给他带来了一天的好心情。 _(频率最高的词是 “的”,占比 4.94%)_ + +## 扩展阅读 + +- **Learn Prompting** - diff --git a/docs/Usage-Topics.md b/docs/Usage-Topics.md new file mode 100644 index 0000000000000..e2857182f4fc5 --- /dev/null +++ b/docs/Usage-Topics.md @@ -0,0 +1,31 @@ +# Topic Guide + +#### TOC + +- [Explanation of Agent and Topic Concepts](#explanation-of-agent-and-topic-concepts) +- [User Guide](#user-guide) + +## Explanation of Agent and Topic Concepts + +In the official ChatGPT app, there is only the concept of topics, as shown in the figure, the sidebar contains the user's historical conversation topic list. + +> \[!NOTE] +> +> However, in our use, we actually find that this mode has many problems, such as the information indexing of historical conversations is too scattered, and when dealing with some repetitive tasks, it is difficult to have a stable entrance. For example, I hope there is a stable entrance to allow ChatGPT to help me translate documents. In this mode, I need to constantly create new topics and then set the translation Prompt I created before. When there are high-frequency tasks, this will be a very low-efficiency interaction form. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279602474-fe7cb3f3-8eb7-40d3-a69f-6615393bbd4e.png) + +Therefore, in LobeChat, we introduced the concept of `Agent`. The agent is a complete functional module, and each agent has its own responsibilities and tasks. The agent can help you handle various tasks and provide professional advice and guidance. + +At the same time, we index the topic into each agent. The advantage of this is that each agent has an independent topic list, you can choose the corresponding agent according to the current task, and quickly switch historical conversation records. This way is more in line with the user's use habits of common chat software, and improves the interaction efficiency. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279602489-89893e61-2791-4083-9b57-ed80884ad58b.png) + +
+ +## User Guide + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279602496-fd72037a-735e-4cc2-aa56-2994bceaba81.png) + +- **Save Topic:** During the chat, if you want to save the current context and start a new topic, you can click the save button next to the send button. +- **Topic List:** Clicking on the topic in the list can quickly switch historical conversation records and continue the conversation. You can also click the star icon ⭐️ to bookmark the topic to the top, or rename and delete the topic through the more button on the right. diff --git a/docs/Usage-Topics.zh-CN.md b/docs/Usage-Topics.zh-CN.md new file mode 100644 index 0000000000000..67e151982706c --- /dev/null +++ b/docs/Usage-Topics.zh-CN.md @@ -0,0 +1,31 @@ +# 话题指南 + +#### TOC + +- [助手与话题概念解析](#助手与话题概念解析) +- [使用指南](#使用指南) + +## 助手与话题概念解析 + +在 ChatGPT 官方应用中,只存在话题的概念,如图所示,在侧边栏中是用户的历史对话话题列表。 + +> \[!NOTE] +> +> 但在我们的使用过程中其实会发现这种模式存在很多问题,比如历史对话的信息索引过于分散问题,同时当处理一些重复任务时很难有一个稳定的入口,比如我希望有一个稳定的入口可以让 ChatGPT 帮助我翻译文档,在这个模式下,我需要不断新建新的话题同时再设置我之前创建好的翻译 Prompt 设定,当有高频任务存在时,这将是一个效率很低的交互形式。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279602474-fe7cb3f3-8eb7-40d3-a69f-6615393bbd4e.png) + +因此在 LobeChat 中,我们引入了 **助手** 的概念。助手是一个完整的功能模块,每个助手都有自己的职责和任务。助手可以帮助你处理各种任务,并提供专业的建议和指导。 + +与此同时,我们将话题索引到每个助手内部。这样做的好处是,每个助手都有一个独立的话题列表,你可以根据当前任务选择对应的助手,并快速切换历史对话记录。这种方式更符合用户对常见聊天软件的使用习惯,提高了交互的效率。 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279602489-89893e61-2791-4083-9b57-ed80884ad58b.png) + +
+ +## 使用指南 + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/17870709/279602496-fd72037a-735e-4cc2-aa56-2994bceaba81.png) + +- **保存话题:** 在聊天过程中,如果想要保存当前上下文并开启新的话题,可以点击发送按钮旁边的保存按钮。 +- **话题列表:** 点击列表中的话题可以快速切换历史对话记录,并继续对话。你还可以通过点击星标图标 ⭐️ 将话题收藏置顶,或者通过右侧更多按钮对话题进行重命名和删除操作。 diff --git a/docs/_Footer.md b/docs/_Footer.md new file mode 100644 index 0000000000000..8711bffc64689 --- /dev/null +++ b/docs/_Footer.md @@ -0,0 +1 @@ +This is the **🤯 / 🤖 Lobe Chat** wiki. [Wiki Home](https://github.com/lobehub/lobe-chat/wiki) diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md new file mode 100644 index 0000000000000..00c71e69d3080 --- /dev/null +++ b/docs/_Sidebar.md @@ -0,0 +1,40 @@ +## Lobe Chat Wiki + +#### 🏠 Home + +- [TOC](Home) | [目录](Home) + +#### 🤯 LobeChat Usage + +- [Custom Agents Guide](Usage-Agents) | [中文](Usage-Agents.zh-CN) +- [Topics Guide](Usage-Topics) | [中文](Usage-Topics.zh-CN) + +#### 🛳 Self Hosting + +- [Environment Variables](Environment-Variable) | [中文](Environment-Variable.zh-CN) +- [Upstream Sync](Upstream-Sync) | [中文](Upstream-Sync.zh-CN) +- [Deploying with Azure OpenAI](Deploy-with-Azure-OpenAI) | [中文](Deploy-with-Azure-OpenAI.zh-CN) +- [Docker Deployment Guide](Docker-Deployment) | [中文](Docker-Deployment.zh-CN) + +#### 🤖 Agents + +- [Agent Index][agent-index] | [中文][agent-index-cn] + +#### 🧩 Plugins + +- [Plugin Index][plugin-index] | [中文][plugin-index-cn] +- [Plugin Development](Plugin-Development) | [中文](Plugin-Development.zh-CN) +- [Plugin SDK Docs][plugin-sdk] | [中文][plugin-skd-cn] + +#### 📊 Other + +- [Lighthouse Report](Lighthouse) | [中文](Lighthouse.zh-CN) + + + +[agent-index]: https://github.com/lobehub/lobe-chat-agents +[agent-index-cn]: https://github.com/lobehub/lobe-chat-agents/blob/main/README.zh-CN.md +[plugin-index]: https://github.com/lobehub/lobe-chat-plugins +[plugin-index-cn]: https://github.com/lobehub/lobe-chat-plugins/blob/main/README.zh-CN.md +[plugin-sdk]: https://chat-plugin-sdk.lobehub.com +[plugin-skd-cn]: https://chat-plugin-sdk.lobehub.com diff --git a/lobe-chat-main.zip b/lobe-chat-main.zip new file mode 100644 index 0000000000000..56e9af99c2053 Binary files /dev/null and b/lobe-chat-main.zip differ diff --git a/locales/en_US/chat.json b/locales/en_US/chat.json new file mode 100644 index 0000000000000..cf14c7947ea3e --- /dev/null +++ b/locales/en_US/chat.json @@ -0,0 +1,80 @@ +{ + "agentDefaultMessage": "Hello, I'm **{{name}}**. You can start chatting with me right away or go to [Agent Settings](/chat/settings#session={{id}}) to improve my information.", + "agentDefaultMessageWithSystemRole": "Hello, I'm **{{name}}**, {{systemRole}}. Let's start the conversation!", + "backToBottom": "Go to Latest Messages", + "clearCurrentMessages": "Clear Current Session Messages", + "confirmClearCurrentMessages": "You are about to clear the current session messages. Once cleared, they cannot be recovered. Please confirm your operation.", + "confirmRemoveSessionItemAlert": "You are about to delete this agent. Once deleted, it cannot be recovered. Please confirm your operation.", + "defaultAgent": "Custom Agent", + "defaultSession": "Custom Agent", + "historyRange": "History Range", + "inbox": { + "defaultMessage": "Hello, I'm your intelligent agent. You can ask me any questions, and I will do my best to answer you. If you need a more professional or customized agent, you can click on `+` to create a custom agent.", + "desc": "Activate brain clusters and spark thinking. Your intelligent agent is here to communicate with you about everything.", + "title": "Chat Randomly" + }, + "newAgent": "Create New Agent", + "noDescription": "No description available", + "pin": "Pin", + "pinOff": "Unpin", + "regenerate": "Regenerate", + "roleAndArchive": "Roles and Archives", + "searchAgentPlaceholder": "Search agents and conversations...", + "send": "Send", + "sendPlaceholder": "Enter chat content...", + "sessionList": "Agent List", + "shareModal": { + "download": "Download Screenshot", + "imageType": "Image Format", + "screenshot": "Screenshot", + "settings": "Export Settings", + "shareToShareGPT": "Generate ShareGPT Sharing Link", + "withBackground": "Include Background Image", + "withFooter": "Include Footer", + "withPluginInfo": "Include Plugin Information", + "withSystemRole": "Include Agent Role Setting" + }, + "stop": "Stop", + "stt": { + "action": "Voice Input", + "loading": "Recognizing...", + "prettifying": "Prettifying..." + }, + "temp": "Temporary", + "tokenDetail": "Role Setting: {{systemRoleToken}} · Chat History: {{chatsToken}}", + "tokenTag": { + "overload": "Exceeded Limit", + "remained": "Remaining", + "used": "Used" + }, + "topic": { + "confirmRemoveTopic": "You are about to delete this topic. Once deleted, it cannot be recovered. Please proceed with caution.", + "defaultTitle": "Default Topic", + "saveCurrentMessages": "Save Current Session as Topic", + "searchPlaceholder": "Search topics...", + "deleteAll": "Delete All Topics", + "deleteUnstarred": "Delete Unstarred Topics", + "title": "Topic List", + "confirmRemoveAll": "All topics will be deleted and cannot be recovered. Please proceed with caution.", + "confirmRemoveUnstarred": "All unstarred topics will be deleted and cannot be recovered. Please proceed with caution.", + "removeAll": "Remove All Topics", + "removeUnstarred": "Remove Unstarred Topics", + "openNewTopic": "Open a new topic" + }, + "translate": { + "clear": "Clear Translation", + "action": "Translate" + }, + "translateTo": "Translate", + "tts": { + "action": "Text to Speech", + "clear": "Clear Speech" + }, + "updateAgent": "Update Agent Information", + "upload": { + "actionTooltip": "Upload Image", + "dragDesc": "Drag and drop files here, supports uploading multiple images. Hold Shift to send images directly", + "dragTitle": "Upload Image" + }, + "warp": "Line Break" +} diff --git a/locales/en_US/common.json b/locales/en_US/common.json new file mode 100644 index 0000000000000..255f290b3be0a --- /dev/null +++ b/locales/en_US/common.json @@ -0,0 +1,71 @@ +{ + "about": "About", + "advanceSettings": "Advanced Settings", + "agentMaxToken": "Max Session Length", + "agentModel": "Model", + "agentProfile": "Agent Profile", + "appInitializing": "ChatGPT Power is initializing, please wait...", + "archive": "Archive", + "autoGenerate": "Auto Generate", + "autoGenerateTooltip": "Auto generate agent description based on prompts", + "cancel": "Cancel", + "changelog": "Changelog", + "close": "Close", + "confirmRemoveSessionItemAlert": "You are about to delete this agent. Once deleted, it cannot be recovered. Please confirm your action.", + "copy": "Copy", + "copySuccess": "Copy Successful", + "defaultAgent": "Custom Agent", + "defaultSession": "Custom Agent", + "delete": "Delete", + "edit": "Edit", + "export": "Export Configuration", + "exportType": { + "agent": "Export Agent Settings", + "agentWithMessage": "Export Agent and Messages", + "all": "Export Global Settings and All Agent Data", + "allAgent": "Export All Agent Settings", + "allAgentWithMessage": "Export All Agents and Messages", + "globalSetting": "Export Global Settings" + }, + "feedback": "Feedback", + "historyRange": "History Range", + "import": "Import Configuration", + "lang": { + "en": "English", + "en-US": "English", + "es-ES": "Spanish", + "ja-JP": "Japanese", + "ko-KR": "Korean", + "ru-RU": "Russian", + "zh": "Simplified Chinese", + "zh-CN": "Simplified Chinese", + "zh-TW": "Traditional Chinese" + }, + "layoutInitializing": "Loading layout...", + "noDescription": "No description", + "ok": "OK", + "password": "Password", + "pin": "Pin", + "pinOff": "Unpin", + "regenerate": "Regenerate", + "rename": "Rename", + "reset": "Reset", + "retry": "Retry", + "send": "Send", + "sessionList": "Agent List", + "setting": "Settings", + "share": "Share", + "stop": "Stop", + "tab": { + "chat": "Chat", + "market": "Discover", + "setting": "Settings" + }, + "temp": "Temporary", + "updateAgent": "Update Agent Profile", + "upgradeVersion": { + "action": "Upgrade Now", + "hasNew": "Update available", + "newVersion": "New version available: {{version}}" + } +} diff --git a/locales/en_US/empty.json b/locales/en_US/empty.json new file mode 100644 index 0000000000000..318e0910a947a --- /dev/null +++ b/locales/en_US/empty.json @@ -0,0 +1,6 @@ +{ + "topic": { + "desc": "Click the button on the left to save the current conversation as a historical topic and start a new conversation", + "title": "Topic List" + } +} diff --git a/locales/en_US/error.json b/locales/en_US/error.json new file mode 100644 index 0000000000000..da53f0f8f8de6 --- /dev/null +++ b/locales/en_US/error.json @@ -0,0 +1,51 @@ +{ + "pluginSettings": { + "desc": "Complete the following configuration to start using this plugin", + "title": "{{name}} Plugin Settings" + }, + "response": { + "400": "Sorry, the server does not understand your request. Please make sure your request parameters are correct.", + "401": "Sorry, the server has rejected your request, possibly due to insufficient permissions or invalid authentication.", + "403": "Sorry, the server has rejected your request. You do not have permission to access this content.", + "404": "Sorry, the server cannot find the page or resource you requested. Please make sure your URL is correct.", + "405": "Sorry, the server does not support the request method you are using. Please make sure your request method is correct.", + "429": "Sorry, your request is too frequent and the server is a bit tired. Please try again later.", + "500": "Sorry, the server seems to be experiencing some difficulties and is temporarily unable to complete your request. Please try again later.", + "502": "Sorry, the server seems to be lost and is temporarily unable to provide service. Please try again later.", + "503": "Sorry, the server is currently unable to process your request, possibly due to overload or maintenance. Please try again later.", + "504": "Sorry, the server did not receive a response from the upstream server. Please try again later.", + "InvalidAccessCode": "The password is incorrect or empty. Please enter the correct access password or add a custom OpenAI API Key.", + "OpenAIBizError": "Error requesting OpenAI service. Please troubleshoot or retry based on the following information.", + "PluginMarketIndexNotFound": "Sorry, the server could not find the plugin index. Please check if the index address is correct", + "PluginMarketIndexInvalid": "Sorry, the plugin index validation failed. Please check if the index file format is correct", + "PluginMetaNotFound": "Sorry, the plugin was not found in the index. Please check the plugin's configuration information in the index", + "PluginMetaInvalid": "Sorry, the plugin's metadata validation failed. Please check if the plugin metadata format is correct", + "PluginManifestNotFound": "Sorry, the server could not find the plugin's manifest file (manifest.json). Please check if the plugin manifest file address is correct", + "PluginManifestInvalid": "Sorry, the plugin's manifest validation failed. Please check if the manifest format is correct", + "PluginApiNotFound": "Sorry, the API does not exist in the plugin's manifest. Please check if your request method matches the plugin manifest API", + "PluginApiParamsError": "Sorry, the input parameter validation for the plugin request failed. Please check if the input parameters match the API description", + "PluginSettingsInvalid": "This plugin needs to be correctly configured before it can be used. Please check if your configuration is correct", + "PluginServerError": "Plugin server request returned an error. Please check your plugin manifest file, plugin configuration, or server implementation based on the error information below", + "NoAPIKey": "OpenAI API Key is empty, please add a custom OpenAI API Key" + }, + "stt": { + "responseError": "Service request failed, please check the configuration or try again" + }, + "tts": { + "responseError": "Service request failed, please check the configuration or try again" + }, + "unlock": { + "apikey": { + "title": "Use Custom API Key", + "description": "Enter your OpenAI API Key to start the conversation. The application will not record your API Key.", + "addProxyUrl": "Add OpenAI Proxy URL (optional)" + }, + "confirm": "Confirm and Retry", + "password": { + "description": "The application encryption has been enabled by the administrator. Enter the application password to unlock the application. The password only needs to be filled in once.", + "title": "Enter Password to Unlock Application", + "placeholder": "Please enter password" + }, + "closeMessage": "Close message" + } +} diff --git a/locales/en_US/market.json b/locales/en_US/market.json new file mode 100644 index 0000000000000..f38ddd175e01e --- /dev/null +++ b/locales/en_US/market.json @@ -0,0 +1,30 @@ +{ + "addAgent": "Add Agent", + "guide": { + "func1": { + "desc1": "Enter the settings page you want to submit to the assistant by clicking on the settings icon in the upper right corner of the chat window.", + "desc2": "Click on the 'Submit to Assistant Market' button in the upper right corner.", + "tag": "Method 1", + "title": "Submit via ChatGPT Power" + }, + "func2": { + "button": "Go to Github Assistant Repository", + "desc": "If you want to add the assistant to the index, create an entry in the plugins directory using agent-template.json or agent-template-full.json, write a brief description and appropriate tags, and then create a pull request.", + "tag": "Method 2", + "title": "Submit via Github" + } + }, + "search": { + "placeholder": "Search agent name, description or keywords..." + }, + "sidebar": { + "comment": "Comments", + "prompt": "Prompts", + "title": "Agent Details" + }, + "submitAgent": "Submit Agent", + "title": { + "recentSubmits": "Recent Submits", + "allAgents": "All Agents" + } +} diff --git a/locales/en_US/plugin.json b/locales/en_US/plugin.json new file mode 100644 index 0000000000000..0299373f767f9 --- /dev/null +++ b/locales/en_US/plugin.json @@ -0,0 +1,129 @@ +{ + "debug": { + "arguments": "Arguments", + "function_call": "Function Call", + "response": "Response", + "off": "Turn off debug", + "on": "View plugin invocation information" + }, + "dev": { + "confirmDeleteDevPlugin": "Are you sure you want to delete this local plugin? Once deleted, it cannot be recovered.", + "deleteSuccess": "Plugin deleted successfully", + "manifest": { + "identifier": { + "desc": "The unique identifier of the plugin", + "label": "Identifier" + }, + "mode": { + "local": "Visual Configuration", + "local-tooltip": "Visual configuration is not supported at the moment", + "url": "Online Link" + }, + "name": { + "desc": "The title of the plugin", + "label": "Title", + "placeholder": "Search Engine" + } + }, + "meta": { + "author": { + "desc": "The author of the plugin", + "label": "Author" + }, + "avatar": { + "desc": "The icon of the plugin, can be an Emoji or a URL", + "label": "Icon" + }, + "description": { + "desc": "The description of the plugin", + "label": "Description", + "placeholder": "Get information from search engines" + }, + "formFieldRequired": "This field is required", + "homepage": { + "desc": "The homepage of the plugin", + "label": "Homepage" + }, + "identifier": { + "desc": "The unique identifier of the plugin, only supports alphanumeric characters, hyphen -, and underscore _", + "errorDuplicate": "The identifier is already used by another plugin, please modify the identifier", + "label": "Identifier", + "pattenErrorMessage": "Only alphanumeric characters, hyphen -, and underscore _ are allowed" + }, + "manifest": { + "desc": "ChatGPT Power will install the plugin using this link", + "invalid": "The input manifest link is invalid or does not comply with the specification", + "label": "Plugin Manifest URL", + "urlError": "Please enter a valid URL", + "jsonInvalid": "The manifest is not valid, validation result: \n\n {{error}}", + "preview": "Preview Manifest", + "refresh": "Refresh", + "requestError": "Failed to request the link, please enter a valid link and check if the link allows cross-origin access" + }, + "title": { + "desc": "The title of the plugin", + "label": "Title", + "placeholder": "Search Engine" + } + }, + "metaConfig": "Plugin metadata configuration", + "modalDesc": "After adding a custom plugin, it can be used for plugin development verification or directly in conversations. Please refer to the plugin development documentation for more information.", + "preview": { + "card": "Preview of plugin display", + "desc": "Preview of plugin description", + "title": "Plugin Name Preview" + }, + "save": "Save", + "saveSuccess": "Plugin settings saved successfully", + "tabs": { + "manifest": "Function Description Manifest (Manifest)", + "meta": "Plugin Metadata" + }, + "title": "Add Custom Plugin", + "update": "Update", + "updateSuccess": "Plugin settings updated successfully" + }, + "list": { + "item": { + "local.config": "Configuration", + "local.title": "Local", + "deprecated.title": "Deleted" + } + }, + "loading": { + "plugin": "Plugin is running...", + "content": "Calling plugin..." + }, + "pluginList": "Plugin List", + "plugins": { + "realtimeWeather": "Realtime Weather", + "searchEngine": "Search Engine", + "undefined": "Plugin Detection...", + "websiteCrawler": "Website Crawler", + "unknown": "Plugin detection in progress..." + }, + "realtimeWeather": { + "data": { + "date": "Date", + "daytemp_float": "Daytime Temperature", + "dayweather": "Daytime Weather", + "daywind": "Daytime Wind", + "nighttemp_float": "Nighttime Temperature", + "nightweather": "Nighttime Weather", + "nightwind": "Nighttime Wind", + "week": "Week" + }, + "title": "Weather Data for the Next 7 Days ({{city}})", + "updateAt": "Last Updated" + }, + "responseData": "Response Data", + "setting": "Plugin Settings", + "settings": { + "indexUrl": { + "title": "Marketplace Index", + "tooltip": "Editing is not supported at the moment" + }, + "modalDesc": "After configuring the address of the plugin marketplace, you can use a custom plugin marketplace", + "title": "Configure Plugin Marketplace" + } +} diff --git a/locales/en_US/setting.json b/locales/en_US/setting.json new file mode 100644 index 0000000000000..d94cafa482ddc --- /dev/null +++ b/locales/en_US/setting.json @@ -0,0 +1,297 @@ +{ + "danger": { + "clear": { + "action": "Clear Now", + "confirm": "Confirm clearing all chat data?", + "desc": "Clear all session data", + "success": "All session messages have been cleared", + "title": "Clear All Session Messages" + }, + "reset": { + "action": "Reset Now", + "confirm": "Confirm resetting all settings?", + "currentVersion": "Current Version", + "desc": "Reset all settings to default values", + "title": "Reset All Settings" + } + }, + "header": { + "global": "Global Settings", + "session": "Session Settings", + "sessionWithName": "Session Settings · {{name}}" + }, + "llm": { + "AzureOpenAI": { + "endpoint": { + "desc": "This value can be found in the Keys and Endpoints section when checking out a resource on an Azure site.", + "placeholder": "https://docs-test-001.openai.azure.com", + "title": "Azure API URL" + }, + "models": { + "desc": "Supported models", + "title": "List of models" + }, + "title": "Azure OpenAI Settings", + "token": { + "desc": "This value can be found in the Keys and Endpoints section when checking out a resource on an Azure site. You can use KEY1 or KEY2", + "placeholder": "Azure API Key", + "title": "API Key" + } + }, + "OpenAI": { + "azureApiVersion": { + "desc": "Azure API version in YYYY-MM-DD format, check [latest version](https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions)", + "fetch": "Get list", + "title": "Azure API version" + }, + "check": { + "button": "Check", + "desc": "Check that the Api Key and proxy server address are filled in correctly.", + "pass": "Connection successful", + "title": "Checking connectivity" + }, + "endpoint": { + "desc": "Must contain http(s):// in addition to the default address.", + "placeholder": "https://api.openai.com/v1", + "title": "API proxy address" + }, + "models": { + "count": "Total supported models: {{count}}", + "desc": "Supported models", + "fetch": "Fetching the list of models", + "notSupport": "Azure OpenAI currently does not support viewing lists of models", + "notSupportTip": "Make sure that the deployment name matches the model name", + "refetch": "Fetching the list of models", + "title": "List of models" + }, + "title": "OpenAI Settings", + "token": { + "desc": "Use your own OpenAI key", + "placeholder": "OpenAI API Key", + "title": "API Key" + }, + "useAzure": { + "desc": "Using OpenAI services from Azure", + "fetch": "Get list", + "title": "Azure OpenAI", + "serverConfig": "The administrator has enabled Azure OpenAI on the server side, switching is prohibited" + }, + "customModelName": { + "desc": "Add custom models, separate multiple models with commas (,)", + "placeholder": "model1,model2,model3", + "title": "Custom Model Name" + } + }, + "waitingForMore": "<1>Access to other models is planned, so stay tuned ✨" + }, + "settingAgent": { + "avatar": { + "title": "Avatar" + }, + "backgroundColor": { + "title": "Background Color" + }, + "description": { + "placeholder": "Please enter agent description", + "title": "Agent Description" + }, + "name": { + "placeholder": "Please enter agent name", + "title": "Name" + }, + "prompt": { + "placeholder": "Please enter role prompt", + "title": "Role Prompt" + }, + "tag": { + "placeholder": "Please enter tag", + "title": "Tag" + }, + "title": "Agent Information" + }, + "settingChat": { + "chatStyleType": { + "title": "Chat Window Style", + "type": { + "chat": "Chat Mode", + "docs": "Document Mode" + } + }, + "compressThreshold": { + "desc": "When the uncompressed history messages exceed this value, compression will be performed", + "title": "History Message Length Compression Threshold" + }, + "enableCompressThreshold": { + "title": "Enable History Message Length Compression Threshold" + }, + "enableHistoryCount": { + "alias": "Unlimited", + "limited": "Only include {{number}} session messages", + "title": "Limit History Message Count", + "unlimited": "Unlimited History Message Count" + }, + "historyCount": { + "desc": "Number of history messages carried in each request", + "title": "Attached History Message Count" + }, + "inputTemplate": { + "desc": "The latest user message will be filled into this template", + "placeholder": "{{text}} will be replaced with real-time input information", + "title": "User Input Preprocessing" + }, + "title": "Chat Settings", + "autoCreateTopicThreshold": { + "title": "Message Threshold", + "desc": "Automatically create a topic when the current message count exceeds this value" + }, + "enableAutoCreateTopic": { + "title": "Enable Auto Topic Creation", + "desc": "Whether to automatically create a topic during the conversation, only effective in temporary topics" + } + }, + "settingModel": { + "enableMaxTokens": { + "title": "Enable Single Reply Limit" + }, + "frequencyPenalty": { + "desc": "The larger the value, the more likely it is to reduce repeated words", + "title": "Frequency Penalty" + }, + "maxTokens": { + "desc": "Maximum number of tokens used in a single interaction", + "title": "Single Reply Limit" + }, + "model": { + "desc": "ChatGPT Model", + "list": { + "gpt-3.5-turbo": "GPT 3.5", + "gpt-3.5-turbo-16k": "GPT 3.5 (16K)", + "gpt-4": "GPT 4", + "gpt-4-32k": "GPT 4 (32K)" + }, + "title": "Model" + }, + "presencePenalty": { + "desc": "The larger the value, the more likely it is to expand to new topics", + "title": "Topic Freshness" + }, + "temperature": { + "desc": "The larger the value, the more random the reply", + "title": "Randomness", + "titleWithValue": "Randomness {{value}}" + }, + "title": "Model Settings", + "topP": { + "desc": "Similar to randomness, but do not change together with randomness", + "title": "Nucleus Sampling" + } + }, + "settingOpenAI": { + "endpoint": { + "desc": "Must include http(s)://, in addition to the default address", + "placeholder": "https://api.openai.com/v1", + "title": "API Proxy Address" + }, + "title": "OpenAI Settings", + "token": { + "desc": "Use your own OpenAI Key", + "placeholder": "OpenAI API Key", + "title": "API Key" + } + }, + "settingPlugin": { + "title": "Plugin List", + "add": "Add", + "addTooltip": "Add custom plugin", + "config": "{{id}} Plugin Configuration", + "clearDeprecated": "Remove Deprecated Plugins", + "settings": "Plugin Marketplace Settings" + }, + "settingSystem": { + "accessCode": { + "desc": "Encryption access has been enabled by the administrator", + "placeholder": "Please enter access password", + "title": "Access Password" + }, + "title": "System Settings" + }, + "settingTTS": { + "showAllLocaleVoice": { + "desc": "If disabled, only voices for the current language will be displayed", + "title": "Show all locale voices" + }, + "sttService": { + "desc": "The 'browser' option refers to the native speech recognition service in the browser", + "title": "Speech-to-Text Service" + }, + "title": "Speech Services", + "ttsService": { + "desc": "If using the OpenAI text-to-speech service, ensure that the OpenAI model service is enabled", + "title": "Text-to-Speech Service" + }, + "voice": { + "title": "Text-to-Speech Voices", + "desc": "Select a voice for the current assistant, different TTS services support different voices", + "preview": "Preview Voice" + }, + "openai": { + "sttModel": "OpenAI Speech Recognition Model", + "ttsModel": "OpenAI Text-to-Speech Model" + }, + "stt": "Speech Recognition Settings", + "sttLocale": { + "desc": "The language of the speech input, this option can improve the accuracy of speech recognition", + "title": "Speech Recognition Language" + }, + "sttPersisted": { + "desc": "When enabled, speech recognition will not automatically end and requires manual click on the end button", + "title": "Manually End Speech Recognition" + }, + "tts": "Text-to-Speech Settings", + "sttAutoStop": { + "desc": "When disabled, speech recognition will not automatically stop and will require manual intervention to end the process.", + "title": "Automatic Speech Recognition Termination" + } + }, + "settingTheme": { + "avatar": { + "title": "Avatar" + }, + "fontSize": { + "desc": "Font size of chat content", + "title": "Font Size" + }, + "lang": { + "title": "Language Settings", + "autoMode": "Follow System" + }, + "neutralColor": { + "desc": "Custom grayscale for different color tendencies", + "title": "Neutral Color" + }, + "primaryColor": { + "desc": "Custom theme color", + "title": "Theme Color" + }, + "themeMode": { + "auto": "Auto", + "dark": "Dark", + "light": "Light", + "title": "Theme" + }, + "title": "Theme Settings" + }, + "submitAgentModal": { + "tooltips": "Share to Assistant Market", + "button": "Submit Assistant", + "identifier": "Identifier", + "metaMiss": "Please complete the assistant information before submitting. It should include name, description, and tags.", + "placeholder": "Please enter a unique identifier for the assistant, such as web-development." + }, + "tab": { + "agent": "Default Agent", + "common": "Common Settings", + "llm": "Custom LLM API", + "tts": "Speech Services" + } +} diff --git a/locales/en_US/welcome.json b/locales/en_US/welcome.json new file mode 100644 index 0000000000000..6f8d561012d01 --- /dev/null +++ b/locales/en_US/welcome.json @@ -0,0 +1,14 @@ +{ + "button": { + "import": "Import Configuration", + "start": "Start Now" + }, + "header": "Welcome", + "pickAgent": "Or choose from the following agent templates", + "skip": "Skip Creation", + "slogan": { + "desc1": "Pioneering the new age of thinking and creating. Built for you, the Super Individual.", + "desc2": "Create your first agent and let's get started~", + "title": "Unlock the superpower of your brain" + } +} diff --git a/locales/es_ES/chat.json b/locales/es_ES/chat.json new file mode 100644 index 0000000000000..4623dd9395a31 --- /dev/null +++ b/locales/es_ES/chat.json @@ -0,0 +1,80 @@ +{ + "agentDefaultMessage": "Hola, me llamo **{{name}}**. Puedes empezar a chatear conmigo ahora mismo o ir a [Configuración del agente](/chat/settings#session={{id}}) para mejorar mi información.", + "agentDefaultMessageWithSystemRole": "Hola, me llamo**{{name}}**, {{systemRole}}. ¡Empecemos la conversación!", + "backToBottom": "Ir a Últimos mensajes", + "clearCurrentMessages": "Borrar mensajes de la sesión actual", + "confirmClearCurrentMessages": "Está a punto de borrar los mensajes de la sesión actual. Una vez borrados, no podrán recuperarse. Confirme la operación.", + "confirmRemoveSessionItemAlert": "Está a punto de eliminar este agente. Una vez borrado, no se puede recuperar. Por favor, confirme su operación.", + "defaultAgent": "Agente personalizado", + "defaultSession": "Agente personalizado", + "historyRange": "Rango de historia", + "inbox": { + "defaultMessage": "Hola, soy tu agente inteligente. Puedes hacerme cualquier pregunta y haré todo lo posible por responderte. Si necesitas un agente más profesional o personalizado, puedes hacer clic en `+` para crear un agente personalizado.", + "desc": "Active los grupos cerebrales y despierte el pensamiento. Su agente inteligente está aquí para comunicarse con usted acerca de todo.", + "title": "Chatear al azar" + }, + "newAgent": "Crear nuevo agente", + "noDescription": "No hay descripción disponible", + "pin": "Pin", + "pinOff": "Sin pin", + "regenerate": "Regenerar", + "roleAndArchive": "Roles y archivos", + "searchAgentPlaceholder": "Agentes de búsqueda y conversaciones...", + "send": "Enviar", + "sendPlaceholder": "Introducir el contenido del chat...", + "sessionList": "Lista de agentes", + "shareModal": { + "download": "Descargar captura de pantalla", + "imageType": "Formato de imagen", + "screenshot": "Captura de pantalla", + "settings": "Ajustes de exportación", + "shareToShareGPT": "Generar enlace para compartir ShareGPT", + "withBackground": "Incluir imagen de fondo", + "withFooter": "Incluir pie de página", + "withPluginInfo": "Incluir información del plugin", + "withSystemRole": "Incluir configuración del rol del agente" + }, + "stop": "Detener", + "stt": { + "action": "Entrada de voz", + "loading": "Reconociendo...", + "prettifying": "Embellecer..." + }, + "temp": "Temporal", + "tokenDetail": "Ajuste de roles: {{systemRoleToken}} · Historia del chat: {{chatsToken}}", + "tokenTag": { + "overload": "Límite superado", + "remained": "Restante", + "used": "Usado" + }, + "topic": { + "confirmRemoveTopic": "Está a punto de borrar este tema. Una vez borrado, no se puede recuperar. Por favor, proceda con precaución.", + "defaultTitle": "Tema por defecto", + "saveCurrentMessages": "Guardar la sesión actual como tema", + "searchPlaceholder": "Buscar temas...", + "deleteAll": "Eliminar todos los temas", + "deleteUnstarred": "Eliminar temas no destacados", + "title": "Lista de temas", + "confirmRemoveAll": "Todos los temas se eliminarán y no se podrán recuperar. Proceda con precaución.", + "confirmRemoveUnstarred": "Todos los temas no destacados se eliminarán y no se podrán recuperar. Proceda con precaución.", + "removeAll": "Eliminar todos los temas", + "removeUnstarred": "Eliminar temas no destacados", + "openNewTopic": "Abrir un nuevo tema" + }, + "translate": { + "clear": "Traducción clara", + "action": "Traducir" + }, + "translateTo": "Traducir", + "tts": { + "action": "Texto a voz", + "clear": "Discurso claro" + }, + "updateAgent": "Actualizar información del agente", + "upload": { + "actionTooltip": "Cargar imagen", + "dragDesc": "Arrastre y suelte archivos aquí, admite la carga de varias imágenes. Mantenga presionada la tecla Mayús para enviar imágenes directamente", + "dragTitle": "Cargar imagen" + }, + "warp": "Salto de línea" +} diff --git a/locales/es_ES/common.json b/locales/es_ES/common.json new file mode 100644 index 0000000000000..2d35ae69463d2 --- /dev/null +++ b/locales/es_ES/common.json @@ -0,0 +1,71 @@ +{ + "about": "Acerca de", + "advanceSettings": "Configuración avanzada", + "agentMaxToken": "Duración máxima de la sesión", + "agentModel": "Modelo", + "agentProfile": "Perfil del agente", + "appInitializing": "ChatGPT Power se está inicializando, por favor espere...", + "archive": "Archivo", + "autoGenerate": "Generación automática", + "autoGenerateTooltip": "Generación automática de la descripción del agente en función de las indicaciones", + "cancel": "Cancelar", + "changelog": "Registro de cambios", + "close": "Cerrar", + "confirmRemoveSessionItemAlert": "Está a punto de eliminar este agente. Una vez borrado, no se puede recuperar. Por favor, confirme su acción.", + "copy": "Copiar", + "copySuccess": "Copia correcta", + "defaultAgent": "Agente personalizado", + "defaultSession": "Agente personalizado", + "delete": "Borrar", + "edit": "Editar", + "export": "Exportar Configuración", + "exportType": { + "agent": "Configuración del agente de exportación", + "agentWithMessage": "Agente exportador y mensajes", + "all": "Exportar la configuración global y todos los datos del agente", + "allAgent": "Exportar todos los ajustes del agente", + "allAgentWithMessage": "Exportar todos los agentes y mensajes", + "globalSetting": "Exportar ajustes globales" + }, + "feedback": "Comentarios", + "historyRange": "Historial", + "import": "Importar configuración", + "lang": { + "en": "Inglés", + "en-US": "Inglés", + "es-ES": "Español", + "ja-JP": "Japones", + "ko-KR": "Koreano", + "ru-RU": "Ruso", + "zh": "Chino simplificado", + "zh-CN": "Chino simplificado", + "zh-TW": "Chino tradicional" + }, + "layoutInitializing": "Cargando diseño...", + "noDescription": "Sin descripción", + "ok": "OK", + "password": "Contraseña", + "pin": "Pin", + "pinOff": "Sin Pin", + "regenerate": "Regenerar", + "rename": "Renombrar", + "reset": "Resetear", + "retry": "Reintentar", + "send": "Enviar", + "sessionList": "Lista de agentes", + "setting": "Configuración", + "share": "Compartir", + "stop": "Detener", + "tab": { + "chat": "Chat", + "market": "Descubrir", + "setting": "Configuración" + }, + "temp": "Temporal", + "updateAgent": "Actualizar perfil de agente", + "upgradeVersion": { + "action": "Actualizar ahora", + "hasNew": "Actualización disponible", + "newVersion": "Nueva versión disponible: {{version}}" + } +} diff --git a/locales/es_ES/empty.json b/locales/es_ES/empty.json new file mode 100644 index 0000000000000..a1f3704ff25b8 --- /dev/null +++ b/locales/es_ES/empty.json @@ -0,0 +1,6 @@ +{ + "topic": { + "desc": "Haz clic en el botón de la izquierda para guardar la conversación actual como tema histórico e iniciar una nueva conversación.", + "title": "Lista de asuntos" + } +} diff --git a/locales/es_ES/error.json b/locales/es_ES/error.json new file mode 100644 index 0000000000000..bb5fc84a1d052 --- /dev/null +++ b/locales/es_ES/error.json @@ -0,0 +1,51 @@ +{ + "pluginSettings": { + "desc": "Complete la siguiente configuración para empezar a utilizar este plugin", + "title": "{{name}} Configuración del plugin" + }, + "response": { + "400": "Lo sentimos, el servidor no entiende su solicitud. Por favor, asegúrese de que los parámetros de su petición son correctos", + "401": "Lo sentimos, el servidor ha rechazado su solicitud, posiblemente debido a permisos insuficientes o autenticación no válida", + "403": "Lo sentimos, el servidor ha rechazado su solicitud. No tiene permiso para acceder a este contenido", + "404": "Lo sentimos, el servidor no puede encontrar la página o el recurso que ha solicitado. Por favor, asegúrese de que su URL es correcta", + "405": "Lo sentimos, el servidor no admite el método de solicitud que está utilizando. Por favor, asegúrese de que su método de solicitud es correcto", + "429": "Lo sentimos, su solicitud es demasiado frecuente y el servidor está un poco cansado. Vuelva a intentarlo más tarde", + "500": "Lo sentimos, el servidor parece estar experimentando algunas dificultades y es temporalmente incapaz de completar su solicitud. Por favor, inténtelo de nuevo más tarde", + "502": "Lo sentimos, el servidor parece estar perdido y es temporalmente incapaz de proporcionar servicio. Por favor, inténtelo de nuevo más tarde", + "503": "Lo sentimos, el servidor no puede procesar actualmente su solicitud, posiblemente debido a sobrecarga o mantenimiento. Por favor, inténtelo de nuevo más tarde", + "504": "Lo sentimos, el servidor no ha recibido respuesta del servidor de origen. Vuelva a intentarlo más tarde", + "InvalidAccessCode": "La contraseña es incorrecta o está vacía. Introduzca la contraseña de acceso correcta o añada una clave de API de OpenAI personalizada.", + "OpenAIBizError": "Error al solicitar el servicio OpenAI. Solucione el problema o vuelva a intentarlo según la siguiente información.", + "PluginMarketIndexNotFound": "Lo sentimos, el servidor no ha podido encontrar el índice del plugin. Por favor, compruebe si la dirección del índice es correcta", + "PluginMarketIndexInvalid": "Lo sentimos, la validación del índice del plugin ha fallado. Por favor, compruebe si el formato del archivo de índice es correcto", + "PluginMetaNotFound": "Lo sentimos, el plugin no se ha encontrado en el índice. Por favor, compruebe la información de configuración del plugin en el índice", + "PluginMetaInvalid": "Lo sentimos, la validación de los metadatos del plugin ha fallado. Compruebe si el formato de los metadatos del complemento es correcto.", + "PluginManifestNotFound": "Lo sentimos, el servidor no ha podido encontrar el archivo de manifiesto del plugin (manifest.json). Por favor, compruebe si la dirección del archivo de manifiesto del plugin es correcta", + "PluginManifestInvalid": "Lo sentimos, la validación del manifiesto del plugin ha fallado. Por favor, compruebe si el formato del manifiesto es correcto", + "PluginApiNotFound": "Lo sentimos, la API no existe en el manifiesto del plugin. Compruebe si el método de solicitud coincide con la API del manifiesto del complemento.", + "PluginApiParamsError": "Lo sentimos, la validación de los parámetros de entrada para la solicitud del plugin ha fallado. Por favor, compruebe si los parámetros de entrada coinciden con la descripción de la API", + "PluginSettingsInvalid": "Este plugin necesita estar correctamente configurado antes de poder ser utilizado. Por favor, compruebe si su configuración es correcta", + "PluginServerError": "La solicitud del servidor del plugin ha devuelto un error. Compruebe el archivo de manifiesto del complemento, la configuración del complemento o la implementación del servidor en función de la información de error que aparece a continuación.", + "NoAPIKey": "La clave de API de OpenAI está vacía, por favor, añada una clave de API de OpenAI personalizada." + }, + "stt": { + "responseError": "Error en la solicitud de servicio, compruebe la configuración o inténtelo de nuevo." + }, + "tts": { + "responseError": "Error en la solicitud de servicio, compruebe la configuración o inténtelo de nuevo." + }, + "unlock": { + "apikey": { + "title": "Utilizar una clave API personalizada", + "description": "Introduce tu API Key de OpenAI para iniciar la conversación. La aplicación no registrará tu API Key.", + "addProxyUrl": "Añadir URL de proxy OpenAI (optional)" + }, + "confirm": "Confirmar y reintentar", + "password": { + "description": "El cifrado de la aplicación ha sido activado por el administrador. Introduzca la contraseña de la aplicación para desbloquearla. Solo es necesario introducir la contraseña una vez.", + "title": "Introduzca la contraseña para desbloquear la aplicación", + "placeholder": "Introduzca la contraseña" + }, + "closeMessage": "Cerrar mensaje" + } +} diff --git a/locales/es_ES/market.json b/locales/es_ES/market.json new file mode 100644 index 0000000000000..13e21e89474bf --- /dev/null +++ b/locales/es_ES/market.json @@ -0,0 +1,30 @@ +{ + "addAgent": "Añadir agente", + "guide": { + "func1": { + "desc1": "Introduzca la página de configuración que desea enviar al asistente haciendo clic en el icono de configuración situado en la esquina superior derecha de la ventana de chat.", + "desc2": "Pulse el botón 'Enviar al mercado auxiliar' en la esquina superior derecha.", + "tag": "Metodo 1", + "title": "Enviar a través de ChatGPT Power" + }, + "func2": { + "button": "Ir al repositorio Github Assistant", + "desc": "Si quieres añadir el asistente al índice, crea una entrada en el directorio de plugins usando agent-template.json o agent-template-full.json, escribe una breve descripción y las etiquetas apropiadas, y luego crea un pull request.", + "tag": "Metodo 2", + "title": "Enviar a través de Github" + } + }, + "search": { + "placeholder": "Buscar nombre de agente, descripción o palabras clave..." + }, + "sidebar": { + "comment": "Comentarios", + "prompt": "Prompts", + "title": "Detalles del agente" + }, + "submitAgent": "Enviar agente", + "title": { + "recentSubmits": "Envíos recientes", + "allAgents": "Todos los agentes" + } +} diff --git a/locales/es_ES/plugin.json b/locales/es_ES/plugin.json new file mode 100644 index 0000000000000..5017b752aff28 --- /dev/null +++ b/locales/es_ES/plugin.json @@ -0,0 +1,129 @@ +{ + "debug": { + "arguments": "Argumentos", + "function_call": "Llamada a función", + "response": "Respuesta", + "off": "Desactivar depuración", + "on": "Ver información sobre la invocación de plugins" + }, + "dev": { + "confirmDeleteDevPlugin": "¿Está seguro de que desea eliminar este plugin local? Una vez eliminado, no se puede recuperar.", + "deleteSuccess": "Plugin eliminado correctamente", + "manifest": { + "identifier": { + "desc": "Identificador único del plugin", + "label": "Identificador" + }, + "mode": { + "local": "Configuración visual", + "local-tooltip": "La configuración visual no es compatible por el momento", + "url": "Enlace en línea" + }, + "name": { + "desc": "El título del plugin", + "label": "Título", + "placeholder": "Motor de búsqueda" + } + }, + "meta": { + "author": { + "desc": "El autor del plugin", + "label": "Autor" + }, + "avatar": { + "desc": "El icono del plugin, puede ser un Emoji o una URL", + "label": "Icono" + }, + "description": { + "desc": "Descripción del plugin", + "label": "Descripción", + "placeholder": "Obtener información de los motores de búsqueda" + }, + "formFieldRequired": "Este campo es obligatorio", + "homepage": { + "desc": "La página de inicio del plugin", + "label": "Página de inicio" + }, + "identifier": { + "desc": "El identificador único del plugin, sólo admite caracteres alfanuméricos, guión - y guión bajo _.", + "errorDuplicate": "El identificador ya está siendo utilizado por otro plugin, por favor modifique el identificador", + "label": "Identificador", + "pattenErrorMessage": "Sólo se admiten caracteres alfanuméricos, guión - y guión bajo _." + }, + "manifest": { + "desc": "ChatGPT Power instalará el plugin usando este enlace", + "invalid": "El enlace del manifiesto de entrada no es válido o no cumple la especificación", + "label": "URL del manifiesto del plugin", + "urlError": "Introduzca una URL válida", + "jsonInvalid": "El manifiesto no es válido, resultado de la validación: \n\n {{error}}", + "preview": "Vista previa del Manifiesto", + "refresh": "Actualizar", + "requestError": "No se ha podido solicitar el enlace, por favor, introduzca un enlace válido y compruebe si el enlace permite el acceso entre orígenes." + }, + "title": { + "desc": "El título del plugin", + "label": "Título", + "placeholder": "Motor de búsqueda" + } + }, + "metaConfig": "Configuración de los metadatos del plugin", + "modalDesc": "Después de añadir un plugin personalizado, se puede utilizar para la verificación de desarrollo de plugins o directamente en las conversaciones. Consulte la documentación de desarrollo de plugins para obtener más información.", + "preview": { + "card": "Vista previa de la visualización del plugin", + "desc": "Vista previa de la descripción del plugin", + "title": "Vista previa del nombre del plugin" + }, + "save": "Guardar", + "saveSuccess": "La configuración del plugin se ha guardado correctamente", + "tabs": { + "manifest": "Función Descripción Manifiesto (Manifest)", + "meta": "Metadatos del plugin" + }, + "title": "Añadir plugin personalizado", + "update": "Actualización", + "updateSuccess": "La configuración del plugin se ha actualizado correctamente" + }, + "list": { + "item": { + "local.config": "Configuración", + "local.title": "Local", + "deprecated.title": "Borrado" + } + }, + "loading": { + "plugin": "El plugin se está ejecutando...", + "content": "Plugin de llamada..." + }, + "pluginList": "Lista de Plugins", + "plugins": { + "realtimeWeather": "El tiempo en tiempo real", + "searchEngine": "Motor de búsqueda", + "undefined": "Detección de plugins...", + "websiteCrawler": "Rastreador de sitios web", + "unknown": "Detección de plugins en curso..." + }, + "realtimeWeather": { + "data": { + "date": "Fecha", + "daytemp_float": "Temperatura diurna", + "dayweather": "Tiempo diurno", + "daywind": "Viento diurno", + "nighttemp_float": "Temperatura nocturna", + "nightweather": "Tiempo nocturno", + "nightwind": "Viento nocturno", + "week": "Semana" + }, + "title": "Datos meteorológicos para los próximos 7 días ({{city}})", + "updateAt": "Última actualización" + }, + "responseData": "Datos de respuesta", + "setting": "Configuración del plugin", + "settings": { + "indexUrl": { + "title": "Índice del mercado", + "tooltip": "Por el momento no es posible editar" + }, + "modalDesc": "Después de configurar la dirección del mercado de plugins, puede utilizar un mercado de plugins personalizado", + "title": "Configurar el mercado de plugins" + } +} diff --git a/locales/es_ES/setting.json b/locales/es_ES/setting.json new file mode 100644 index 0000000000000..11ed184023b89 --- /dev/null +++ b/locales/es_ES/setting.json @@ -0,0 +1,297 @@ +{ + "danger": { + "clear": { + "action": "Borrar ahora", + "confirm": "¿Confirmar el borrado de todos los datos del chat?", + "desc": "Borrar todos los datos de la sesión", + "success": "Se han borrado todos los mensajes de sesión", + "title": "Borrar todos los mensajes de sesión" + }, + "reset": { + "action": "Restablecer ahora", + "confirm": "¿Confirmar el restablecimiento de todos los ajustes?", + "currentVersion": "Versión actual", + "desc": "Restablecer todos los ajustes a los valores predeterminados", + "title": "Restablecer todos los ajustes" + } + }, + "header": { + "global": "Configuración Global", + "session": "Configuración de la sesión", + "sessionWithName": "Configuración de la sesión · {{name}}" + }, + "llm": { + "AzureOpenAI": { + "endpoint": { + "desc": "Este valor se puede encontrar en la sección Claves y puntos finales al comprobar un recurso en un sitio Azure.", + "placeholder": "https://docs-test-001.openai.azure.com", + "title": "Azure API URL" + }, + "models": { + "desc": "Modelos soportados", + "title": "Lista de modelos" + }, + "title": "Configuración de Azure OpenAI", + "token": { + "desc": "Este valor se puede encontrar en la sección Claves y puntos finales al comprobar un recurso en un sitio Azure. Puede utilizar KEY1 o KEY2", + "placeholder": "Azure Clave API", + "title": "CLave API" + } + }, + "OpenAI": { + "azureApiVersion": { + "desc": "Versión de la API de Azure en formato AAAA-MM-DD, comprobar [última versión](https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions)", + "fetch": "Obtener lista", + "title": "Azure API versión" + }, + "check": { + "button": "Comprobar", + "desc": "Compruebe que la clave Api y la dirección del servidor proxy se han rellenado correctamente.", + "pass": "Conexión correcta", + "title": "Comprobación de la conectividad" + }, + "endpoint": { + "desc": "Debe contener http(s):// además de la dirección por defecto.", + "placeholder": "https://api.openai.com/v1", + "title": "Dirección proxy API" + }, + "models": { + "count": "Total de modelos admitidos: {{count}}", + "desc": "Modelos compatibles", + "fetch": "Obtener la lista de modelos", + "notSupport": "Azure OpenAI no admite actualmente la visualización de listas de modelos", + "notSupportTip": "Asegúrese de que el nombre del despliegue coincide con el nombre del modelo", + "refetch": "Obtener la lista de modelos", + "title": "Lista de modelos" + }, + "title": "COnfiguración OpenAI", + "token": { + "desc": "Utiliza tu propia clave OpenAI", + "placeholder": "Clave API de OpenAI", + "title": "Clave API" + }, + "useAzure": { + "desc": "Uso de los servicios OpenAI de Azure", + "fetch": "Obtener lista", + "title": "Azure OpenAI", + "serverConfig": "El administrador ha habilitado Azure OpenAI en el lado del servidor, el cambio está prohibido" + }, + "customModelName": { + "desc": "Añada modelos personalizados, separe varios modelos con comas (,)", + "placeholder": "modelo1,modelo2,modelo3", + "title": "Modelo personalizado" + } + }, + "waitingForMore": "<1>Está previsto el acceso a otros modelos,así que permanezca atent@ ✨" + }, + "settingAgent": { + "avatar": { + "title": "Avatar" + }, + "backgroundColor": { + "title": "Color de fondo" + }, + "description": { + "placeholder": "Introduzca la descripción del agente", + "title": "Descripción del Agente" + }, + "name": { + "placeholder": "Introduzca el nombre del agente", + "title": "Nombre" + }, + "prompt": { + "placeholder": "Por favor, introduzca el rol", + "title": "Función" + }, + "tag": { + "placeholder": "Por favor, introduzca la etiqueta", + "title": "Etiqueta" + }, + "title": "Información para agentes" + }, + "settingChat": { + "chatStyleType": { + "title": "Estilo de ventana de chat", + "type": { + "chat": "Modo de chat", + "docs": "Modo de documento" + } + }, + "compressThreshold": { + "desc": "Cuando los mensajes del historial sin comprimir superen este valor, se realizará la compresión", + "title": "Umbral de compresión de la longitud de los mensajes históricos" + }, + "enableCompressThreshold": { + "title": "Umbral de compresión de la longitud de los mensajes históricos" + }, + "enableHistoryCount": { + "alias": "Ilimitado", + "limited": "Sólo incluye {{number}} mensajes de sesión", + "title": "Limitar el recuento de mensajes del historial", + "unlimited": "Número ilimitado de mensajes históricos" + }, + "historyCount": { + "desc": "Número de mensajes de historial transportados en cada solicitud", + "title": "Historial adjunto Recuento de mensajes" + }, + "inputTemplate": { + "desc": "El último mensaje del usuario se rellenará en esta plantilla", + "placeholder": "{{text}} se sustituirá por información de entrada en tiempo real", + "title": "Preprocesamiento de las entradas del usuario" + }, + "title": "Configuración del chat", + "autoCreateTopicThreshold": { + "title": "Umbral de mensajes", + "desc": "Crear automáticamente un tema cuando el número actual de mensajes supere este valor" + }, + "enableAutoCreateTopic": { + "title": "Activar la creación automática de temas", + "desc": "Si crear automáticamente un tema durante la conversación, sólo efectivo en temas temporales." + } + }, + "settingModel": { + "enableMaxTokens": { + "title": "Activar el límite de respuesta única" + }, + "frequencyPenalty": { + "desc": "Cuanto mayor sea el valor, más probabilidades habrá de reducir las palabras repetidas", + "title": "Frecuencia Penalización" + }, + "maxTokens": { + "desc": "Número máximo de fichas utilizadas en una sola interacción", + "title": "Límite de respuesta única" + }, + "model": { + "desc": "Modelo de ChatGPT", + "list": { + "gpt-3.5-turbo": "GPT 3.5", + "gpt-3.5-turbo-16k": "GPT 3.5 (16K)", + "gpt-4": "GPT 4", + "gpt-4-32k": "GPT 4 (32K)" + }, + "title": "Modelo" + }, + "presencePenalty": { + "desc": "Cuanto mayor sea el valor, más probable es que se amplíe a nuevos temas", + "title": "Frescura del tema" + }, + "temperature": { + "desc": "Cuanto mayor sea el valor, más aleatoria será la respuesta", + "title": "Aleatoriedad", + "titleWithValue": "Aleatoriedad {{value}}" + }, + "title": "Ajustes del modelo", + "topP": { + "desc": "Similar a la aleatoriedad, pero no cambia junto con la aleatoriedad", + "title": "Muestreo de núcleos" + } + }, + "settingOpenAI": { + "endpoint": { + "desc": "Debe incluir http(s)://, además de la dirección por defecto", + "placeholder": "https://api.openai.com/v1", + "title": "Dirección del proxy API" + }, + "title": "Configuración de OpenAI", + "token": { + "desc": "Utiliza tu propia clave OpenAI", + "placeholder": "Clave API de OpenAI", + "title": "Clave API" + } + }, + "settingPlugin": { + "title": "Lista de plugins", + "add": "Añadir", + "addTooltip": "Añadir plugin personalizado", + "config": "{{id}} Configuración del plugin", + "clearDeprecated": "Eliminar plugins obsoletos", + "settings": "Configuración del mercado de plugins" + }, + "settingSystem": { + "accessCode": { + "desc": "El acceso cifrado ha sido habilitado por el administrador", + "placeholder": "Introduzca la contraseña de acceso", + "title": "Contraseña de acceso" + }, + "title": "Configuración del sistema" + }, + "settingTTS": { + "showAllLocaleVoice": { + "desc": "Si se desactiva, sólo se mostrarán las voces del idioma actual.", + "title": "Mostrar todas las locuciones" + }, + "sttService": { + "desc": "La opción 'navegador' se refiere al servicio nativo de reconocimiento de voz del navegador", + "title": "Servicio de voz a texto" + }, + "title": "Servicios de voz", + "ttsService": { + "desc": "Si utiliza el servicio de conversión de texto a voz OpenAI, asegúrese de que el servicio de modelo OpenAI está activado.", + "title": "Servicio de texto a voz" + }, + "voice": { + "title": "Voces de texto a voz", + "desc": "Seleccione una voz para el asistente actual, los diferentes servicios TTS admiten diferentes voces", + "preview": "Vista previa Voz" + }, + "openai": { + "sttModel": "Modelo de reconocimiento de voz OpenAI", + "ttsModel": "Modelo de conversión de texto a voz de OpenAI" + }, + "stt": "Configuración del reconocimiento de voz", + "sttLocale": { + "desc": "El idioma de la entrada de voz, esta opción puede mejorar la precisión del reconocimiento de voz", + "title": "Lenguaje de reconocimiento de voz" + }, + "sttPersisted": { + "desc": "Si está activado, el reconocimiento de voz no finalizará automáticamente y será necesario pulsar manualmente el botón de finalización.", + "title": "Finalizar manualmente el reconocimiento de voz" + }, + "tts": "Ajustes de texto a voz", + "sttAutoStop": { + "desc": "Si se desactiva, el reconocimiento de voz no se detendrá automáticamente y será necesaria la intervención manual para finalizar el proceso.", + "title": "Finalización del reconocimiento automático de voz" + } + }, + "settingTheme": { + "avatar": { + "title": "Avatar" + }, + "fontSize": { + "desc": "Tamaño de letra del contenido del chat", + "title": "Tamaño de letra" + }, + "lang": { + "title": "Ajustes de idioma", + "autoMode": "Sistema de seguimiento" + }, + "neutralColor": { + "desc": "Escala de grises personalizada para diferentes tendencias de color", + "title": "Color neutro" + }, + "primaryColor": { + "desc": "Color del tema personalizado", + "title": "Tema Color" + }, + "themeMode": { + "auto": "Automático", + "dark": "Oscuro", + "light": "Claro", + "title": "Tema" + }, + "title": "Configuración del tema" + }, + "submitAgentModal": { + "tooltips": "Cuota al mercado auxiliar", + "button": "Presentar asistente", + "identifier": "Identificador", + "metaMiss": "Por favor, complete la información del asistente antes de enviarla. Debe incluir nombre, descripción y etiquetas.", + "placeholder": "Introduzca un identificador único para el asistente, como desarrollo web." + }, + "tab": { + "agent": "Agente por defecto", + "common": "Ajustes comunes", + "llm": "API LLM personalizada", + "tts": "Servicios de voz" + } +} diff --git a/locales/es_ES/welcome.json b/locales/es_ES/welcome.json new file mode 100644 index 0000000000000..63d3aae1ce041 --- /dev/null +++ b/locales/es_ES/welcome.json @@ -0,0 +1,14 @@ +{ + "button": { + "import": "Importar Configuración", + "start": "Empezar Ahora" + }, + "header": "Bienvenid@", + "pickAgent": "O elija entre las siguientes plantillas de agentes", + "skip": "Saltar Creación", + "slogan": { + "desc1": "Pioneros en la nueva era del pensamiento y la creación. Creada para ti, el superagente.", + "desc2": "Crea tu primer agente y empecemos~", + "title": "Desbloquea el superpoder de tu cerebro" + } +} diff --git a/locales/ja_JP/chat.json b/locales/ja_JP/chat.json new file mode 100644 index 0000000000000..9db940879dc81 --- /dev/null +++ b/locales/ja_JP/chat.json @@ -0,0 +1,80 @@ +{ + "agentDefaultMessage": "こんにちは、私は **{{name}}** です。すぐに会話を始めることができますし、[エージェント設定](/chat/settings#session={{id}}) に移動して私の情報を充実させることもできます。", + "agentDefaultMessageWithSystemRole": "こんにちは、私は **{{name}}** です、{{systemRole}}、さあ、会話を始めましょう!", + "backToBottom": "最新のメッセージを表示", + "clearCurrentMessages": "現在の会話メッセージをクリア", + "confirmClearCurrentMessages": "現在の会話メッセージをクリアします。クリア後は元に戻すことはできませんので、操作を確認してください", + "confirmRemoveSessionItemAlert": "このエージェントを削除します。削除後は元に戻すことはできませんので、操作を確認してください", + "defaultAgent": "デフォルトエージェント", + "defaultSession": "デフォルトエージェント", + "historyRange": "履歴範囲", + "inbox": { + "defaultMessage": "こんにちは、私はあなたのインテリジェントアシスタントです。何でも質問してください、できる限りお答えします。より専門的またはカスタマイズされたアシスタントが必要な場合は、`+` をクリックしてカスタムエージェントを作成できます", + "desc": "ブレインクラスタを起動し、思考の火花を引き起こします。あなたのインテリジェントアシスタントは、ここであなたとすべてを話します", + "title": "ちょっとおしゃべりしましょう" + }, + "newAgent": "新しいエージェントを作成", + "noDescription": "説明はありません", + "pin": "ピン留め", + "pinOff": "ピン留め解除", + "regenerate": "再生成", + "roleAndArchive": "役割とアーカイブ", + "searchAgentPlaceholder": "エージェントと会話を検索...", + "send": "送信", + "sendPlaceholder": "チャット内容を入力...", + "sessionList": "セッションリスト", + "shareModal": { + "download": "スクリーンショットをダウンロード", + "imageType": "画像形式", + "screenshot": "スクリーンショット", + "settings": "エクスポート設定", + "shareToShareGPT": "ShareGPT共有リンクを生成", + "withBackground": "背景画像を含む", + "withFooter": "フッターを含む", + "withPluginInfo": "プラグイン情報を含む", + "withSystemRole": "エージェントの役割設定を含む" + }, + "stop": "停止", + "stt": { + "action": "音声入力", + "loading": "読み取り中...", + "prettifying": "美化中..." + }, + "temp": "一時", + "tokenDetail": "役割設定: {{systemRoleToken}} · チャット履歴: {{chatsToken}}", + "tokenTag": { + "overload": "制限を超えています", + "remained": "残り", + "used": "使用済み" + }, + "topic": { + "confirmRemoveTopic": "このトピックを削除します。削除後は元に戻すことはできませんので、注意して操作してください", + "defaultTitle": "デフォルトトピック", + "saveCurrentMessages": "現在の会話をトピックとして保存", + "searchPlaceholder": "トピックを検索...", + "deleteAll": "すべてのトピックを削除する", + "deleteUnstarred": "スターを付けていないトピックを削除する", + "title": "トピックリスト", + "confirmRemoveAll": "すべてのトピックを削除します。削除後は元に戻すことはできませんので、注意して操作してください。", + "confirmRemoveUnstarred": "スターをつけていないトピックを削除します。削除後は元に戻すことはできませんので、注意して操作してください。", + "removeAll": "すべてのトピックを削除", + "removeUnstarred": "スターをつけていないトピックを削除", + "openNewTopic": "新しいトピックを開く" + }, + "translate": { + "clear": "翻訳をクリア", + "action": "翻訳" + }, + "translateTo": "翻訳", + "tts": { + "action": "音声読み上げ", + "clear": "音声削除" + }, + "updateAgent": "エージェント情報を更新", + "upload": { + "actionTooltip": "画像をアップロード", + "dragDesc": "ファイルをここにドラッグして複数の画像をアップロードできます。Shift キーを押しながら画像を直接送信できます", + "dragTitle": "画像をアップロード" + }, + "warp": "改行" +} diff --git a/locales/ja_JP/common.json b/locales/ja_JP/common.json new file mode 100644 index 0000000000000..bae1fa6f7fe34 --- /dev/null +++ b/locales/ja_JP/common.json @@ -0,0 +1,71 @@ +{ + "about": "について", + "advanceSettings": "詳細設定", + "agentMaxToken": "セッションの最大トークン数", + "agentModel": "モデル", + "agentProfile": "エージェント情報", + "appInitializing": "ChatGPT Powerを起動中です。お待ちください...", + "archive": "アーカイブ", + "autoGenerate": "自動生成", + "autoGenerateTooltip": "ヒントワードに基づいてエージェントの説明を自動生成します", + "cancel": "キャンセル", + "changelog": "更新履歴", + "close": "閉じる", + "confirmRemoveSessionItemAlert": "このエージェントを削除します。削除後は元に戻すことはできません。操作を確認してください", + "copy": "コピー", + "copySuccess": "コピーが成功しました", + "defaultAgent": "デフォルトエージェント", + "defaultSession": "デフォルトセッション", + "delete": "削除", + "edit": "編集", + "export": "設定のエクスポート", + "exportType": { + "agent": "エージェント設定のエクスポート", + "agentWithMessage": "エージェントとメッセージのエクスポート", + "all": "グローバル設定とすべてのエージェントデータのエクスポート", + "allAgent": "すべてのエージェント設定のエクスポート", + "allAgentWithMessage": "すべてのエージェントとメッセージのエクスポート", + "globalSetting": "グローバル設定のエクスポート" + }, + "feedback": "フィードバック", + "historyRange": "履歴範囲", + "import": "設定のインポート", + "lang": { + "en": "英語", + "en-US": "英語", + "es-ES": "スペイン語", + "ja-JP": "日本語", + "ko-KR": "韓国語", + "ru-RU": "ロシア語", + "zh": "簡体中国語", + "zh-CN": "簡体中国語", + "zh-TW": "繁体中国語" + }, + "layoutInitializing": "レイアウトを読み込んでいます...", + "noDescription": "説明はありません", + "ok": "OK", + "password": "パスワード", + "pin": "ピン留め", + "pinOff": "ピン留め解除", + "regenerate": "再生成", + "rename": "名前の変更", + "reset": "リセット", + "retry": "再試行", + "send": "送信", + "sessionList": "エージェントリスト", + "setting": "設定", + "share": "共有", + "stop": "停止", + "tab": { + "chat": "チャット", + "market": "発見", + "setting": "設定" + }, + "temp": "一時的な", + "updateAgent": "エージェント情報の更新", + "upgradeVersion": { + "action": "今すぐアップグレード", + "hasNew": "利用可能な更新があります", + "newVersion": "新しいバージョンが利用可能です:{{version}}" + } +} diff --git a/locales/ja_JP/empty.json b/locales/ja_JP/empty.json new file mode 100644 index 0000000000000..af2710565348c --- /dev/null +++ b/locales/ja_JP/empty.json @@ -0,0 +1,6 @@ +{ + "topic": { + "desc": "左側のボタンをクリックして、現在の会話を履歴トピックとして保存し、新しい会話を開始します", + "title": "トピックリスト" + } +} diff --git a/locales/ja_JP/error.json b/locales/ja_JP/error.json new file mode 100644 index 0000000000000..b667be088453c --- /dev/null +++ b/locales/ja_JP/error.json @@ -0,0 +1,51 @@ +{ + "pluginSettings": { + "desc": "以下の設定を完了すると、プラグインを使用することができます", + "title": "{{name}} プラグイン設定" + }, + "response": { + "400": "申し訳ありませんが、サーバーはリクエストを理解できません。リクエストパラメータが正しいかどうか確認してください", + "401": "申し訳ありませんが、サーバーはリクエストを拒否しました。権限が不足しているか、有効な認証情報が提供されていない可能性があります", + "403": "申し訳ありませんが、サーバーはリクエストを拒否しました。このコンテンツにアクセスする権限がありません", + "404": "申し訳ありませんが、サーバーはリクエストしたページやリソースを見つけることができません。URLが正しいかどうか確認してください", + "405": "申し訳ありませんが、サーバーは使用されたリクエストメソッドをサポートしていません。リクエストメソッドが正しいかどうか確認してください", + "429": "申し訳ありませんが、リクエストが多すぎてサーバーが忙しいため、しばらくしてから再試行してください", + "500": "申し訳ありませんが、サーバーに一時的な問題が発生し、リクエストを完了できません。しばらくしてから再試行してください", + "502": "申し訳ありませんが、サーバーは一時的にサービスを提供できません。しばらくしてから再試行してください", + "503": "申し訳ありませんが、サーバーは現在、リクエストを処理できません。オーバーロードまたはメンテナンス中の可能性があります。しばらくしてから再試行してください", + "504": "申し訳ありませんが、サーバーは上位サーバーからの応答を待っていません。しばらくしてから再試行してください", + "PluginMarketIndexNotFound": "申し訳ありませんが、プラグインのインデックスが見つかりませんでした。インデックスのアドレスが正しいかどうか確認してください", + "PluginMetaNotFound": "申し訳ありませんが、インデックスでプラグインが見つかりませんでした。プラグインの設定情報をインデックスで確認してください", + "PluginMetaInvalid": "申し訳ありませんが、プラグインのメタ情報の検証に失敗しました。プラグインのメタ情報の形式が正しいかどうか確認してください", + "PluginApiParamsError": "申し訳ありませんが、プラグインのリクエストパラメータの検証に失敗しました。パラメータとAPIの説明が一致しているかどうか確認してください", + "PluginSettingsInvalid": "このプラグインを使用するには、正しい設定が必要です。設定が正しいかどうか確認してください", + "PluginServerError": "プラグインサーバーのリクエストエラーが発生しました。以下のエラーメッセージを参考に、プラグインのマニフェストファイル、設定、サーバー実装を確認してください", + "InvalidAccessCode": "パスワードが正しくないか空です。正しいアクセスパスワードを入力するか、カスタムのOpenAI APIキーを追加してください", + "OpenAIBizError": "OpenAIサービスのリクエストエラーが発生しました。以下の情報に基づいて問題を解決したり、再試行したりしてください", + "PluginMarketIndexInvalid": "申し訳ありませんが、プラグインのインデックスの検証に失敗しました。インデックスファイルの形式が正しいかどうかを確認してください", + "PluginManifestNotFound": "申し訳ありませんが、サーバーでプラグインのマニフェストファイル (manifest.json) が見つかりませんでした。プラグインのマニフェストファイルのアドレスが正しいかどうかを確認してください", + "PluginManifestInvalid": "申し訳ありませんが、このプラグインのマニフェストの検証に失敗しました。マニフェストの形式が正しいかどうかを確認してください", + "PluginApiNotFound": "申し訳ありませんが、プラグインのマニフェストに指定されたAPIが見つかりませんでした。リクエストメソッドとプラグインのマニフェストのAPIが一致しているかどうかを確認してください", + "NoAPIKey": "OpenAI APIキーが空です。カスタムOpenAI APIキーを追加してください。" + }, + "stt": { + "responseError": "サービスリクエストが失敗しました。設定を確認するか、もう一度お試しください" + }, + "tts": { + "responseError": "サービスリクエストが失敗しました。設定を確認するか、もう一度お試しください" + }, + "unlock": { + "apikey": { + "title": "カスタムAPIキーの使用", + "description": "OpenAI APIキーを入力すると、会話を開始できます。アプリはあなたのAPIキーを記録しません。", + "addProxyUrl": "OpenAIプロキシURLを追加(オプション)" + }, + "closeMessage": "ヒントを閉じる", + "confirm": "確認して再試行", + "password": { + "description": "管理者によってアプリが暗号化されました。アプリをロック解除するには、アプリのパスワードを入力してください。パスワードは1回だけ入力すればよいです", + "title": "パスワードを入力してアプリをロック解除", + "placeholder": "パスワードを入力してください" + } + } +} diff --git a/locales/ja_JP/market.json b/locales/ja_JP/market.json new file mode 100644 index 0000000000000..4740332c74f6a --- /dev/null +++ b/locales/ja_JP/market.json @@ -0,0 +1,30 @@ +{ + "addAgent": "助手を追加する", + "guide": { + "func1": { + "desc1": "セッションウィンドウで右上隅の設定にアクセスして、アシスタントの設定ページに移動します。", + "desc2": "右上隅の「アシスタントマーケットに送信」ボタンをクリックします。", + "tag": "方法1", + "title": "ChatGPT Powerを使用して送信する" + }, + "func2": { + "button": "GitHubのアシスタントリポジトリに移動する", + "desc": "アシスタントをインデックスに追加したい場合は、agent-template.jsonまたはagent-template-full.jsonを使用して、pluginsディレクトリにエントリを作成し、簡単な説明と適切なタグを付けてプルリクエストを作成します。", + "tag": "方法2", + "title": "GitHubを使用して送信する" + } + }, + "search": { + "placeholder": "助手の名前、説明、またはキーワードを検索..." + }, + "sidebar": { + "comment": "コメント", + "prompt": "プロンプト", + "title": "助手の詳細" + }, + "submitAgent": "助手を提出する", + "title": { + "allAgents": "すべての助手", + "recentSubmits": "最近の追加" + } +} diff --git a/locales/ja_JP/plugin.json b/locales/ja_JP/plugin.json new file mode 100644 index 0000000000000..019eee4f62b1b --- /dev/null +++ b/locales/ja_JP/plugin.json @@ -0,0 +1,109 @@ +{ + "debug": { + "arguments": "引数", + "function_call": "関数呼び出し", + "response": "レスポンス", + "off": "デバッグをオフにする", + "on": "プラグイン呼び出し情報を表示する" + }, + "dev": { + "confirmDeleteDevPlugin": "このローカルプラグインを削除しますか?削除後は元に戻せません。", + "deleteSuccess": "プラグインが正常に削除されました", + "manifest": { + "identifier": { + "desc": "プラグインの一意の識別子", + "label": "識別子" + }, + "mode": { + "local": "ビジュアル設定", + "local-tooltip": "ビジュアル設定は一時的にサポートされていません", + "url": "オンラインリンク" + }, + "name": { + "desc": "プラグインのタイトル", + "label": "タイトル", + "placeholder": "検索エンジン" + } + }, + "meta": { + "author": { + "desc": "プラグインの作者", + "label": "作者" + }, + "avatar": { + "desc": "プラグインのアイコン、絵文字やURLを使用できます", + "label": "アイコン" + }, + "description": { + "desc": "プラグインの説明", + "label": "説明", + "placeholder": "検索エンジンで情報を取得します" + }, + "formFieldRequired": "このフィールドは必須です", + "homepage": { + "desc": "プラグインのホームページ", + "label": "ホームページ" + }, + "identifier": { + "desc": "プラグインの一意の識別子、マニフェストから自動的に識別されます", + "errorDuplicate": "識別子が既存のプラグインと重複しています。識別子を変更してください", + "label": "識別子", + "pattenErrorMessage": "英数字、-、_ のみ入力できます" + }, + "manifest": { + "desc": "ChatGPT Powerはこのリンクを使用してプラグインをインストールします", + "jsonInvalid": "マニフェストが規格に準拠していません。検証結果:\n\n{{error}}", + "label": "プラグインのマニフェストURL", + "preview": "マニフェストのプレビュー", + "refresh": "更新", + "requestError": "リンクのリクエストに失敗しました。有効なリンクを入力し、クロスオリジンリクエストが許可されているか確認してください", + "urlError": "このリンクはJSON形式のコンテンツを返していません。有効なリンクを入力してください" + }, + "title": { + "desc": "プラグインのタイトル", + "label": "タイトル", + "placeholder": "検索エンジン" + } + }, + "metaConfig": "プラグインのメタ情報の設定", + "modalDesc": "カスタムプラグインを追加すると、プラグインの開発検証やセッションで直接使用できます。プラグインの開発ドキュメントについては、参照してください", + "preview": { + "card": "プラグインのプレビュー表示", + "desc": "プラグインの説明のプレビュー", + "title": "プラグイン名のプレビュー" + }, + "save": "保存", + "saveSuccess": "プラグインの設定が正常に保存されました", + "tabs": { + "manifest": "機能のマニフェスト", + "meta": "プラグインのメタ情報" + }, + "title": "カスタムプラグインの追加", + "update": "更新", + "updateSuccess": "プラグインの設定が正常に更新されました" + }, + "list": { + "item": { + "deprecated.title": "削除済み", + "local.config": "設定", + "local.title": "カスタム" + } + }, + "loading": { + "plugin": "プラグインの実行中...", + "content": "プラグインを呼び出しています..." + }, + "pluginList": "プラグインリスト", + "plugins": { + "unknown": "プラグインの検出中..." + }, + "setting": "プラグインの設定", + "settings": { + "indexUrl": { + "title": "マーケットインデックス", + "tooltip": "オンライン編集は現在サポートされていません。デプロイ時の環境変数を使用して設定してください" + }, + "modalDesc": "プラグインマーケットのアドレスを設定すると、カスタムのプラグインマーケットを使用できます", + "title": "プラグインマーケットの設定" + } +} diff --git a/locales/ja_JP/setting.json b/locales/ja_JP/setting.json new file mode 100644 index 0000000000000..0cfd116c3e053 --- /dev/null +++ b/locales/ja_JP/setting.json @@ -0,0 +1,284 @@ +{ + "danger": { + "clear": { + "action": "クリア", + "confirm": "すべてのチャットデータをクリアしますか?", + "desc": "すべてのセッションデータをクリアします", + "success": "すべてのセッションメッセージがクリアされました", + "title": "すべてのセッションメッセージをクリア" + }, + "reset": { + "action": "リセット", + "confirm": "すべての設定をリセットしますか?", + "currentVersion": "現在のバージョン", + "desc": "すべての設定項目をデフォルト値にリセットします", + "title": "すべての設定をリセット" + } + }, + "header": { + "global": "グローバル設定", + "session": "セッション設定", + "sessionWithName": "セッション設定 · {{name}}" + }, + "llm": { + "AzureOpenAI": { + "endpoint": { + "desc": "Azureポータルでリソースを確認すると、この値は「キーとエンドポイント」セクションで見つけることができます", + "placeholder": "https://docs-test-001.openai.azure.com", + "title": "Azure APIアドレス" + }, + "models": { + "desc": "サポートされているモデル", + "title": "モデルリスト" + }, + "title": "Azure OpenAI設定", + "token": { + "desc": "Azureポータルでリソースを確認すると、この値は「キーとエンドポイント」セクションで見つけることができます。KEY1またはKEY2を使用できます", + "placeholder": "Azure APIキー", + "title": "APIキー" + } + }, + "OpenAI": { + "azureApiVersion": { + "desc": "AzureのAPIバージョンは、YYYY-MM-DD形式に従います。[最新バージョン](https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions)を参照してください", + "fetch": "リストを取得", + "title": "Azure APIバージョン" + }, + "check": { + "button": "チェック", + "desc": "APIキーとプロキシアドレスが正しく入力されているかをテストします", + "pass": "チェックに合格しました", + "title": "接続性のチェック" + }, + "endpoint": { + "desc": "デフォルトのアドレス以外に、http(s)://を含める必要があります", + "placeholder": "https://api.openai.com/v1", + "title": "エンドポイントプロキシアドレス" + }, + "models": { + "count": "{{count}}モデルがサポートされています", + "desc": "サポートされているモデル", + "fetch": "モデルリストを取得", + "notSupport": "Azure OpenAIではモデルリストの表示はサポートされていません", + "notSupportTip": "デプロイ名とモデル名が一致していることを確認する必要があります", + "refetch": "モデルリストを再取得", + "title": "モデルリスト" + }, + "title": "OpenAI設定", + "token": { + "desc": "独自のOpenAIキーを使用します", + "placeholder": "OpenAI APIキー", + "title": "APIキー" + }, + "useAzure": { + "desc": "Azureが提供するOpenAIサービスを使用します", + "fetch": "リストを取得", + "serverConfig": "管理者がサーバー側でAzure OpenAIを設定しており、切り替えが禁止されています", + "title": "Azure OpenAI" + }, + "customModelName": { + "desc": "カスタムモデルを追加します。複数のモデルはカンマ(,)で区切ってください", + "placeholder": "model1,model2,model3", + "title": "カスタムモデル名" + } + }, + "waitingForMore": "他のモデルは現在 <1>計画中 です。お楽しみに ✨" + }, + "settingAgent": { + "avatar": { + "title": "アバター" + }, + "backgroundColor": { + "title": "背景色" + }, + "description": { + "placeholder": "アシスタントの説明を入力してください", + "title": "説明" + }, + "name": { + "placeholder": "アシスタントの名前を入力してください", + "title": "名前" + }, + "prompt": { + "placeholder": "キャラクタープロンプトを入力してください", + "title": "キャラクター設定" + }, + "tag": { + "placeholder": "タグを入力してください", + "title": "タグ" + }, + "title": "アシスタント情報" + }, + "settingChat": { + "chatStyleType": { + "title": "チャットウィンドウのスタイル", + "type": { + "chat": "対話モード", + "docs": "ドキュメントモード" + } + }, + "compressThreshold": { + "desc": "非圧縮の履歴メッセージがこの値を超えると、圧縮されます", + "title": "履歴メッセージの圧縮閾値" + }, + "enableCompressThreshold": { + "title": "履歴メッセージの圧縮閾値を有効にする" + }, + "enableHistoryCount": { + "alias": "制限なし", + "limited": "{{number}}件の会話メッセージのみ含む", + "title": "履歴メッセージ数の制限", + "unlimited": "履歴メッセージ数の制限なし" + }, + "historyCount": { + "desc": "リクエストごとに含まれる履歴メッセージ数", + "title": "履歴メッセージ数" + }, + "inputTemplate": { + "desc": "ユーザーの最新のメッセージがこのテンプレートに埋め込まれます", + "placeholder": "プリプロセステンプレート {{text}} はリアルタイムの入力情報に置き換えられます", + "title": "ユーザー入力のプリプロセス" + }, + "title": "チャット設定", + "autoCreateTopicThreshold": { + "desc": "現在のメッセージ数がこの値を超えると、トピックが自動的に作成されます", + "title": "メッセージ閾値" + }, + "enableAutoCreateTopic": { + "desc": "会話中にトピックを自動的に作成するかどうか、一時的なトピックでのみ有効です", + "title": "トピックの自動作成" + } + }, + "settingModel": { + "enableMaxTokens": { + "title": "単一応答制限を有効にする" + }, + "frequencyPenalty": { + "desc": "値が大きいほど、重複する単語が減少する可能性が高くなります", + "title": "頻度ペナルティ" + }, + "maxTokens": { + "desc": "単一の対話で使用される最大トークン数", + "title": "単一応答制限" + }, + "model": { + "desc": "ChatGPTモデル", + "list": { + "gpt-3.5-turbo": "GPT 3.5", + "gpt-3.5-turbo-16k": "GPT 3.5 (16K)", + "gpt-4": "GPT 4", + "gpt-4-32k": "GPT 4 (32K)" + }, + "title": "モデル" + }, + "presencePenalty": { + "desc": "値が大きいほど、新しいトピックに展開する可能性が高くなります", + "title": "トピックの新鮮さ" + }, + "temperature": { + "desc": "値が大きいほど、応答がよりランダムになります", + "title": "ランダム性", + "titleWithValue": "ランダム性 {{value}}" + }, + "title": "モデル設定", + "topP": { + "desc": "ランダム性と同様ですが、ランダム性とは同時に変更しないでください", + "title": "トップPサンプリング" + } + }, + "settingPlugin": { + "add": "追加", + "addTooltip": "カスタムプラグインを追加", + "clearDeprecated": "無効なプラグインを削除", + "config": "{{id}}プラグインの設定", + "settings": "プラグインマーケットの設定", + "title": "プラグインリスト" + }, + "settingSystem": { + "accessCode": { + "desc": "管理者が暗号化アクセスを有効にしています", + "placeholder": "アクセスコードを入力してください", + "title": "アクセスコード" + }, + "title": "システム設定" + }, + "settingTTS": { + "showAllLocaleVoice": { + "desc": "关闭すると、現在の言語の音声のみが表示されます", + "title": "すべての言語の音声を表示" + }, + "sttService": { + "desc": "ブラウザはブラウザのネイティブ音声認識サービスです", + "title": "音声認識サービス" + }, + "title": "音声サービス", + "ttsService": { + "desc": "OpenAIの音声合成サービスを使用する場合、OpenAIモデルサービスが有効になっていることを確認する必要があります", + "title": "音声合成サービス" + }, + "voice": { + "title": "音声合成音声源", + "desc": "現在のアシスタントに適した音声を選択します。異なるTTSサービスは異なる音声をサポートしています", + "preview": "プレビュー" + }, + "openai": { + "sttModel": "OpenAI 音声認識モデル", + "ttsModel": "OpenAI 音声合成モデル" + }, + "stt": "音声認識設定", + "sttLocale": { + "desc": "音声入力の言語、このオプションを選択すると音声認識の精度が向上します", + "title": "音声認識言語" + }, + "sttPersisted": { + "desc": "有効にすると、音声認識が自動的に終了せず、手動で終了ボタンをクリックする必要があります", + "title": "音声認識の手動終了" + }, + "tts": "音声合成設定", + "sttAutoStop": { + "desc": "オフにすると、音声認識が自動的に終了せず、手動で終了ボタンをクリックする必要があります", + "title": "音声認識の自動終了" + } + }, + "settingTheme": { + "avatar": { + "title": "アバター" + }, + "fontSize": { + "desc": "チャットのテキストサイズ", + "title": "フォントサイズ" + }, + "lang": { + "autoMode": "システムに従う", + "title": "言語" + }, + "neutralColor": { + "desc": "異なる色調のグレースケールのカスタマイズ", + "title": "中立色" + }, + "primaryColor": { + "desc": "カスタムテーマカラー", + "title": "テーマカラー" + }, + "themeMode": { + "auto": "自動", + "dark": "ダーク", + "light": "ライト", + "title": "テーマ" + }, + "title": "テーマ設定" + }, + "submitAgentModal": { + "tooltips": "アシスタントマーケットに共有する", + "button": "助手を提出する", + "identifier": "識別子 エージェントの識別子", + "metaMiss": "エージェント情報を入力してから提出してください。名前、説明、およびタグが必要です", + "placeholder": "エージェントの識別子を入力してください。一意である必要があります。例:web-development" + }, + "tab": { + "agent": "デフォルトのアシスタント", + "common": "一般設定", + "llm": "言語モデル", + "tts": "音声サービス" + } +} diff --git a/locales/ja_JP/welcome.json b/locales/ja_JP/welcome.json new file mode 100644 index 0000000000000..28aa8fdddbe7c --- /dev/null +++ b/locales/ja_JP/welcome.json @@ -0,0 +1,14 @@ +{ + "button": { + "import": "設定をインポート", + "start": "すぐに開始" + }, + "header": "ようこそ", + "pickAgent": "または以下のアシスタントテンプレートから選択してください", + "skip": "作成をスキップ", + "slogan": { + "desc1": "脳のクラスターを開始し、思考の火花を引き起こします。あなたのスマートアシスタントは常にそこにあります。", + "desc2": "最初のアシスタントを作成して、始めましょう〜", + "title": "より賢い脳を自分に与える" + } +} diff --git a/locales/ko_KR/chat.json b/locales/ko_KR/chat.json new file mode 100644 index 0000000000000..9c960285c609d --- /dev/null +++ b/locales/ko_KR/chat.json @@ -0,0 +1,80 @@ +{ + "agentDefaultMessage": "안녕하세요, 저는 **{{name}}**입니다. 바로 대화를 시작하거나 [도우미 설정](/chat/settings#session={{id}})으로 이동하여 제 정보를 완성할 수 있습니다.", + "agentDefaultMessageWithSystemRole": "안녕하세요, 저는 **{{name}}**입니다. {{systemRole}}입니다. 대화를 시작해보세요!", + "backToBottom": "최신 메시지 보기", + "clearCurrentMessages": "현재 대화 지우기", + "confirmClearCurrentMessages": "현재 대화를 지우시겠습니까? 지우면 복구할 수 없습니다. 작업을 확인하세요.", + "confirmRemoveSessionItemAlert": "도우미를 삭제하시겠습니까? 삭제하면 복구할 수 없습니다. 작업을 확인하세요.", + "defaultAgent": "사용자 정의 도우미", + "defaultSession": "사용자 정의 도우미", + "historyRange": "기록 범위", + "inbox": { + "defaultMessage": "안녕하세요, 저는 여러분의 인공지능 도우미입니다. 궁금한 점이 있으면 물어보세요. 더 전문적이거나 맞춤화된 도우미가 필요하다면 `+`를 클릭하여 사용자 정의 도우미를 생성할 수 있습니다.", + "desc": "뇌 클러스터를 활성화하여 창의적인 생각을 이끌어내는 인공지능 도우미입니다. 모든 것에 대해 여기에서 대화하세요.", + "title": "잡담하기" + }, + "newAgent": "새 도우미 만들기", + "noDescription": "설명 없음", + "pin": "고정", + "pinOff": "고정 해제", + "regenerate": "재생성", + "roleAndArchive": "역할 및 아카이브", + "searchAgentPlaceholder": "도우미 및 대화 검색...", + "send": "보내기", + "sendPlaceholder": "대화 내용 입력...", + "sessionList": "도우미 목록", + "shareModal": { + "download": "스크린샷 다운로드", + "imageType": "이미지 형식", + "screenshot": "스크린샷", + "settings": "내보내기 설정", + "shareToShareGPT": "ShareGPT 공유 링크 생성", + "withBackground": "배경 이미지 포함", + "withFooter": "푸터 포함", + "withPluginInfo": "플러그인 정보 포함", + "withSystemRole": "도우미 역할 포함" + }, + "stop": "정지", + "stt": { + "action": "음성 입력", + "loading": "인식 중...", + "prettifying": "미화 중..." + }, + "temp": "임시", + "tokenDetail": "역할 설정: {{systemRoleToken}} · 대화 기록: {{chatsToken}}", + "tokenTag": { + "overload": "한도 초과", + "remained": "남음", + "used": "사용" + }, + "topic": { + "confirmRemoveTopic": "해당 주제를 삭제하시겠습니까? 삭제하면 복구할 수 없습니다. 신중하게 작업하세요.", + "defaultTitle": "기본 주제", + "saveCurrentMessages": "현재 대화를 주제로 저장", + "searchPlaceholder": "주제 검색...", + "deleteAll": "모든 주제 삭제", + "deleteUnstarred": "스타가 없는 주제 삭제", + "title": "주제 목록", + "confirmRemoveAll": "모든 주제를 삭제하려고 합니다. 삭제 후에는 복구할 수 없으므로 신중하게 작업하십시오.", + "confirmRemoveUnstarred": "스타를 지정하지 않은 주제를 삭제하려고 합니다. 삭제 후에는 복구할 수 없으므로 신중하게 작업하십시오.", + "removeAll": "모든 주제 삭제", + "removeUnstarred": "스타를 지정하지 않은 주제 삭제", + "openNewTopic": "새로운 주제 열기" + }, + "translate": { + "clear": "번역 지우기", + "action": "번역" + }, + "translateTo": "번역", + "tts": { + "action": "음성 읽기", + "clear": "음성 삭제" + }, + "updateAgent": "도우미 정보 업데이트", + "upload": { + "actionTooltip": "이미지 업로드", + "dragDesc": "여기로 파일을 끌어다 놓으세요. 여러 이미지를 업로드할 수 있습니다. Shift를 누른 채로 이미지를 직접 보내세요.", + "dragTitle": "이미지 업로드" + }, + "warp": "줄바꿈" +} diff --git a/locales/ko_KR/common.json b/locales/ko_KR/common.json new file mode 100644 index 0000000000000..14f863e22c63f --- /dev/null +++ b/locales/ko_KR/common.json @@ -0,0 +1,71 @@ +{ + "about": "소개", + "advanceSettings": "고급 설정", + "agentMaxToken": "세션 최대 길이", + "agentModel": "모델", + "agentProfile": "에이전트 정보", + "appInitializing": "ChatGPT Power이 시작 중입니다. 잠시 기다려주세요...", + "archive": "보관", + "autoGenerate": "자동 생성", + "autoGenerateTooltip": "힌트 단어를 기반으로 에이전트 설명을 자동으로 생성합니다.", + "cancel": "취소", + "changelog": "변경 내역", + "close": "닫기", + "confirmRemoveSessionItemAlert": "에이전트를 삭제하려고 합니다. 삭제 후에는 복구할 수 없습니다. 작업을 확인하세요.", + "copy": "복사", + "copySuccess": "복사 완료", + "defaultAgent": "기본 에이전트", + "defaultSession": "기본 세션", + "delete": "삭제", + "edit": "편집", + "export": "설정 내보내기", + "exportType": { + "agent": "에이전트 설정 내보내기", + "agentWithMessage": "에이전트 및 메시지 내보내기", + "all": "전역 설정 및 모든 에이전트 데이터 내보내기", + "allAgent": "모든 에이전트 설정 내보내기", + "allAgentWithMessage": "모든 에이전트 및 메시지 내보내기", + "globalSetting": "전역 설정 내보내기" + }, + "feedback": "피드백", + "historyRange": "기록 범위", + "import": "설정 가져오기", + "lang": { + "en": "영어", + "en-US": "영어", + "es-ES": "스페인의", + "ja-JP": "일본어", + "ko-KR": "한국어", + "ru-RU": "러시아어", + "zh": "중국어 간체", + "zh-CN": "중국어 간체", + "zh-TW": "중국어 번체" + }, + "layoutInitializing": "레이아웃을 로드 중입니다...", + "noDescription": "설명 없음", + "ok": "확인", + "password": "비밀번호", + "pin": "고정", + "pinOff": "고정 해제", + "regenerate": "재생성", + "rename": "이름 변경", + "reset": "재설정", + "retry": "재시도", + "send": "보내기", + "sessionList": "에이전트 목록", + "setting": "설정", + "share": "공유", + "stop": "중지", + "tab": { + "chat": "채팅", + "market": "탐색", + "setting": "설정" + }, + "temp": "임시", + "updateAgent": "에이전트 정보 업데이트", + "upgradeVersion": { + "action": "지금 업그레이드", + "hasNew": "사용 가능한 업데이트가 있습니다", + "newVersion": "새 버전 사용 가능: {{version}}" + } +} diff --git a/locales/ko_KR/empty.json b/locales/ko_KR/empty.json new file mode 100644 index 0000000000000..8864d20e2abc1 --- /dev/null +++ b/locales/ko_KR/empty.json @@ -0,0 +1,6 @@ +{ + "topic": { + "desc": "현재 대화를 히스토리 토픽으로 저장하고 새로운 대화를 시작하려면 왼쪽 버튼을 클릭하세요.", + "title": "토픽 목록" + } +} diff --git a/locales/ko_KR/error.json b/locales/ko_KR/error.json new file mode 100644 index 0000000000000..b934e1f3c955b --- /dev/null +++ b/locales/ko_KR/error.json @@ -0,0 +1,51 @@ +{ + "pluginSettings": { + "desc": "다음 구성을 완료하면 플러그인을 사용할 수 있습니다.", + "title": "{{name}} 플러그인 설정" + }, + "response": { + "400": "죄송합니다. 서버가 요청을 이해하지 못했습니다. 요청 매개변수가 올바른지 확인해주세요.", + "401": "죄송합니다. 서버가 요청을 거부했습니다. 권한이 부족하거나 유효한 인증 정보를 제공하지 않았을 수 있습니다.", + "403": "죄송합니다. 서버가 요청을 거부했습니다. 이 콘텐츠에 대한 액세스 권한이 없습니다.", + "404": "죄송합니다. 서버가 요청한 페이지나 리소스를 찾을 수 없습니다. URL이 올바른지 확인해주세요.", + "405": "죄송합니다. 서버가 사용한 요청 메서드를 지원하지 않습니다. 요청 메서드가 올바른지 확인해주세요.", + "429": "죄송합니다. 요청이 너무 많아 서버가 약간 지친 상태입니다. 잠시 후에 다시 시도해주세요.", + "500": "죄송합니다. 서버에 문제가 발생하여 요청을 완료할 수 없습니다. 잠시 후에 다시 시도해주세요.", + "502": "죄송합니다. 서버가 잠시 서비스를 제공할 수 없는 상태입니다. 잠시 후에 다시 시도해주세요.", + "503": "죄송합니다. 서버가 현재 요청을 처리할 수 없습니다. 과부하 또는 유지 보수 중일 수 있습니다. 잠시 후에 다시 시도해주세요.", + "504": "죄송합니다. 서버가 상위 서버의 응답을 기다리지 못했습니다. 잠시 후에 다시 시도해주세요.", + "PluginMarketIndexNotFound": "죄송합니다. 서버에서 플러그인 인덱스를 찾을 수 없습니다. 인덱스 주소가 올바른지 확인해주세요.", + "PluginMarketIndexInvalid": "죄송합니다. 플러그인 인덱스 유효성 검사에 실패했습니다. 인덱스 파일 형식이 올바른지 확인해주세요.", + "PluginMetaNotFound": "죄송합니다. 인덱스에서 해당 플러그인을 찾을 수 없습니다. 플러그인의 구성 정보를 인덱스에서 확인해주세요.", + "PluginMetaInvalid": "죄송합니다. 해당 플러그인의 메타 정보 유효성 검사에 실패했습니다. 플러그인 메타 정보 형식이 올바른지 확인해주세요.", + "PluginManifestNotFound": "죄송합니다. 서버에서 해당 플러그인의 설명서 (manifest.json)를 찾을 수 없습니다. 플러그인 설명 파일 주소가 올바른지 확인해주세요.", + "PluginManifestInvalid": "죄송합니다. 해당 플러그인의 설명서 유효성 검사에 실패했습니다. 설명서 형식이 올바른지 확인해주세요.", + "PluginApiNotFound": "죄송합니다. 플러그인 설명서에 해당 API가 없습니다. 요청 메서드와 플러그인 설명서 API가 일치하는지 확인해주세요.", + "PluginApiParamsError": "죄송합니다. 플러그인 요청의 입력 매개변수 유효성 검사에 실패했습니다. 입력 매개변수와 API 설명 정보가 일치하는지 확인해주세요.", + "PluginSettingsInvalid": "플러그인을 사용하려면 올바른 구성이 필요합니다. 구성이 올바른지 확인해주세요.", + "PluginServerError": "플러그인 서버 요청이 오류로 반환되었습니다. 플러그인 설명 파일, 플러그인 구성 또는 서버 구현을 확인해주세요.", + "InvalidAccessCode": "암호가 올바르지 않거나 비어 있습니다. 올바른 액세스 암호를 입력하거나 사용자 지정 OpenAI API 키를 추가해주세요.", + "OpenAIBizError": "OpenAI 서비스 요청 중 오류가 발생했습니다. 아래 정보를 확인하고 문제를 해결하거나 다시 시도해주세요.", + "NoAPIKey": "OpenAI API 키가 비어 있습니다. 사용자 정의 OpenAI API 키를 추가해주세요." + }, + "stt": { + "responseError": "서비스 요청이 실패했습니다. 구성을 확인하거나 다시 시도해주세요." + }, + "tts": { + "responseError": "서비스 요청이 실패했습니다. 구성을 확인하거나 다시 시도해주세요." + }, + "unlock": { + "apikey": { + "title": "사용자 정의 API 키 사용", + "description": "OpenAI API 키를 입력하면 대화를 시작할 수 있습니다. 애플리케이션은 API 키를 기록하지 않습니다.", + "addProxyUrl": "OpenAI 프록시 주소 추가하기 (선택 사항)" + }, + "closeMessage": "알림 닫기", + "confirm": "확인 및 다시 시도", + "password": { + "description": "관리자가 애플리케이션 암호화를 활성화했습니다. 애플리케이션을 잠금 해제하려면 애플리케이션 비밀번호를 입력하십시오. 비밀번호는 한 번만 입력하면 됩니다.", + "title": "암호 입력하여 애플리케이션 잠금 해제", + "placeholder": "비밀번호를 입력하세요" + } + } +} diff --git a/locales/ko_KR/market.json b/locales/ko_KR/market.json new file mode 100644 index 0000000000000..fef8932ecb66a --- /dev/null +++ b/locales/ko_KR/market.json @@ -0,0 +1,30 @@ +{ + "addAgent": "보조 프로그램 추가", + "guide": { + "func1": { + "desc1": "세션 창에서 오른쪽 상단 설정으로 이동하여 도우미를 제출할 설정 페이지로 이동합니다.", + "desc2": "도우미 마켓에 제출 버튼을 클릭합니다.", + "tag": "방법 1", + "title": "ChatGPT Power을 통해 제출하기" + }, + "func2": { + "button": "Github 도우미 저장소로 이동", + "desc": "도우미를 색인에 추가하려면 agent-template.json 또는 agent-template-full.json을 사용하여 plugins 디렉토리에 항목을 작성하고 간단한 설명과 적절한 태그를 추가한 다음 풀 리퀘스트를 생성하십시오.", + "tag": "방법 2", + "title": "Github을 통해 제출하기" + } + }, + "search": { + "placeholder": "보조 프로그램 이름, 설명 또는 키워드 검색..." + }, + "sidebar": { + "comment": "의견", + "prompt": "프롬프트", + "title": "보조 프로그램 세부 정보" + }, + "submitAgent": "보조 프로그램 제출", + "title": { + "allAgents": "모든 보조 프로그램", + "recentSubmits": "최근 추가" + } +} diff --git a/locales/ko_KR/plugin.json b/locales/ko_KR/plugin.json new file mode 100644 index 0000000000000..be09480f7bc4c --- /dev/null +++ b/locales/ko_KR/plugin.json @@ -0,0 +1,109 @@ +{ + "debug": { + "arguments": "함수 호출 인수", + "function_call": "함수 호출", + "response": "응답", + "off": "디버그 끄기", + "on": "플러그인 호출 정보 보기" + }, + "dev": { + "confirmDeleteDevPlugin": "로컬 플러그인을 삭제하시겠습니까? 삭제 후에는 복구할 수 없습니다.", + "deleteSuccess": "플러그인이 성공적으로 삭제되었습니다.", + "manifest": { + "identifier": { + "desc": "플러그인의 고유 식별자", + "label": "식별자" + }, + "mode": { + "local": "시각적 구성", + "local-tooltip": "시각적 구성은 일시적으로 지원되지 않습니다.", + "url": "온라인 링크" + }, + "name": { + "desc": "플러그인 제목", + "label": "제목", + "placeholder": "검색 엔진" + } + }, + "meta": { + "author": { + "desc": "플러그인 작성자", + "label": "작성자" + }, + "avatar": { + "desc": "플러그인 아이콘으로는 Emoji 또는 URL을 사용할 수 있습니다.", + "label": "아이콘" + }, + "description": { + "desc": "플러그인 설명", + "label": "설명", + "placeholder": "검색 엔진에서 정보 가져오기" + }, + "formFieldRequired": "이 필드는 필수 입력 사항입니다.", + "homepage": { + "desc": "플러그인 홈페이지", + "label": "홈페이지" + }, + "identifier": { + "desc": "플러그인의 고유 식별자는 manifest에서 자동으로 인식됩니다.", + "errorDuplicate": "식별자가 이미 있는 플러그인과 중복되었습니다. 식별자를 수정해주세요.", + "label": "식별자", + "pattenErrorMessage": "영문자, 숫자, - 및 _만 입력할 수 있습니다." + }, + "manifest": { + "desc": "ChatGPT Power은 이 링크를 통해 플러그인을 설치합니다.", + "jsonInvalid": "manifest가 규칙에 맞지 않습니다. 유효성 검사 결과: \n\n {{error}}", + "label": "플러그인 설명 파일 URL 주소", + "preview": "Manifest 미리보기", + "refresh": "새로 고침", + "requestError": "이 링크를 요청하는 중에 오류가 발생했습니다. 유효한 링크를 입력하고 링크가 크로스 도메인 액세스를 허용하는지 확인해주세요.", + "urlError": "이 링크는 JSON 형식의 내용을 반환하지 않습니다. 유효한 링크를 입력해주세요." + }, + "title": { + "desc": "플러그인 제목", + "label": "제목", + "placeholder": "검색 엔진" + } + }, + "metaConfig": "플러그인 메타 정보 구성", + "modalDesc": "사용자 정의 플러그인을 추가하면 플러그인 개발 검증 및 세션에서 직접 사용할 수 있습니다. 플러그인 개발 문서는 참조해주세요.", + "preview": { + "card": "플러그인 미리보기", + "desc": "플러그인 설명 미리보기", + "title": "플러그인 이름 미리보기" + }, + "save": "저장", + "saveSuccess": "플러그인 설정이 성공적으로 저장되었습니다.", + "tabs": { + "manifest": "기능 설명 목록 (Manifest)", + "meta": "플러그인 메타 정보" + }, + "title": "사용자 정의 플러그인 추가", + "update": "업데이트", + "updateSuccess": "플러그인 설정이 성공적으로 업데이트되었습니다." + }, + "list": { + "item": { + "deprecated.title": "삭제됨", + "local.config": "구성", + "local.title": "사용자 정의" + } + }, + "loading": { + "plugin": "플러그인 실행 중...", + "content": "플러그인 호출 중..." + }, + "pluginList": "플러그인 목록", + "plugins": { + "unknown": "플러그인 검사 중..." + }, + "setting": "플러그인 설정", + "settings": { + "indexUrl": { + "title": "마켓 인덱스", + "tooltip": "온라인 편집은 지원되지 않습니다. 배포 환경 변수를 통해 설정해주세요." + }, + "modalDesc": "플러그인 마켓의 주소를 구성하면 사용자 정의 플러그인 마켓을 사용할 수 있습니다.", + "title": "플러그인 마켓 설정" + } +} diff --git a/locales/ko_KR/setting.json b/locales/ko_KR/setting.json new file mode 100644 index 0000000000000..47bcd1c224cad --- /dev/null +++ b/locales/ko_KR/setting.json @@ -0,0 +1,284 @@ +{ + "danger": { + "clear": { + "action": "지금 지우기", + "confirm": "모든 채팅 데이터를 지우시겠습니까?", + "desc": "모든 대화 데이터를 지웁니다.", + "success": "모든 대화 메시지가 지워졌습니다.", + "title": "모든 대화 메시지 지우기" + }, + "reset": { + "action": "지금 재설정", + "confirm": "모든 설정을 재설정하시겠습니까?", + "currentVersion": "현재 버전", + "desc": "모든 설정 항목을 기본값으로 재설정합니다.", + "title": "모든 설정 재설정" + } + }, + "header": { + "global": "전역 설정", + "session": "세션 설정", + "sessionWithName": "세션 설정 · {{name}}" + }, + "llm": { + "AzureOpenAI": { + "endpoint": { + "desc": "Azure 포털에서 리소스를 확인할 때 이 값을 '키 및 엔드포인트' 섹션에서 찾을 수 있습니다.", + "placeholder": "https://docs-test-001.openai.azure.com", + "title": "Azure API 주소" + }, + "models": { + "desc": "지원되는 모델", + "title": "모델 목록" + }, + "title": "Azure OpenAI 설정", + "token": { + "desc": "Azure 포털에서 리소스를 확인할 때 이 값을 '키 및 엔드포인트' 섹션에서 찾을 수 있습니다. KEY1 또는 KEY2를 사용할 수 있습니다.", + "placeholder": "Azure API 키", + "title": "API 키" + } + }, + "OpenAI": { + "azureApiVersion": { + "desc": "Azure의 API 버전입니다. YYYY-MM-DD 형식을 따릅니다. [최신 버전](https://learn.microsoft.com/ko-kr/azure/ai-services/openai/reference#chat-completions)을 확인하세요.", + "fetch": "목록 가져오기", + "title": "Azure API 버전" + }, + "check": { + "button": "확인", + "desc": "API 키와 프록시 주소가 올바르게 입력되었는지 테스트합니다.", + "pass": "확인 완료", + "title": "연결성 확인" + }, + "endpoint": { + "desc": "기본 주소 외에도 반드시 http(s)://를 포함해야 합니다.", + "placeholder": "https://api.openai.com/v1", + "title": "인터페이스 프록시 주소" + }, + "models": { + "count": "총 {{count}}개의 모델 지원", + "desc": "지원되는 모델", + "fetch": "모델 목록 가져오기", + "notSupport": "Azure OpenAI에서 모델 목록을 볼 수 없습니다.", + "notSupportTip": "배포 이름과 모델 이름이 일치하는지 확인해야 합니다.", + "refetch": "모델 목록 다시 가져오기", + "title": "모델 목록" + }, + "title": "OpenAI 설정", + "token": { + "desc": "자체 OpenAI 키 사용", + "placeholder": "OpenAI API 키", + "title": "API 키" + }, + "useAzure": { + "desc": "Azure에서 제공하는 OpenAI 서비스 사용", + "fetch": "목록 가져오기", + "serverConfig": "관리자가 서버에서 Azure OpenAI를 구성했으므로 변경이 금지되었습니다.", + "title": "Azure OpenAI" + }, + "customModelName": { + "desc": "사용자 정의 모델 추가, 여러 모델은 쉼표(,)로 구분합니다", + "placeholder": "model1,model2,model3", + "title": "사용자 정의 모델 이름" + } + }, + "waitingForMore": "더 많은 모델이 <1>계획 중에 있으니 기대해주세요 ✨" + }, + "settingAgent": { + "avatar": { + "title": "아바타" + }, + "backgroundColor": { + "title": "배경색" + }, + "description": { + "placeholder": "도우미 설명을 입력하세요.", + "title": "도우미 설명" + }, + "name": { + "placeholder": "도우미 이름을 입력하세요.", + "title": "이름" + }, + "prompt": { + "placeholder": "역할 프롬프트 힌트를 입력하세요.", + "title": "역할 설정" + }, + "tag": { + "placeholder": "태그를 입력하세요.", + "title": "태그" + }, + "title": "도우미 정보" + }, + "settingChat": { + "chatStyleType": { + "title": "채팅 창 스타일", + "type": { + "chat": "대화 모드", + "docs": "문서 모드" + } + }, + "compressThreshold": { + "desc": "압축되지 않은 이전 메시지가이 값보다 크면 압축됩니다.", + "title": "압축 임계값" + }, + "enableCompressThreshold": { + "title": "이전 메시지 길이 압축 사용" + }, + "enableHistoryCount": { + "alias": "제한 없음", + "limited": "대화 메시지 {{number}} 개만 포함", + "title": "대화 메시지 제한", + "unlimited": "대화 메시지 제한 없음" + }, + "historyCount": { + "desc": "요청당 포함되는 이전 메시지 수", + "title": "포함된 이전 메시지 수" + }, + "inputTemplate": { + "desc": "사용자의 최신 메시지가이 템플릿에 채워집니다.", + "placeholder": "사전 처리 템플릿 {{text}}은(는) 실시간 입력 정보로 대체됩니다.", + "title": "사용자 입력 사전 처리" + }, + "title": "채팅 설정", + "autoCreateTopicThreshold": { + "desc": "현재 메시지 수가이 값 이상이면 자동으로 주제를 만듭니다.", + "title": "메시지 임계값" + }, + "enableAutoCreateTopic": { + "desc": "대화 중에 주제를 자동으로 만들지 여부를 설정합니다. 임시 주제에서만 작동합니다.", + "title": "주제 자동 생성" + } + }, + "settingModel": { + "enableMaxTokens": { + "title": "단일 응답 제한 사용" + }, + "frequencyPenalty": { + "desc": "값이 클수록 반복 단어가 줄어듭니다.", + "title": "빈도 패널티" + }, + "maxTokens": { + "desc": "단일 상호 작용에 사용되는 최대 토큰 수", + "title": "단일 응답 제한" + }, + "model": { + "desc": "ChatGPT 모델", + "list": { + "gpt-3.5-turbo": "GPT 3.5", + "gpt-3.5-turbo-16k": "GPT 3.5 (16K)", + "gpt-4": "GPT 4", + "gpt-4-32k": "GPT 4 (32K)" + }, + "title": "모델" + }, + "presencePenalty": { + "desc": "값이 클수록 새로운 주제로 확장될 가능성이 높아집니다.", + "title": "주제 신선도" + }, + "temperature": { + "desc": "값이 클수록 응답이 더 무작위 해집니다.", + "title": "랜덤성", + "titleWithValue": "랜덤성 {{value}}" + }, + "title": "모델 설정", + "topP": { + "desc": "랜덤성과 유사하지만 함께 변경하지 마십시오.", + "title": "상위 P 샘플링" + } + }, + "settingPlugin": { + "add": "추가", + "addTooltip": "사용자 정의 플러그인 추가", + "clearDeprecated": "사용되지 않는 플러그인 제거", + "config": "{{id}} 플러그인 구성", + "settings": "플러그인 마켓 설정", + "title": "플러그인 목록" + }, + "settingSystem": { + "accessCode": { + "desc": "관리자가 암호 액세스를 활성화했습니다.", + "placeholder": "액세스 코드를 입력하세요.", + "title": "액세스 코드" + }, + "title": "시스템 설정" + }, + "settingTTS": { + "showAllLocaleVoice": { + "desc": "현재 언어의 음성만 표시하려면 닫으십시오", + "title": "모든 언어 음성 표시" + }, + "sttService": { + "desc": "브라우저는 브라우저 기본 음성 인식 서비스입니다", + "title": "음성 인식 서비스" + }, + "title": "음성 서비스", + "ttsService": { + "desc": "OpenAI 음성 합성 서비스를 사용하는 경우 OpenAI 모델 서비스가 열려 있어야 합니다", + "title": "음성 합성 서비스" + }, + "voice": { + "title": "음성 합성 음성", + "desc": "현재 어시스턴트에 대한 음성을 선택하십시오. 각기 다른 TTS 서비스는 다른 음성을 지원합니다.", + "preview": "프리뷰 음성" + }, + "openai": { + "sttModel": "OpenAI 음성 인식 모델", + "ttsModel": "OpenAI 음성 합성 모델" + }, + "stt": "음성 인식 설정", + "sttLocale": { + "desc": "음성 입력의 언어, 이 옵션을 통해 음성 인식 정확도를 높일 수 있습니다.", + "title": "음성 인식 언어" + }, + "sttPersisted": { + "desc": "활성화하면 음성 인식이 자동으로 종료되지 않고, 수동으로 종료 버튼을 클릭해야 합니다.", + "title": "음성 인식 수동 종료" + }, + "tts": "음성 합성 설정", + "sttAutoStop": { + "desc": "자동으로 종료되지 않고 수동으로 종료 버튼을 클릭해야 하는 음성 인식을 사용하지 않습니다.", + "title": "음성 인식 자동 종료" + } + }, + "settingTheme": { + "avatar": { + "title": "아바타" + }, + "fontSize": { + "desc": "채팅 콘텐츠의 글꼴 크기", + "title": "글꼴 크기" + }, + "lang": { + "autoMode": "시스템에 따름", + "title": "언어" + }, + "neutralColor": { + "desc": "다양한 색상 경향의 중립적인 사용자 정의", + "title": "중립 색상" + }, + "primaryColor": { + "desc": "사용자 정의 테마 색상", + "title": "테마 색상" + }, + "themeMode": { + "auto": "자동", + "dark": "다크", + "light": "라이트", + "title": "테마" + }, + "title": "테마 설정" + }, + "submitAgentModal": { + "tooltips": "도우미 마켓에 공유", + "button": "도우미 제출", + "identifier": "식별자 도우미 식별자", + "metaMiss": "도우미 정보를 입력한 후 제출하세요. 이름, 설명 및 태그를 포함해야 합니다.", + "placeholder": "도우미의 식별자를 입력하세요. 고유해야 하며, 예를 들어 web-development과 같은 형식이어야 합니다." + }, + "tab": { + "agent": "기본 도우미", + "common": "일반 설정", + "llm": "언어 모델", + "tts": "음성 서비스" + } +} diff --git a/locales/ko_KR/welcome.json b/locales/ko_KR/welcome.json new file mode 100644 index 0000000000000..8247b64d2f177 --- /dev/null +++ b/locales/ko_KR/welcome.json @@ -0,0 +1,14 @@ +{ + "button": { + "import": "구성 가져오기", + "start": "지금 시작" + }, + "header": "환영합니다", + "pickAgent": "또는 다음 도우미 템플릿 중 하나를 선택하세요", + "skip": "생성 건너뛰기", + "slogan": { + "desc1": "뇌 클러스터를 시작하여 아이디어를 자극하세요. 당신의 지능형 어시스턴트가 항상 여기에 있습니다.", + "desc2": "첫 번째 어시스턴트를 만들어 보세요. 시작해 봅시다~", + "title": "더 똑똑한 뇌를 위해 스스로에게 선물하세요" + } +} diff --git a/locales/ru_RU/chat.json b/locales/ru_RU/chat.json new file mode 100644 index 0000000000000..b6196bb49d26e --- /dev/null +++ b/locales/ru_RU/chat.json @@ -0,0 +1,80 @@ +{ + "agentDefaultMessage": "Привет, я **{{name}}**, ты можешь начать разговор со мной прямо сейчас или перейти к [настройкам помощника](/chat/settings#session={{id}}), чтобы улучшить мою информацию.", + "agentDefaultMessageWithSystemRole": "Привет, я **{{name}}**, {{systemRole}}, давай начнем разговор!", + "backToBottom": "К последнему сообщению", + "clearCurrentMessages": "Очистить текущий разговор", + "confirmClearCurrentMessages": "Вы собираетесь очистить текущий разговор, после этого его нельзя будет восстановить. Подтвердите свое действие.", + "confirmRemoveSessionItemAlert": "Вы собираетесь удалить этого помощника, после этого его нельзя будет восстановить. Подтвердите свое действие.", + "defaultAgent": "Пользовательский помощник", + "defaultSession": "Пользовательский помощник", + "historyRange": "История сообщений", + "inbox": { + "defaultMessage": "Привет, я твой интеллектуальный помощник. Ты можешь задать мне любой вопрос, и я постараюсь ответить на него. Если тебе нужен более профессиональный или настроенный помощник, нажми на `+`, чтобы создать пользовательского помощника.", + "desc": "Включи кластер мозгов и разгори искру мысли. Твой интеллектуальный помощник, готовый общаться о всем здесь", + "title": "Просто поболтаем" + }, + "newAgent": "Создать помощника", + "noDescription": "Нет описания", + "pin": "Закрепить", + "pinOff": "Открепить", + "regenerate": "Сгенерировать заново", + "roleAndArchive": "Роль и архив", + "searchAgentPlaceholder": "Поиск помощников и разговоров...", + "send": "Отправить", + "sendPlaceholder": "Введите текст сообщения...", + "sessionList": "Список помощников", + "shareModal": { + "download": "Скачать скриншот", + "imageType": "Тип изображения", + "screenshot": "Скриншот", + "settings": "Настройки экспорта", + "shareToShareGPT": "Создать ссылку ShareGPT для обмена", + "withBackground": "С фоновым изображением", + "withFooter": "С нижним колонтитулом", + "withPluginInfo": "С информацией о плагине", + "withSystemRole": "С указанием роли помощника" + }, + "stop": "Остановить", + "stt": { + "action": "Голосовой ввод", + "loading": "Идет распознавание...", + "prettifying": "Форматирование..." + }, + "temp": "Временный", + "tokenDetail": "Роль помощника: {{systemRoleToken}} · История сообщений: {{chatsToken}}", + "tokenTag": { + "overload": "Превышение лимита", + "remained": "Осталось", + "used": "Использовано" + }, + "topic": { + "confirmRemoveTopic": "Вы собираетесь удалить эту тему, после этого ее нельзя будет восстановить. Подтвердите свое действие.", + "defaultTitle": "Стандартная тема", + "saveCurrentMessages": "Сохранить текущий разговор как тему", + "searchPlaceholder": "Поиск темы...", + "deleteAll": "Удалить все темы", + "deleteUnstarred": "Удалить неотмеченные темы", + "title": "Список тем", + "confirmRemoveAll": "Вы собираетесь удалить все темы. После удаления их будет невозможно восстановить. Пожалуйста, будьте осторожны.", + "confirmRemoveUnstarred": "Вы собираетесь удалить неотмеченные темы. После удаления их будет невозможно восстановить. Пожалуйста, будьте осторожны.", + "removeAll": "Удалить все темы", + "removeUnstarred": "Удалить неотмеченные темы", + "openNewTopic": "Открыть новую тему" + }, + "translate": { + "clear": "Очистить перевод", + "action": "перевести" + }, + "translateTo": "Перевести на", + "tts": { + "action": "воспроизвести речь", + "clear": "очистить речь" + }, + "updateAgent": "Обновить информацию о помощнике", + "upload": { + "actionTooltip": "Загрузить изображение", + "dragDesc": "Перетащите файлы сюда, поддерживается загрузка нескольких изображений. Удерживайте клавишу Shift для прямой отправки изображений", + "dragTitle": "Загрузить изображение" + }, + "warp": "Перенос строки" +} diff --git a/locales/ru_RU/common.json b/locales/ru_RU/common.json new file mode 100644 index 0000000000000..ef952b1df2e89 --- /dev/null +++ b/locales/ru_RU/common.json @@ -0,0 +1,72 @@ +{ + "about": "Наш Github", + "advanceSettings": "Дополнительные настройки", + "agentDefaultMessage": "Здравствуйте, я **{{name}}**. Вы можете начать общаться со мной прямо сейчас или перейти на [Agent Settings](/chat/settings#session={{id}}) для моей настройки.", + "agentMaxToken": "Максимальная длина сессии", + "agentModel": "Модель", + "agentProfile": "Информация о помощнике", + "appInitializing": "ChatGPT Power запускается, пожалуйста, подождите...", + "archive": "Архив", + "autoGenerate": "Автогенерация", + "autoGenerateTooltip": "Автогенерация описания помощника на основе подсказок", + "cancel": "Отмена", + "changelog": "Журнал изменений", + "close": "Закрывать", + "confirmRemoveSessionItemAlert": "Вы собираетесь удалить этого помощника? После удаления его невозможно восстановить. Пожалуйста, подтвердите вашу операцию.", + "copy": "Копировать", + "copySuccess": "Скопировано", + "defaultAgent": "Пользовательский ассистент", + "defaultSession": "Пользовательский ассистент", + "delete": "Удалить", + "edit": "Редактировать", + "export": "Экспорт конфига", + "exportType": { + "agent": "Экспорт настроек помощника", + "agentWithMessage": "Экспорт помощника и переписки", + "all": "Экспорт глобальных настроек и всех данных ассистента", + "allAgent": "Экспорт всех настроек ассистента", + "allAgentWithMessage": "Экспорт всех помощников и переписок", + "globalSetting": "Экспорт глобальных настроек" + }, + "feedback": "Обратная связь", + "historyRange": "Исторический диапазон", + "import": "Импорт конфига", + "lang": { + "en": "Английский", + "en-US": "Английский", + "es-ES": "испанский", + "ja-JP": "Японский", + "ko-KR": "Корейский", + "ru-RU": "Русский", + "zh": "Китайский (упрощенный)", + "zh-CN": "Китайский (упрощенный)", + "zh-TW": "Китайский (традиционный)" + }, + "layoutInitializing": "Идет загрузка макета...", + "noDescription": "Нет описания", + "ok": "ОК", + "password": "пароль", + "pin": "Закрепить", + "pinOff": "Открепить", + "regenerate": "Ре-генерация", + "rename": "Переименовать", + "reset": "Сброс", + "retry": "Повторить", + "send": "Отправить", + "sessionList": "Список помощников", + "setting": "Настройки", + "share": "Поделиться", + "stop": "Остановить", + "tab": { + "chat": "Чат", + "market": "Магазин ассистентов", + "setting": "Настройки" + }, + "temp": "Временный", + "updateAgent": "Обновление информации о помощнике", + "upgradeVersion": { + "action": "Обновить сейчас", + "hasNew": "Доступно обновление", + "newVersion": "Доступна новая версия: {{version}}" + } +} diff --git a/locales/ru_RU/empty.json b/locales/ru_RU/empty.json new file mode 100644 index 0000000000000..b599ed6ca71ca --- /dev/null +++ b/locales/ru_RU/empty.json @@ -0,0 +1,6 @@ +{ + "topic": { + "desc": "Нажмите кнопку слева, чтобы сохранить текущий разговор как историческую тему и начать новый разговор", + "title": "Список тем" + } +} diff --git a/locales/ru_RU/error.json b/locales/ru_RU/error.json new file mode 100644 index 0000000000000..b2e9c19e9864c --- /dev/null +++ b/locales/ru_RU/error.json @@ -0,0 +1,51 @@ +{ + "pluginSettings": { + "desc": "Чтобы начать использовать этот плагин, выполните следующую конфигурацию", + "title": "{{name}} Настройки плагина" + }, + "response": { + "400": "Извините, сервер не понимает ваш запрос. Убедитесь в правильности параметров запроса", + "401": "Извините, сервер отклонил ваш запрос, возможно, из-за недостаточного количества разрешений или недействительной аутентификации.", + "403": "Извините, сервер отклонил ваш запрос. У вас нет разрешения на доступ к этому содержимому", + "404": "Извините, сервер не может найти запрошенную вами страницу или ресурс. Убедитесь, что ваш URL-адрес указан правильно.", + "405": "К сожалению, сервер не поддерживает используемый вами метод запроса. Убедитесь, что ваш метод запроса правильный.", + "429": "Извините, ваш запрос слишком частый, и сервер немного устал. Повторите попытку позже.", + "500": "К сожалению, сервер, похоже, испытывает некоторые трудности и временно не может выполнить ваш запрос. Повторите попытку позже.", + "502": "К сожалению, сервер, похоже, потерян и временно не может предоставлять услуги. Повторите попытку позже.", + "503": "К сожалению, сервер в настоящее время не может обработать ваш запрос, возможно, из-за перегрузки или технического обслуживания. Повторите попытку позже.", + "504": "К сожалению, сервер не получил ответа от вышестоящего сервера. Повторите попытку позже.", + "InvalidAccessCode": "Пароль неверен или пуст. Введите правильный пароль доступа или добавьте собственный ключ API OpenAI.", + "OpenAIBizError": "Ошибка запроса службы OpenAI. Устраните неполадку или повторите попытку, основываясь на следующей информации.", + "PluginMarketIndexNotFound": "К сожалению, сервер не смог найти индекс плагина. Пожалуйста, проверьте правильность адреса индекса", + "PluginMarketIndexInvalid": "К сожалению, проверка индекса плагина не удалась. Пожалуйста, проверьте правильность формата индексного файла", + "PluginMetaNotFound": "К сожалению, плагин не найден в индексе. Пожалуйста, проверьте информацию о конфигурации плагина в индексе", + "PluginMetaInvalid": "К сожалению, проверка метаданных плагина не удалась. Пожалуйста, проверьте правильность формата метаданных плагина", + "PluginManifestNotFound": "К сожалению, серверу не удалось найти файл манифеста плагина (manifest.json). Пожалуйста, проверьте правильность адреса файла манифеста плагина", + "PluginManifestInvalid": "К сожалению, проверка манифеста плагина не удалась. Пожалуйста, проверьте правильность формата манифеста", + "PluginApiNotFound": "К сожалению, API не существует в манифесте плагина. Пожалуйста, проверьте, соответствует ли ваш метод запроса API манифеста плагина", + "PluginApiParamsError": "К сожалению, проверка входных параметров для запроса плагина не удалась. Пожалуйста, проверьте, соответствуют ли входные параметры описанию API", + "PluginSettingsInvalid": "Этот плагин необходимо правильно настроить, прежде чем его можно будет использовать. Пожалуйста, проверьте правильность вашей конфигурации", + "PluginServerError": "Запрос сервера плагина возвратил ошибку. Проверьте файл манифеста плагина, конфигурацию плагина или реализацию сервера на основе информации об ошибке ниже", + "NoAPIKey": "Ключ OpenAI API пуст, пожалуйста, добавьте свой собственный ключ OpenAI API" + }, + "stt": { + "responseError": "Ошибка запроса сервиса. Пожалуйста, проверьте конфигурацию или повторите попытку" + }, + "tts": { + "responseError": "Ошибка запроса сервиса. Пожалуйста, проверьте конфигурацию или повторите попытку" + }, + "unlock": { + "apikey": { + "title": "Использовать собственный ключ API", + "description": "Введите свой ключ API OpenAI, чтобы начать сеанс. Приложение не будет сохранять ваш ключ API.", + "addProxyUrl": "Добавить адрес прокси OpenAI (необязательно)" + }, + "confirm": "Подтвердить и повторить попытку", + "password": { + "description": "Шифрование приложения включено администратором. Введите пароль приложения, чтобы разблокировать приложение. Пароль необходимо ввести только один раз.", + "title": "Введите пароль для разблокировки приложения", + "placeholder": "Введите пароль" + }, + "closeMessage": "Закрыть сообщение" + } +} diff --git a/locales/ru_RU/market.json b/locales/ru_RU/market.json new file mode 100644 index 0000000000000..c63c661a9696d --- /dev/null +++ b/locales/ru_RU/market.json @@ -0,0 +1,30 @@ +{ + "addAgent": "Добавить агента", + "guide": { + "func1": { + "desc1": "Перейдите на страницу настроек, нажав на значок в правом верхнем углу окна сеанса.", + "desc2": "Нажмите кнопку \"Отправить в магазин помощников\" в правом верхнем углу.", + "tag": "Метод 1", + "title": "Отправка через ChatGPT Power" + }, + "func2": { + "button": "Перейти в репозиторий помощника на Github", + "desc": "Если вы хотите добавить помощник в индекс, создайте запись в файле agent-template.json или agent-template-full.json в каталоге плагинов, напишите краткое описание и соответствующие теги, а затем создайте запрос на извлечение.", + "tag": "Метод 2", + "title": "Отправка через Github" + } + }, + "search": { + "placeholder": "Введите название или ключевое слово помощника..." + }, + "sidebar": { + "comment": "Комментарии", + "prompt": "Подсказка", + "title": "Детали агента" + }, + "submitAgent": "Отправить агента", + "title": { + "recentSubmits": "Недавние добавления", + "allAgents": "Все агенты" + } +} diff --git a/locales/ru_RU/plugin.json b/locales/ru_RU/plugin.json new file mode 100644 index 0000000000000..f5629b63b3c51 --- /dev/null +++ b/locales/ru_RU/plugin.json @@ -0,0 +1,109 @@ +{ + "debug": { + "arguments": "Аргументы вызова", + "function_call": "Вызов функции", + "response": "Ответ", + "off": "Выключить отладку", + "on": "Просмотр информации о вызове плагина" + }, + "dev": { + "confirmDeleteDevPlugin": "Вы собираетесь удалить этот локальный плагин. После удаления его будет невозможно восстановить. Вы уверены, что хотите удалить этот плагин?", + "deleteSuccess": "Плагин успешно удален", + "manifest": { + "identifier": { + "desc": "Уникальный идентификатор плагина", + "label": "Идентификатор" + }, + "mode": { + "local": "Визуальная настройка", + "local-tooltip": "Визуальная настройка временно недоступна", + "url": "Онлайн-ссылка" + }, + "name": { + "desc": "Заголовок плагина", + "label": "Заголовок", + "placeholder": "Поиск в поисковой системе" + } + }, + "meta": { + "author": { + "desc": "Автор плагина", + "label": "Автор" + }, + "avatar": { + "desc": "Иконка плагина, можно использовать Emoji или URL", + "label": "Иконка" + }, + "description": { + "desc": "Описание плагина", + "label": "Описание", + "placeholder": "Получение информации из поисковой системы" + }, + "formFieldRequired": "Это обязательное поле", + "homepage": { + "desc": "Домашняя страница плагина", + "label": "Домашняя страница" + }, + "identifier": { + "desc": "Уникальный идентификатор плагина, будет автоматически определен из манифеста", + "errorDuplicate": "Идентификатор уже используется другим плагином. Пожалуйста, измените идентификатор", + "label": "Идентификатор", + "pattenErrorMessage": "Можно вводить только латинские буквы, цифры, - и _" + }, + "manifest": { + "desc": "ChatGPT Power будет устанавливать плагин по этой ссылке", + "jsonInvalid": "Манифест не соответствует стандарту. Результат проверки: \n\n {{error}}", + "label": "URL-адрес описания плагина", + "preview": "Предварительный просмотр манифеста", + "refresh": "Обновить", + "requestError": "Не удалось получить данные по этой ссылке. Пожалуйста, введите действительную ссылку и проверьте, разрешен ли кросс-доменный доступ", + "urlError": "Ссылка не возвращает данные в формате JSON. Пожалуйста, введите действительную ссылку" + }, + "title": { + "desc": "Заголовок плагина", + "label": "Заголовок", + "placeholder": "Поиск в поисковой системе" + } + }, + "metaConfig": "Настройка метаданных плагина", + "modalDesc": "После добавления пользовательского плагина его можно использовать для проверки разработки плагинов или непосредственно в сеансе. См. документацию по разработке плагинов", + "preview": { + "card": "Предварительный просмотр плагина", + "desc": "Предварительный просмотр описания плагина", + "title": "Предварительный просмотр имени плагина" + }, + "save": "Сохранить", + "saveSuccess": "Настройки плагина успешно сохранены", + "tabs": { + "manifest": "Описание функций (Манифест)", + "meta": "Метаданные плагина" + }, + "title": "Добавить пользовательский плагин", + "update": "Обновить", + "updateSuccess": "Настройки плагина успешно обновлены" + }, + "list": { + "item": { + "deprecated.title": "Удалено", + "local.config": "Настройка", + "local.title": "Пользовательский" + } + }, + "loading": { + "plugin": "Выполнение плагина...", + "content": "Вызов плагина..." + }, + "pluginList": "Список плагинов", + "plugins": { + "unknown": "Проверка плагинов..." + }, + "setting": "Настройки плагина", + "settings": { + "indexUrl": { + "title": "Индекс рынка", + "tooltip": "Редактирование в настоящее время недоступно" + }, + "modalDesc": "После настройки адреса рынка плагинов можно использовать пользовательский рынок плагинов", + "title": "Настройки рынка плагинов" + } +} diff --git a/locales/ru_RU/setting.json b/locales/ru_RU/setting.json new file mode 100644 index 0000000000000..d13a1bf6575e6 --- /dev/null +++ b/locales/ru_RU/setting.json @@ -0,0 +1,297 @@ +{ + "danger": { + "clear": { + "action": "Очистить все", + "confirm": "Подтвердить очистку всех данных чата?", + "desc": "Очистить все данные сессии", + "success": "Все сообщения сессии были очищены", + "title": "Очистить все сообщения сессии" + }, + "reset": { + "action": "Сбросить настройки", + "confirm": "Подтвердить сброс всех настроек?", + "currentVersion": "Текущая версия", + "desc": "Сброс всех настроек к значениям по умолчанию", + "title": "Сброс всех настроек" + } + }, + "header": { + "global": "Глобальные настройки", + "session": "Настройки сессии", + "sessionWithName": "Настройки сессии · {{name}}" + }, + "llm": { + "AzureOpenAI": { + "endpoint": { + "desc": "Это значение можно найти в разделе «Ключи и конечные точки» при проверке ресурса на сайте Azure.", + "placeholder": "https://docs-test-001.openai.azure.com", + "title": "Адрес API Azure" + }, + "models": { + "desc": "Поддерживаемые модели", + "title": "Список моделей" + }, + "title": "Настройки Azure OpenAI", + "token": { + "desc": "Это значение можно найти в разделе «Ключи и конечные точки» при проверке ресурса на сайте Azure. Можно использовать KEY1 или KEY2", + "placeholder": "Azure Ключ API", + "title": "Ключ API" + } + }, + "OpenAI": { + "azureApiVersion": { + "desc": "Версия API Azure в формате ГГГГ-ММ-ДД, проверьте [последнюю версию](https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions)", + "fetch": "Получить список", + "title": "Версия Azure Api" + }, + "check": { + "button": "Проверить", + "desc": "Проверьте правильность заполнения Api Key и адреса прокси-сервера.", + "pass": "Подключение успешно", + "title": "Проверка возможности подключения" + }, + "endpoint": { + "desc": "Должен содержать http(s):// в дополнение к адресу по умолчанию.", + "placeholder": "https://api.openai.com/v1", + "title": "адрес API прокси" + }, + "models": { + "count": "Всего поддерживается {{count}} моделей", + "desc": "Поддерживаемые модели", + "fetch": "Получение списка моделей", + "notSupport": "Azure OpenAI в настоящее время не поддерживает просмотр списков моделей", + "notSupportTip": "Необходимо убедиться в том, что имя развертывания совпадает с именем модели", + "refetch": "Получение списка моделей", + "title": "Список моделей" + }, + "title": "Настройки OpenAI", + "token": { + "desc": "Используйте свой собственный ключ OpenAI", + "placeholder": "Ключ API OpenAI", + "title": "Ключ API" + }, + "useAzure": { + "desc": "Использование служб OpenAI из Azure", + "fetch": "Получить список", + "title": "Azure OpenAI", + "serverConfig": "Администратор настроил сервер для использования Azure OpenAI. Переключение запрещено." + }, + "customModelName": { + "desc": "Добавьте пользовательскую модель, разделяя их запятыми (,)", + "placeholder": "model1,model2,model3", + "title": "Название пользовательской модели" + } + }, + "waitingForMore": "<1>Планируется доступ к другим моделям, так что следите за обновлениями ✨" + }, + "settingAgent": { + "avatar": { + "title": "Аватар" + }, + "backgroundColor": { + "title": "Цвет фона" + }, + "description": { + "placeholder": "Пожалуйста, введите описание помощника", + "title": "Описание помощника" + }, + "name": { + "placeholder": "Пожалуйста, введите имя ассистента", + "title": "Название" + }, + "prompt": { + "placeholder": "Пожалуйста, введите роль", + "title": "Промт роли" + }, + "tag": { + "placeholder": "Пожалуйста, введите тег", + "title": "Тег" + }, + "title": "Информация о помощнике" + }, + "settingChat": { + "chatStyleType": { + "title": "Стиль окна чата", + "type": { + "chat": "Режим чата", + "docs": "Режим документа" + } + }, + "compressThreshold": { + "desc": "Когда количество несжатых сообщений истории превысит это значение, будет произведено сжатие", + "title": "Порог сжатия длины истории сообщений" + }, + "enableCompressThreshold": { + "title": "Включить порог сжатия длины сообщений истории" + }, + "enableHistoryCount": { + "alias": "Неограниченный", + "limited": "Включать только {{number}} сообщение(й) сессии", + "title": "Ограничить количество истории сообщений", + "unlimited": "Неограниченное количество истории сообщений" + }, + "historyCount": { + "desc": "Количество сообщений, передаваемых в каждом запросе из истории", + "title": "Количество сообщений в прикрепленной истории" + }, + "inputTemplate": { + "desc": "В этот шаблон будет залито последнее сообщение пользователя", + "placeholder": "{{text}} будут заменены входной информацией, поступающей в режиме реального времени", + "title": "Предварительная обработка пользовательского ввода" + }, + "title": "Настройки чата", + "autoCreateTopicThreshold": { + "desc": "Когда текущее количество сообщений превысит эту величину, будет автоматически создана тема", + "title": "Порог сообщений" + }, + "enableAutoCreateTopic": { + "desc": "Автоматическое создание темы во время разговора, действует только во временной теме", + "title": "Включить автоматическое создание темы" + } + }, + "settingModel": { + "enableMaxTokens": { + "title": "Включить ограничение токенов на один ответ" + }, + "frequencyPenalty": { + "desc": "Чем больше значение, тем больше вероятность сокращения повторяющихся слов", + "title": "Штраф за частоту" + }, + "maxTokens": { + "desc": "Максимальное количество токенов, используемых в одном взаимодействии", + "title": "Лимит на один ответ" + }, + "model": { + "desc": "Модель ChatGPT", + "list": { + "gpt-3.5-turbo": "GPT 3.5", + "gpt-3.5-turbo-16k": "GPT 3.5 (16K)", + "gpt-4": "GPT 4", + "gpt-4-32k": "GPT 4 (32K)" + }, + "title": "Модель" + }, + "presencePenalty": { + "desc": "Чем больше значение, тем больше вероятность общение на левые темы", + "title": "Точность темы" + }, + "temperature": { + "desc": "Чем больше значение, тем более случайным будет ответ", + "title": "Случайность", + "titleWithValue": "Случайность {{value}}" + }, + "title": "Настройки модели", + "topP": { + "desc": "Аналогично случайности, но не изменяются вместе со случайностью", + "title": "Ядерное сэмплирование" + } + }, + "settingOpenAI": { + "endpoint": { + "desc": "Должен включать http(s):// в дополнение к адресу по умолчанию.", + "placeholder": "https://api.openai.com/v1", + "title": "Адрес прокси API" + }, + "title": "Настройки OpenAI", + "token": { + "desc": "Используйте свой собственный ключ OpenAI", + "placeholder": "API-ключ OpenAI", + "title": "API-ключ" + } + }, + "settingPlugin": { + "title": "Список плагинов", + "add": "Добавить", + "addTooltip": "Добавить кастомный плагин", + "config": "{{id}} Конфигурация плагина", + "clearDeprecated": "Удалить недействительные плагины", + "settings": "Настройки плагинов" + }, + "settingSystem": { + "accessCode": { + "desc": "Шифрование доступа включено администратором", + "placeholder": "Пожалуйста, введите пароль доступа", + "title": "Пароль доступа" + }, + "title": "Настройки системы" + }, + "settingTTS": { + "showAllLocaleVoice": { + "desc": "Если отключено, отображаются только голоса текущего языка", + "title": "Показать все голоса локали" + }, + "sttService": { + "desc": "где broswer - это встроенная в браузер служба распознавания речи", + "title": "Служба распознавания речи" + }, + "title": "Служба речи", + "ttsService": { + "desc": "Если используется услуга синтеза речи OpenAI, убедитесь, что услуга модели OpenAI включена", + "title": "Служба синтеза речи" + }, + "voice": { + "title": "Голосовой синтез", + "desc": "Выберите голос для текущего помощника, различные службы TTS поддерживают разные источники звука", + "preview": "Предварительный просмотр голоса" + }, + "openai": { + "sttModel": "Модель распознавания речи OpenAI", + "ttsModel": "Модель синтеза речи OpenAI" + }, + "stt": "Настройки распознавания речи", + "sttLocale": { + "desc": "Язык речи для ввода речи, этот параметр может повысить точность распознавания речи", + "title": "Язык распознавания речи" + }, + "sttPersisted": { + "desc": "При включении распознавание речи не будет автоматически завершаться, необходимо вручную нажать кнопку завершения", + "title": "Вручную завершить распознавание речи" + }, + "tts": "Настройки синтеза речи", + "sttAutoStop": { + "desc": "После отключения распознавания речи оно не будет автоматически останавливаться, вам нужно будет вручную нажать кнопку завершения", + "title": "Автоматическое завершение распознавания речи" + } + }, + "settingTheme": { + "avatar": { + "title": "Аватар" + }, + "fontSize": { + "desc": "Размер шрифта содержимого чата", + "title": "Размер шрифта" + }, + "lang": { + "title": "Языковые настройки", + "autoMode": "Следовать за системой" + }, + "neutralColor": { + "desc": "Пользовательская шкала серого для различных цветовых тенденций", + "title": "Нейтральный цвет" + }, + "primaryColor": { + "desc": "Пользовательский цвет темы", + "title": "Цвет темы" + }, + "themeMode": { + "auto": "Авто", + "dark": "Темная", + "light": "Светлая", + "title": "Тема" + }, + "title": "Настройки темы" + }, + "submitAgentModal": { + "tooltips": "Поделиться на рынке помощников", + "button": "Отправить агента", + "identifier": "Идентификатор агента", + "metaMiss": "Пожалуйста, заполните информацию об агенте перед отправкой. Необходимо указать имя, описание и метки", + "placeholder": "Введите идентификатор агента, который должен быть уникальным, например, web-development" + }, + "tab": { + "agent": "Помощник по умолчанию", + "common": "Общие настройки", + "llm": "Пользовательский API GPT", + "tts": "Сервис речи" + } +} diff --git a/locales/ru_RU/welcome.json b/locales/ru_RU/welcome.json new file mode 100644 index 0000000000000..27aedc248fbdf --- /dev/null +++ b/locales/ru_RU/welcome.json @@ -0,0 +1,14 @@ +{ + "button": { + "import": "Импорт конфига", + "start": "Начать" + }, + "header": "Привет", + "pickAgent": "Или выберите один из следующих шаблонов помощника", + "skip": "Пропустить создание", + "slogan": { + "desc1": "Раскройте силу своего мозга и разожгите свой творческий потенциал. Ваш умный помощник всегда под рукой.", + "desc2": "Создайте своего первого помощника и приступим~", + "title": "Используйте свой мозг более продуктивно" + } +} diff --git a/locales/zh_CN/chat.json b/locales/zh_CN/chat.json new file mode 100644 index 0000000000000..133400a5b1c89 --- /dev/null +++ b/locales/zh_CN/chat.json @@ -0,0 +1,77 @@ +{ + "agentDefaultMessage": "你好,我是 **{{name}}**,你可以立即与我开始对话,也可以前往 [助手设置](/chat/settings#session={{id}}) 完善我的信息。", + "agentDefaultMessageWithSystemRole": "你好,我是 **{{name}}**,{{systemRole}},让我们开始对话吧!", + "backToBottom": "查看最新消息", + "clearCurrentMessages": "清空当前会话消息", + "confirmClearCurrentMessages": "即将清空当前会话消息,清空后将无法找回,请确认你的操作", + "confirmRemoveSessionItemAlert": "即将删除该助手,删除后该将无法找回,请确认你的操作", + "defaultAgent": "自定义助手", + "defaultSession": "自定义助手", + "historyRange": "历史范围", + "inbox": { + "defaultMessage": "你好,我是你的智能助手,你可以问我任何问题,我会尽力回答你。如果需要获得更加专业或定制的助手,可以点击`+`创建自定义助手", + "desc": "开启大脑集群,激发思维火花。你的智能助理,在这里与你交流一切", + "title": "随便聊聊" + }, + "newAgent": "新建助手", + "noDescription": "暂无描述", + "pin": "置顶", + "pinOff": "取消置顶", + "regenerate": "重新生成", + "roleAndArchive": "角色与记录", + "searchAgentPlaceholder": "搜索助手和对话...", + "send": "发送", + "sendPlaceholder": "输入聊天内容...", + "sessionList": "助手列表", + "shareModal": { + "download": "下载截图", + "imageType": "图片格式", + "screenshot": "截图", + "settings": "导出设置", + "shareToShareGPT": "生成 ShareGPT 分享链接", + "withBackground": "包含背景图片", + "withFooter": "包含页脚", + "withPluginInfo": "包含插件信息", + "withSystemRole": "包含助手角色设定" + }, + "stop": "停止", + "stt": { + "action": "语音输入", + "loading": "识别中...", + "prettifying": "润色中..." + }, + "temp": "临时", + "tokenDetail": "角色设定: {{systemRoleToken}} · 历史消息: {{chatsToken}}", + "tokenTag": { + "overload": "超过限制", + "remained": "剩余", + "used": "使用" + }, + "topic": { + "confirmRemoveAll": "即将删除全部话题,删除后将不可恢复,请谨慎操作。", + "confirmRemoveTopic": "即将删除该话题,删除后将不可恢复,请谨慎操作。", + "confirmRemoveUnstarred": "即将删除未收藏话题,删除后将不可恢复,请谨慎操作。", + "defaultTitle": "默认话题", + "openNewTopic": "开启新话题", + "removeAll": "删除全部话题", + "removeUnstarred": "删除未收藏话题", + "saveCurrentMessages": "将当前会话保存为话题", + "searchPlaceholder": "搜索话题...", + "title": "话题列表" + }, + "translate": { + "action": "翻译", + "clear": "删除翻译" + }, + "tts": { + "action": "语音朗读", + "clear": "删除语音" + }, + "updateAgent": "更新助理信息", + "upload": { + "actionTooltip": "上传图片", + "dragDesc": "拖拽文件到这里,支持上传多个图片。按住 Shift 直接发送图片", + "dragTitle": "上传图片" + }, + "warp": "换行" +} diff --git a/locales/zh_CN/common.json b/locales/zh_CN/common.json new file mode 100644 index 0000000000000..ac25b45809196 --- /dev/null +++ b/locales/zh_CN/common.json @@ -0,0 +1,70 @@ +{ + "about": "关于", + "advanceSettings": "高级设置", + "agentMaxToken": "会话最大长度", + "agentModel": "模型", + "agentProfile": "助手信息", + "appInitializing": "ChatGPT Power 启动中,请耐心等待...", + "archive": "归档", + "autoGenerate": "自动补全", + "autoGenerateTooltip": "基于提示词自动补全助手描述", + "cancel": "取消", + "changelog": "更新日志", + "close": "关闭", + "confirmRemoveSessionItemAlert": "即将删除该助手,删除后该将无法找回,请确认你的操作", + "copy": "复制", + "copySuccess": "复制成功", + "defaultAgent": "自定义助手", + "defaultSession": "自定义助手", + "delete": "删除", + "edit": "编辑", + "export": "导出配置", + "exportType": { + "agent": "导出助手设定", + "agentWithMessage": "导出助手和消息", + "all": "导出全局设置和所有助手数据", + "allAgent": "导出所有助手设定", + "allAgentWithMessage": "导出所有助手和消息", + "globalSetting": "导出全局设置" + }, + "feedback": "反馈与建议", + "historyRange": "历史范围", + "import": "导入配置", + "lang": { + "en": "英语", + "en-US": "英语", + "es-ES": "西班牙语", + "ja-JP": "日语", + "ko-KR": "韩语", + "ru-RU": "俄语", + "zh": "简体中文", + "zh-CN": "简体中文", + "zh-TW": "繁体中文" + }, + "layoutInitializing": "正在加载布局...", + "noDescription": "暂无描述", + "ok": "确定", + "password": "密码", + "pin": "置顶", + "pinOff": "取消置顶", + "regenerate": "重新生成", + "rename": "重命名", + "reset": "重置", + "retry": "重试", + "send": "发送", + "setting": "设置", + "share": "分享", + "stop": "停止", + "tab": { + "chat": "会话", + "market": "发现", + "setting": "设置" + }, + "temp": "临时", + "updateAgent": "更新助理信息", + "upgradeVersion": { + "action": "立即升级", + "hasNew": "有可用更新", + "newVersion": "有新版本可用:{{version}}" + } +} diff --git a/locales/zh_CN/empty.json b/locales/zh_CN/empty.json new file mode 100644 index 0000000000000..2ef04cf085140 --- /dev/null +++ b/locales/zh_CN/empty.json @@ -0,0 +1,6 @@ +{ + "topic": { + "desc": "点击发送左侧按钮可将当前会话保存为历史话题,并开启新一轮会话", + "title": "话题列表" + } +} diff --git a/locales/zh_CN/error.json b/locales/zh_CN/error.json new file mode 100644 index 0000000000000..cf51ae8e960ec --- /dev/null +++ b/locales/zh_CN/error.json @@ -0,0 +1,51 @@ +{ + "pluginSettings": { + "desc": "完成以下配置,即可开始使用该插件", + "title": "{{name}} 插件配置" + }, + "response": { + "400": "很抱歉,服务器不明白您的请求,请确认您的请求参数是否正确", + "401": "很抱歉,服务器拒绝了您的请求,可能是因为您的权限不足或未提供有效的身份验证", + "403": "很抱歉,服务器拒绝了您的请求,您没有访问此内容的权限 ", + "404": "很抱歉,服务器找不到您请求的页面或资源,请确认您的 URL 是否正确", + "405": "很抱歉,服务器不支持您使用的请求方法,请确认您的请求方法是否正确", + "429": "很抱歉,您的请求太多,服务器有点累了,请稍后再试", + "500": "很抱歉,服务器似乎遇到了一些困难,暂时无法完成您的请求,请稍后再试", + "502": "很抱歉,服务器似乎迷失了方向,暂时无法提供服务,请稍后再试", + "503": "很抱歉,服务器当前无法处理您的请求,可能是由于过载或正在进行维护,请稍后再试", + "504": "很抱歉,服务器没有等到上游服务器的回应,请稍后再试", + "PluginMarketIndexNotFound": "很抱歉,服务器没有找到插件索引,请检查索引地址是否正确", + "PluginMarketIndexInvalid": "很抱歉,插件索引校验未通过,请检查索引文件格式是否规范", + "PluginMetaNotFound": "很抱歉,没有在索引中发现该插件,请插件在索引中的配置信息", + "PluginMetaInvalid": "很抱歉,该插件的元信息校验未通过,请检查插件元信息格式是否规范", + "PluginManifestNotFound": "很抱歉,服务器没有找到该插件的描述清单 (manifest.json),请检查插件描述文件地址是否正确", + "PluginManifestInvalid": "很抱歉,该插件的描述清单校验未通过,请检查描述清单格式是否规范", + "PluginApiNotFound": "很抱歉,插件描述清单中不存在该 API ,请检查你的请求方法与插件清单 API 是否匹配", + "PluginApiParamsError": "很抱歉,该插件请求的入参校验未通过,请检查入参与 Api 描述信息是否匹配", + "PluginSettingsInvalid": "该插件需要正确配置后才可以使用,请检查你的配置是否正确", + "PluginServerError": "插件服务端请求返回出错,请检查根据下面的报错信息检查你的插件描述文件、插件配置或服务端实现", + "InvalidAccessCode": "密码不正确或为空,请输入正确的访问密码,或者添加自定义 OpenAI API Key", + "OpenAIBizError": "请求 OpenAI 服务出错,请根据以下信息排查或重试", + "NoAPIKey": "OpenAI API Key 为空,请添加自定义 OpenAI API Key" + }, + "stt": { + "responseError": "服务请求失败,请检查配置或重试" + }, + "tts": { + "responseError": "服务请求失败,请检查配置或重试" + }, + "unlock": { + "apikey": { + "addProxyUrl": "添加 OpenAI 代理地址(可选)", + "description": "输入你的 OpenAI API Key 即可开始会话。应用不会记录你的 API Key", + "title": "使用自定义 API Key" + }, + "closeMessage": "关闭提示", + "confirm": "确认并重试", + "password": { + "description": "管理员已开启应用加密,输入应用密码后即可解锁应用。密码只需填写一次", + "placeholder": "请输入密码", + "title": "输入密码解锁应用" + } + } +} diff --git a/locales/zh_CN/market.json b/locales/zh_CN/market.json new file mode 100644 index 0000000000000..21b346c322b3d --- /dev/null +++ b/locales/zh_CN/market.json @@ -0,0 +1,30 @@ +{ + "addAgent": "添加助手", + "guide": { + "func1": { + "desc1": "在会话窗口中通过右上角设置进入你想提交助手的设置页面;", + "desc2": "点击右上角提交到助手市场按钮。", + "tag": "方法一", + "title": "通过 ChatGPT Power 提交" + }, + "func2": { + "button": "前往 Github 助手仓库", + "desc": "如果您想将助手添加到索引中,请使用 agent-template.json 或 agent-template-full.json 在 plugins 目录中创建一个条目,编写简短的描述并适当标记,然后创建一个拉取请求。", + "tag": "方法二", + "title": "通过 Github 提交" + } + }, + "search": { + "placeholder": "搜索助手名称介绍或关键词..." + }, + "sidebar": { + "comment": "讨论区", + "prompt": "提示词", + "title": "助手详情" + }, + "submitAgent": "提交助手", + "title": { + "allAgents": "全部助手", + "recentSubmits": "最近新增" + } +} diff --git a/locales/zh_CN/plugin.json b/locales/zh_CN/plugin.json new file mode 100644 index 0000000000000..1ca24f2332772 --- /dev/null +++ b/locales/zh_CN/plugin.json @@ -0,0 +1,109 @@ +{ + "debug": { + "arguments": "调用参数", + "function_call": "函数调用", + "off": "关闭调试", + "on": "查看插件调用信息", + "response": "返回结果" + }, + "dev": { + "confirmDeleteDevPlugin": "即将删除该本地插件,删除后将无法找回,是否删除该插件?", + "deleteSuccess": "插件删除成功", + "manifest": { + "identifier": { + "desc": "插件的唯一标识", + "label": "标识符" + }, + "mode": { + "local": "可视化配置", + "local-tooltip": "暂时不支持可视化配置", + "url": "在线链接" + }, + "name": { + "desc": "插件标题", + "label": "标题", + "placeholder": "搜索引擎" + } + }, + "meta": { + "author": { + "desc": "插件的作者", + "label": "作者" + }, + "avatar": { + "desc": "插件的图标,可以使用 Emoji,也可以使用 URL", + "label": "图标" + }, + "description": { + "desc": "插件描述", + "label": "描述", + "placeholder": "查询搜索引擎获取信息" + }, + "formFieldRequired": "该字段为必填项", + "homepage": { + "desc": "插件的首页", + "label": "首页" + }, + "identifier": { + "desc": "插件的唯一标识,将从 manifest 中自动识别", + "errorDuplicate": "标识符和已有插件重复,请修改标识符", + "label": "标识符", + "pattenErrorMessage": "只能输入英文字符、数字 、- 和_ 这两个符号" + }, + "manifest": { + "desc": "ChatGPT Power 将会通过该链接安装插件", + "jsonInvalid": " manifest 不符合规范,校验结果: \n\n {{error}}", + "label": "插件描述文件 Url 地址", + "preview": "预览 Manifest", + "refresh": "刷新", + "requestError": "请求该链接失败,请输入一个有效的链接,并检查链接是否允许跨域访问", + "urlError": "该链接没有返回 JSON 格式的内容, 请输入一个有效的链接" + }, + "title": { + "desc": "插件标题", + "label": "标题", + "placeholder": "搜索引擎" + } + }, + "metaConfig": "插件元信息配置", + "modalDesc": "添加自定义插件后,可用于插件开发验证,也可直接在会话中使用。插件开发文档请参考", + "preview": { + "card": "预览插件展示效果", + "desc": "预览插件描述", + "title": "插件名称预览" + }, + "save": "保存", + "saveSuccess": "插件设置保存成功", + "tabs": { + "manifest": "功能描述清单 (Manifest)", + "meta": "插件元信息" + }, + "title": "添加自定义插件", + "update": "更新", + "updateSuccess": "插件设置更新成功" + }, + "list": { + "item": { + "deprecated.title": "已删除", + "local.config": "配置", + "local.title": "自定义" + } + }, + "loading": { + "content": "调用插件中...", + "plugin": "插件运行中..." + }, + "pluginList": "插件列表", + "plugins": { + "unknown": "插件检测中..." + }, + "setting": "插件设置", + "settings": { + "indexUrl": { + "title": "市场索引", + "tooltip": "暂不支持在线编辑,请通过部署时环境变量进行设置" + }, + "modalDesc": "配置插件市场的地址后,可以使用自定义的插件市场", + "title": "设置插件市场" + } +} diff --git a/locales/zh_CN/setting.json b/locales/zh_CN/setting.json new file mode 100644 index 0000000000000..2f0149cf060c8 --- /dev/null +++ b/locales/zh_CN/setting.json @@ -0,0 +1,280 @@ +{ + "danger": { + "clear": { + "action": "立即清除", + "confirm": "确认清除所有聊天数据?", + "desc": "清除所有会话数据", + "success": "已清除所有会话消息", + "title": "清除所有会话消息" + }, + "reset": { + "action": "立即重置", + "confirm": "确认重置所有设置?", + "currentVersion": "当前版本", + "desc": "重置所有设置项回默认值", + "title": "重置所有设置" + } + }, + "header": { + "global": "全局设置", + "session": "会话设置", + "sessionWithName": "会话设置 · {{name}}" + }, + "llm": { + "AzureOpenAI": { + "endpoint": { + "desc": "从 Azure 门户检查资源时,可在“密钥和终结点”部分中找到此值", + "placeholder": "https://docs-test-001.openai.azure.com", + "title": "Azure API 地址" + }, + "models": { + "desc": "支持的模型", + "title": "模型列表" + }, + "title": "Azure OpenAI 设置", + "token": { + "desc": "从 Azure 门户检查资源时,可在“密钥和终结点”部分中找到此值。 可以使用 KEY1 或 KEY2", + "placeholder": "Azure API Key", + "title": "API Key" + } + }, + "OpenAI": { + "azureApiVersion": { + "desc": "Azure 的 API 版本,遵循 YYYY-MM-DD 格式,查阅[最新版本](https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions)", + "fetch": "获取列表", + "title": "Azure Api Version" + }, + "check": { + "button": "检查", + "desc": "测试 Api Key 与代理地址是否正确填写", + "pass": "检查通过", + "title": "连通性检查" + }, + "customModelName": { + "desc": "增加自定义模型,多个模型使用逗号(,) 隔开", + "placeholder": "model1,model2,model3", + "title": "自定义模型名称" + }, + "endpoint": { + "desc": "除默认地址外,必须包含 http(s)://", + "placeholder": "https://api.openai.com/v1", + "title": "接口代理地址" + }, + "models": { + "count": "共支持 {{count}} 个模型", + "desc": "支持的模型", + "fetch": "获取模型列表", + "notSupport": "Azure OpenAI 暂不支持查看模型列表", + "notSupportTip": "你需要自行确保部署名称与模型名称一致", + "refetch": "重新获取模型列表", + "title": "模型列表" + }, + "title": "OpenAI 设置", + "token": { + "desc": "使用自己的 OpenAI Key", + "placeholder": "OpenAI API Key", + "title": "API Key" + }, + "useAzure": { + "desc": "使用 Azure 提供的 OpenAI 服务", + "fetch": "获取列表", + "serverConfig": "管理员在服务端配置开启了 Azure OpenAI,禁止切换", + "title": "Azure OpenAI" + } + }, + "waitingForMore": "更多模型正在 <1>计划接入 中,敬请期待 ✨" + }, + "settingAgent": { + "avatar": { + "title": "头像" + }, + "backgroundColor": { + "title": "背景色" + }, + "description": { + "placeholder": "请输入助手描述", + "title": "助手描述" + }, + "name": { + "placeholder": "请输入助手名称", + "title": "名称" + }, + "prompt": { + "placeholder": "请输入角色 Prompt 提示词", + "title": "角色设定" + }, + "tag": { + "placeholder": "请输入标签", + "title": "标签" + }, + "title": "助手信息" + }, + "settingChat": { + "autoCreateTopicThreshold": { + "desc": "当前消息数超过设定该值后,将自动创建话题", + "title": "消息阈值" + }, + "chatStyleType": { + "title": "聊天窗口样式", + "type": { + "chat": "对话模式", + "docs": "文档模式" + } + }, + "compressThreshold": { + "desc": "当未压缩的历史消息超过该值时,将进行压缩", + "title": "历史消息长度压缩阈值" + }, + "enableAutoCreateTopic": { + "desc": "会话过程中是否自动创建话题,仅在临时话题中生效", + "title": "自动创建话题" + }, + "enableCompressThreshold": { + "title": "是否开启历史消息长度压缩阈值" + }, + "enableHistoryCount": { + "alias": "不限制", + "limited": "只包含 {{number}} 条会话消息", + "title": "限制历史消息数", + "unlimited": "不限历史消息数" + }, + "historyCount": { + "desc": "每次请求携带的历史消息数", + "title": "附带历史消息数" + }, + "inputTemplate": { + "desc": "用户最新的一条消息会填充到此模板", + "placeholder": "预处理模版 {{text}} 将替换为实时输入信息", + "title": "用户输入预处理" + }, + "title": "聊天设置" + }, + "settingModel": { + "enableMaxTokens": { + "title": "开启单次回复限制" + }, + "frequencyPenalty": { + "desc": "值越大,越有可能降低重复字词", + "title": "频率惩罚度" + }, + "maxTokens": { + "desc": "单次交互所用的最大 Token 数", + "title": "单次回复限制" + }, + "model": { + "desc": "ChatGPT 模型", + "list": { + "gpt-3.5-turbo": "GPT 3.5", + "gpt-3.5-turbo-16k": "GPT 3.5 (16K)", + "gpt-4": "GPT 4", + "gpt-4-32k": "GPT 4 (32K)" + }, + "title": "模型" + }, + "presencePenalty": { + "desc": "值越大,越有可能扩展到新话题", + "title": "话题新鲜度" + }, + "temperature": { + "desc": "值越大,回复越随机", + "title": "随机性", + "titleWithValue": "随机性 {{value}}" + }, + "title": "模型设置", + "topP": { + "desc": "与随机性类似,但不要和随机性一起更改", + "title": "核采样" + } + }, + "settingPlugin": { + "add": "添加", + "addTooltip": "添加自定义插件", + "clearDeprecated": "移除无效插件", + "config": "{{id}} 插件配置", + "settings": "配置插件市场", + "title": "插件列表" + }, + "settingSystem": { + "accessCode": { + "desc": "管理员已开启加密访问", + "placeholder": "请输入访问密码", + "title": "访问密码" + }, + "title": "系统设置" + }, + "settingTTS": { + "openai": { + "sttModel": "OpenAI 语音识别模型", + "ttsModel": "OpenAI 语音合成模型" + }, + "showAllLocaleVoice": { + "desc": "关闭则只显示当前语种的声源", + "title": "显示所有语种声源" + }, + "stt": "语音识别设置", + "sttAutoStop": { + "desc": "关闭后,语音识别将不会自动结束,需要手动点击结束按钮", + "title": "自动结束语音识别" + }, + "sttLocale": { + "desc": "语音输入的语种,此选项可提高语音识别准确率", + "title": "语音识别语种" + }, + "sttService": { + "desc": "其中 broswer 为浏览器原生的语音识别服务", + "title": "语音识别服务" + }, + "title": "语音服务", + "tts": "语音合成设置", + "ttsService": { + "desc": "如使用 OpenAI 语音合成服务,需要保证 OpenAI 模型服务已开启", + "title": "语音合成服务" + }, + "voice": { + "desc": "为当前助手挑选一个声音,不同 TTS 服务支持的声源不同", + "preview": "试听声源", + "title": "语音合成声源" + } + }, + "settingTheme": { + "avatar": { + "title": "头像" + }, + "fontSize": { + "desc": "聊天内容的字体大小", + "title": "字体大小" + }, + "lang": { + "autoMode": "跟随系统", + "title": "语言" + }, + "neutralColor": { + "desc": "不同色彩倾向的灰阶自定义", + "title": "中性色" + }, + "primaryColor": { + "desc": "自定义主题色", + "title": "主题色" + }, + "themeMode": { + "auto": "自动", + "dark": "深色", + "light": "浅色", + "title": "主题" + }, + "title": "主题设置" + }, + "submitAgentModal": { + "button": "提交助手", + "identifier": "identifier 助手标识符", + "metaMiss": "请补全助手信息后提交,需要包含名称、描述和标签", + "placeholder": "请输入助手的标识符,需要是唯一的,比如 web-development", + "tooltips": "分享到助手市场" + }, + "tab": { + "agent": "默认助手", + "common": "通用设置", + "llm": "语言模型", + "tts": "语音服务" + } +} diff --git a/locales/zh_CN/welcome.json b/locales/zh_CN/welcome.json new file mode 100644 index 0000000000000..8c935e200162b --- /dev/null +++ b/locales/zh_CN/welcome.json @@ -0,0 +1,14 @@ +{ + "button": { + "import": "导入配置", + "start": "立即开始" + }, + "header": "欢迎使用", + "pickAgent": "或从下列助手模板选择", + "skip": "跳过创建", + "slogan": { + "desc1": "开启大脑集群,激发思维火花。你的智能助理,一直都在。", + "desc2": "创建你的第一个助手,让我们开始吧~", + "title": "给自己一个更聪明的大脑" + } +} diff --git a/locales/zh_TW/chat.json b/locales/zh_TW/chat.json new file mode 100644 index 0000000000000..c78e1c0e7aef7 --- /dev/null +++ b/locales/zh_TW/chat.json @@ -0,0 +1,80 @@ +{ + "agentDefaultMessage": "妳好,我是 **{{name}}**,妳可以立即與我開始對話,也可以前往 [助手設定](/chat/settings#session={{id}}) 完善我的資訊。", + "agentDefaultMessageWithSystemRole": "妳好,我是 **{{name}}**,{{systemRole}},讓我們開始對話吧!", + "backToBottom": "查看最新訊息", + "clearCurrentMessages": "清空當前會話訊息", + "confirmClearCurrentMessages": "即將清空當前會話訊息,清空後將無法找回,請確認妳的操作", + "confirmRemoveSessionItemAlert": "即將刪除該助手,刪除後該將無法找回,請確認妳的操作", + "defaultAgent": "自定義助手", + "defaultSession": "自定義助手", + "historyRange": "歷史範圍", + "inbox": { + "defaultMessage": "妳好,我是妳的智能助手,妳可以問我任何問題,我會盡力回答妳。如果需要獲得更加專業或定制的助手,可以點擊`+`創建自定義助手", + "desc": "開啟大腦集群,激發思維火花。妳的智能助理,在這裡與妳交流一切", + "title": "隨便聊聊" + }, + "newAgent": "新建助手", + "noDescription": "暫無描述", + "pin": "置頂", + "pinOff": "取消置頂", + "regenerate": "重新生成", + "roleAndArchive": "角色與記錄", + "searchAgentPlaceholder": "搜索助手和對話...", + "send": "發送", + "sendPlaceholder": "輸入聊天內容...", + "sessionList": "助手列表", + "shareModal": { + "download": "下載截圖", + "imageType": "圖片格式", + "screenshot": "截圖", + "settings": "導出設定", + "shareToShareGPT": "生成 ShareGPT 分享鏈接", + "withBackground": "包含背景圖片", + "withFooter": "包含頁腳", + "withPluginInfo": "包含插件信息", + "withSystemRole": "包含助手角色設定" + }, + "stop": "停止", + "stt": { + "action": "語音輸入", + "loading": "辨識中...", + "prettifying": "美化中..." + }, + "temp": "臨時", + "tokenDetail": "角色設定: {{systemRoleToken}} · 歷史訊息: {{chatsToken}}", + "tokenTag": { + "overload": "超過限制", + "remained": "剩餘", + "used": "使用" + }, + "topic": { + "confirmRemoveTopic": "即將刪除該話題,刪除後將不可恢復,請謹慎操作。", + "defaultTitle": "默認話題", + "saveCurrentMessages": "將當前會話保存為話題", + "searchPlaceholder": "搜索話題...", + "deleteAll": "刪除所有話題", + "deleteUnstarred": "刪除未收藏話題", + "title": "話題列表", + "confirmRemoveAll": "即將刪除全部話題,刪除後將無法恢復,請謹慎操作。", + "confirmRemoveUnstarred": "即將刪除未收藏話題,刪除後將無法恢復,請謹慎操作。", + "removeAll": "刪除全部話題", + "removeUnstarred": "刪除未收藏話題", + "openNewTopic": "開啟新話題" + }, + "translate": { + "clear": "刪除翻譯", + "action": "翻譯" + }, + "translateTo": "翻譯", + "tts": { + "action": "語音朗讀", + "clear": "清除語音" + }, + "updateAgent": "更新助理資訊", + "upload": { + "actionTooltip": "上傳圖片", + "dragDesc": "拖曳檔案到這裡,支援上傳多張圖片。按住 Shift 直接發送圖片", + "dragTitle": "上傳圖片" + }, + "warp": "換行" +} diff --git a/locales/zh_TW/common.json b/locales/zh_TW/common.json new file mode 100644 index 0000000000000..b41f8f3fa9f47 --- /dev/null +++ b/locales/zh_TW/common.json @@ -0,0 +1,71 @@ +{ + "about": "關於", + "advanceSettings": "進階設定", + "agentMaxToken": "最大對話長度", + "agentModel": "模型", + "agentProfile": "助手資訊", + "appInitializing": "ChatGPT Power 正在啟動,請稍候...", + "archive": "歸檔", + "autoGenerate": "自動生成", + "autoGenerateTooltip": "基於提示詞自動生成助手描述", + "cancel": "取消", + "changelog": "更新日誌", + "close": "關閉", + "confirmRemoveSessionItemAlert": "即將刪除該助手,刪除後將無法找回,請確認您的操作", + "copy": "複製", + "copySuccess": "複製成功", + "defaultAgent": "自定義助手", + "defaultSession": "自定義助手", + "delete": "刪除", + "edit": "編輯", + "export": "匯出設定", + "exportType": { + "agent": "匯出助手設定", + "agentWithMessage": "匯出助手和訊息", + "all": "匯出全域設定和所有助手資料", + "allAgent": "匯出所有助手設定", + "allAgentWithMessage": "匯出所有助手和訊息", + "globalSetting": "匯出全域設定" + }, + "feedback": "回饋與建議", + "historyRange": "歷史範圍", + "import": "匯入設定", + "lang": { + "en": "英語", + "en-US": "英語", + "es-ES": "西班牙語", + "ja-JP": "日語", + "ko-KR": "韓語", + "ru-RU": "俄語", + "zh": "簡體中文", + "zh-CN": "簡體中文", + "zh-TW": "繁體中文" + }, + "layoutInitializing": "正在載入佈局...", + "noDescription": "暫無描述", + "ok": "確定", + "password": "密碼", + "pin": "置頂", + "pinOff": "取消置頂", + "regenerate": "重新生成", + "rename": "重命名", + "reset": "重置", + "retry": "重試", + "send": "發送", + "sessionList": "助手列表", + "setting": "設定", + "share": "分享", + "stop": "停止", + "tab": { + "chat": "聊天", + "market": "探索", + "setting": "設定" + }, + "temp": "臨時", + "updateAgent": "更新助理資訊", + "upgradeVersion": { + "action": "立即升級", + "hasNew": "有可用更新", + "newVersion": "有新版本可用:{{version}}" + } +} diff --git a/locales/zh_TW/empty.json b/locales/zh_TW/empty.json new file mode 100644 index 0000000000000..3467191418e9d --- /dev/null +++ b/locales/zh_TW/empty.json @@ -0,0 +1,6 @@ +{ + "topic": { + "desc": "點選左側的按鈕,將目前的對話存成歷史主題,並開始新的對話", + "title": "主題清單" + } +} diff --git a/locales/zh_TW/error.json b/locales/zh_TW/error.json new file mode 100644 index 0000000000000..88ea5d8ef0626 --- /dev/null +++ b/locales/zh_TW/error.json @@ -0,0 +1,51 @@ +{ + "pluginSettings": { + "desc": "完成以下設定後,即可開始使用此外掛", + "title": "{{name}} 插件設定" + }, + "response": { + "400": "抱歉,伺服器無法理解您的請求。請確認您的請求參數是否正確。", + "401": "抱歉,伺服器已拒絕您的請求,可能是因為權限不足或身分驗證無效。", + "403": "抱歉,伺服器已拒絕您的請求。您沒有權限存取此內容。", + "404": "抱歉,伺服器無法找到您請求的頁面或資源。請確認您的 URL 是否正確。", + "405": "抱歉,伺服器不支援您正在使用的請求方法。請確認您的請求方法是否正確。", + "429": "抱歉,您的請求太頻繁,伺服器有點累了。請稍後再試。", + "500": "抱歉,伺服器似乎遇到一些困難,暫時無法完成您的請求。請稍後再試。", + "502": "抱歉,伺服器似乎迷失了方向,暫時無法提供服務。請稍後再試。", + "503": "抱歉,伺服器目前無法處理您的請求,可能是因為過載或正在進行維護。請稍後再試。", + "504": "抱歉,伺服器沒有收到上游伺服器的回應。請稍後再試。", + "InvalidAccessCode": "密碼不正確或為空。請輸入正確的存取密碼,或新增自定義的 OpenAI API Key。", + "OpenAIBizError": "請求 OpenAI 服務出錯。請根據以下資訊進行排查或重試。", + "PluginMarketIndexNotFound": "抱歉,伺服器找不到外掛索引。請檢查索引地址是否正確", + "PluginMarketIndexInvalid": "抱歉,外掛索引驗證失敗。請檢查索引檔案格式是否正確", + "PluginMetaNotFound": "抱歉,索引中找不到該外掛。請檢查索引中的外掛設定資訊", + "PluginMetaInvalid": "抱歉,外掛的元資料驗證失敗。請檢查外掛元資料格式是否正確", + "PluginManifestNotFound": "抱歉,伺服器找不到該外掛的描述檔案 (manifest.json)。請檢查外掛描述檔案地址是否正確", + "PluginManifestInvalid": "抱歉,外掛的描述檔案驗證失敗。請檢查描述檔案格式是否正確", + "PluginApiNotFound": "抱歉,外掛描述檔案中不存在該 API。請檢查您的請求方法與外掛清單 API 是否相符", + "PluginApiParamsError": "抱歉,該外掛請求的輸入參數驗證失敗。請檢查輸入參數與 API 描述資訊是否相符", + "PluginSettingsInvalid": "該外掛需要正確設定後才可以使用。請檢查您的設定是否正確", + "PluginServerError": "外掛伺服器請求回傳錯誤。請根據下面的錯誤資訊檢查您的外掛描述檔案、外掛設定或伺服器實作", + "NoAPIKey": "OpenAI API 金鑰為空,請添加自訂 OpenAI API 金鑰" + }, + "stt": { + "responseError": "服務請求失敗,請檢查配置或重試" + }, + "tts": { + "responseError": "服務請求失敗,請檢查配置或重試" + }, + "unlock": { + "apikey": { + "title": "使用自定義 API Key", + "description": "輸入你的 OpenAI API Key 即可開始會話。應用程式不會記錄你的 API Key", + "addProxyUrl": "添加 OpenAI 代理地址(可選)" + }, + "confirm": "確認並重試", + "password": { + "description": "管理員已啟用應用程式加密,輸入應用程式密碼後即可解鎖應用程式。密碼只需填寫一次。", + "title": "輸入密碼解鎖應用程式", + "placeholder": "請輸入密碼" + }, + "closeMessage": "關閉提示" + } +} diff --git a/locales/zh_TW/market.json b/locales/zh_TW/market.json new file mode 100644 index 0000000000000..f7933b418c6c6 --- /dev/null +++ b/locales/zh_TW/market.json @@ -0,0 +1,30 @@ +{ + "addAgent": "新增助理", + "guide": { + "func1": { + "desc1": "在會話視窗中通過右上角設置進入你想提交助手的設置頁面;", + "desc2": "點擊右上角提交到助手市場按鈕。", + "tag": "方法一", + "title": "通過 ChatGPT Power 提交" + }, + "func2": { + "button": "前往 Github 助手倉庫", + "desc": "如果您想將助手添加到索引中,請使用 agent-template.json 或 agent-template-full.json 在 plugins 目錄中創建一個條目,編寫簡短的描述並適當標記,然後創建一個拉取請求。", + "tag": "方法二", + "title": "通過 Github 提交" + } + }, + "search": { + "placeholder": "搜尋助理名稱、描述或關鍵字..." + }, + "sidebar": { + "comment": "評論", + "prompt": "提示", + "title": "助理詳細資訊" + }, + "submitAgent": "上傳助理", + "title": { + "recentSubmits": "最新上傳", + "allAgents": "所有助理" + } +} diff --git a/locales/zh_TW/plugin.json b/locales/zh_TW/plugin.json new file mode 100644 index 0000000000000..448d193f5182a --- /dev/null +++ b/locales/zh_TW/plugin.json @@ -0,0 +1,129 @@ +{ + "debug": { + "arguments": "參數", + "function_call": "函式呼叫", + "response": "回應", + "off": "關閉偵錯", + "on": "查看插件呼叫資訊" + }, + "dev": { + "confirmDeleteDevPlugin": "您確定要刪除此本機外掛嗎?一旦刪除,將無法復原。", + "deleteSuccess": "外掛已成功刪除", + "manifest": { + "identifier": { + "desc": "外掛的唯一識別碼", + "label": "識別碼" + }, + "mode": { + "local": "視覺設定", + "local-tooltip": "目前不支援視覺設定", + "url": "線上連結" + }, + "name": { + "desc": "外掛的名稱", + "label": "名稱", + "placeholder": "搜尋引擎" + } + }, + "meta": { + "author": { + "desc": "外掛的作者", + "label": "作者" + }, + "avatar": { + "desc": "外掛的圖示,可以是 Emoji 或網址", + "label": "圖示" + }, + "description": { + "desc": "外掛的描述", + "label": "描述", + "placeholder": "從搜尋引擎取得資訊" + }, + "formFieldRequired": "此欄位必填", + "homepage": { + "desc": "外掛的官方首頁", + "label": "首頁" + }, + "identifier": { + "desc": "外掛的唯一識別碼,只支援英數字元、連字號 -,以及底線 _", + "errorDuplicate": "此識別碼已被其他外掛使用,請更改識別碼", + "label": "識別碼", + "pattenErrorMessage": "只允許英數字元、連字號 -,以及底線 _" + }, + "manifest": { + "desc": "ChatGPT Power 會使用此連結安裝外掛", + "invalid": "輸入的 manifest 連結不正確或不符合標準", + "label": "外掛 Manifest 網址", + "urlError": "請輸入有效的網址", + "jsonInvalid": "manifest 不正確,驗證結果:\n\n {{error}}", + "preview": "預覽 Manifest", + "refresh": "重新載入", + "requestError": "連結請求失敗,請確認網址是否正確且允許跨域存取" + }, + "title": { + "desc": "外掛的名稱", + "label": "名稱", + "placeholder": "搜尋引擎" + } + }, + "metaConfig": "外掛後設資料設定", + "modalDesc": "新增自訂外掛後,可用於外掛開發測試或直接在對話中使用。請參考外掛開發文件以取得更多資訊。", + "preview": { + "card": "外掛顯示預覽", + "desc": "外掛描述預覽", + "title": "外掛名稱預覽" + }, + "save": "儲存", + "saveSuccess": "外掛設定已成功儲存", + "tabs": { + "manifest": "功能描述清單 (Manifest)", + "meta": "外掛後設資料" + }, + "title": "新增自訂外掛", + "update": "更新", + "updateSuccess": "外掛設定已成功更新" + }, + "list": { + "item": { + "local.config": "設定", + "local.title": "本機", + "deprecated.title": "已刪除" + } + }, + "loading": { + "plugin": "外掛執行中...", + "content": "呼叫插件中..." + }, + "pluginList": "外掛清單", + "plugins": { + "realtimeWeather": "即時天氣", + "searchEngine": "搜尋引擎", + "undefined": "正在偵測外掛...", + "websiteCrawler": "網站爬蟲", + "unknown": "外掛偵測進行中..." + }, + "realtimeWeather": { + "data": { + "date": "日期", + "daytemp_float": "日間溫度", + "dayweather": "日間天氣", + "daywind": "日間風向", + "nighttemp_float": "夜間溫度", + "nightweather": "夜間天氣", + "nightwind": "夜間風向", + "week": "週" + }, + "title": "未來 7 天的天氣資料 ({{city}})", + "updateAt": "最後更新時間" + }, + "responseData": "回應資料", + "setting": "插件設置", + "settings": { + "indexUrl": { + "title": "外掛市集索引", + "tooltip": "目前不支援編輯" + }, + "modalDesc": "設定外掛市集的網址後,您可以使用自訂的外掛市集", + "title": "設定外掛市集" + } +} diff --git a/locales/zh_TW/setting.json b/locales/zh_TW/setting.json new file mode 100644 index 0000000000000..8cc8e21fd2648 --- /dev/null +++ b/locales/zh_TW/setting.json @@ -0,0 +1,297 @@ +{ + "danger": { + "clear": { + "action": "立即清除", + "confirm": "確定要清除所有聊天資料嗎?", + "desc": "清除所有對話資料", + "success": "已清除所有對話訊息", + "title": "清除所有對話訊息" + }, + "reset": { + "action": "立即重設", + "confirm": "確定要重設所有設定嗎?", + "currentVersion": "目前版本", + "desc": "將所有設定重設為預設值", + "title": "重設所有設定" + } + }, + "header": { + "global": "全域設定", + "session": "對話設定", + "sessionWithName": "對話設定 · {{name}}" + }, + "llm": { + "AzureOpenAI": { + "endpoint": { + "desc": "在 Azure 網站檢查資源時,可以在「金鑰和端點」部分找到此值。", + "placeholder": "https://docs-test-001.openai.azure.com", + "title": "Azure API 網址" + }, + "models": { + "desc": "支援的模型", + "title": "模型列表" + }, + "title": "Azure OpenAI 設定", + "token": { + "desc": "在 Azure 網站檢查資源時,可以在「金鑰和端點」部分找到此值。可以使用 KEY1 或 KEY2", + "placeholder": "Azure API 金鑰", + "title": "API 金鑰" + } + }, + "OpenAI": { + "azureApiVersion": { + "desc": "Azure API 版本,遵循 YYYY-MM-DD 格式,查詢[最新版本](https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions)", + "fetch": "取得列表", + "title": "Azure API 版本" + }, + "check": { + "button": "檢查", + "desc": "檢查 API 金鑰和代理伺服器網址是否正確填寫。", + "pass": "連線成功", + "title": "檢查連線狀態" + }, + "endpoint": { + "desc": "除了預設網址外,必須包含 http(s)://", + "placeholder": "https://api.openai.com/v1", + "title": "API 代理網址" + }, + "models": { + "count": "總共支援 {{count}} 個模型", + "desc": "支援的模型", + "fetch": "取得模型列表", + "notSupport": "Azure OpenAI 目前不支援檢視模型列表", + "notSupportTip": "請確保部署名稱與模型名稱相符", + "refetch": "重新取得模型列表", + "title": "模型列表" + }, + "title": "OpenAI 設定", + "token": { + "desc": "使用自己的 OpenAI 金鑰", + "placeholder": "OpenAI API 金鑰", + "title": "API 金鑰" + }, + "useAzure": { + "desc": "使用 Azure 提供的 OpenAI 服務", + "fetch": "取得列表", + "title": "Azure OpenAI", + "serverConfig": "管理員已在伺服器端啟用 Azure OpenAI,禁止切換" + }, + "customModelName": { + "desc": "增加自訂模型,多個模型使用逗號(,) 隔開", + "placeholder": "model1,model2,model3", + "title": "自訂模型名稱" + } + }, + "waitingForMore": "<1>計劃支援其他模型,敬請期待 ✨" + }, + "settingAgent": { + "avatar": { + "title": "頭像" + }, + "backgroundColor": { + "title": "背景色" + }, + "description": { + "placeholder": "請輸入助理描述", + "title": "助理描述" + }, + "name": { + "placeholder": "請輸入助理名稱", + "title": "名稱" + }, + "prompt": { + "placeholder": "請輸入角色提示", + "title": "角色提示" + }, + "tag": { + "placeholder": "請輸入標籤", + "title": "標籤" + }, + "title": "助理資訊" + }, + "settingChat": { + "chatStyleType": { + "title": "聊天視窗樣式", + "type": { + "chat": "對話模式", + "docs": "文件模式" + } + }, + "compressThreshold": { + "desc": "當未壓縮的歷史訊息超過此值時,將進行壓縮", + "title": "歷史訊息長度壓縮閾值" + }, + "enableCompressThreshold": { + "title": "是否啟用歷史訊息長度壓縮閾值" + }, + "enableHistoryCount": { + "alias": "不限制", + "limited": "只包含 {{number}} 條對話訊息", + "title": "限制歷史訊息數", + "unlimited": "不限歷史訊息數" + }, + "historyCount": { + "desc": "每次請求攜帶的歷史訊息數", + "title": "附帶歷史訊息數" + }, + "inputTemplate": { + "desc": "使用者最新的一條訊息會填充到此範本", + "placeholder": "前置處理範本 {{text}} 將替換為即時輸入資訊", + "title": "使用者輸入前置處理" + }, + "title": "聊天設定", + "autoCreateTopicThreshold": { + "desc": "當前訊息數超過設定該值後,將自動創建話題", + "title": "訊息閾值" + }, + "enableAutoCreateTopic": { + "desc": "會話過程中是否自動創建話題,僅在臨時話題中生效", + "title": "自動創建話題" + } + }, + "settingModel": { + "enableMaxTokens": { + "title": "啟用單次回覆限制" + }, + "frequencyPenalty": { + "desc": "值越大,越有可能降低重複字詞", + "title": "頻率懲罰度" + }, + "maxTokens": { + "desc": "單次互動所用的最大 Token 數", + "title": "單次回覆限制" + }, + "model": { + "desc": "ChatGPT 模型", + "list": { + "gpt-3.5-turbo": "GPT 3.5", + "gpt-3.5-turbo-16k": "GPT 3.5 (16K)", + "gpt-4": "GPT 4", + "gpt-4-32k": "GPT 4 (32K)" + }, + "title": "模型" + }, + "presencePenalty": { + "desc": "值越大,越有可能延伸到新話題", + "title": "話題新鮮度" + }, + "temperature": { + "desc": "值越大,回覆越隨機", + "title": "隨機性", + "titleWithValue": "隨機性 {{value}}" + }, + "title": "模型設定", + "topP": { + "desc": "與隨機性類似,但不要和隨機性一起更改", + "title": "核心抽樣參數" + } + }, + "settingOpenAI": { + "endpoint": { + "desc": "除了預設網址外,必須包含 http(s)://", + "placeholder": "https://api.openai.com/v1", + "title": "API 代理網址" + }, + "title": "OpenAI 設定", + "token": { + "desc": "使用自己的 OpenAI 金鑰", + "placeholder": "OpenAI API 金鑰", + "title": "API 金鑰" + } + }, + "settingPlugin": { + "add": "新增", + "addTooltip": "新增自訂外掛", + "clearDeprecated": "移除過時外掛", + "config": "{{id}} 外掛設定", + "settings": "設定外掛市場", + "title": "外掛列表" + }, + "settingSystem": { + "accessCode": { + "desc": "管理員已啟用加密存取", + "placeholder": "請輸入存取密碼", + "title": "存取密碼" + }, + "title": "系統設定" + }, + "settingTTS": { + "showAllLocaleVoice": { + "desc": "關閉則只顯示當前語種的聲源", + "title": "顯示所有語種聲源" + }, + "sttService": { + "desc": "其中 broswer 為瀏覽器原生的語音識別服務", + "title": "語音識別服務" + }, + "title": "語音服務", + "ttsService": { + "desc": "如使用 OpenAI 語音合成服務,需要保證 OpenAI 模型服務已開啟", + "title": "語音合成服務" + }, + "voice": { + "title": "語音合成聲源", + "desc": "為當前助手挑選一個聲音,不同 TTS 服務支持的聲源不同", + "preview": "預覽" + }, + "openai": { + "sttModel": "OpenAI 語音識別模型", + "ttsModel": "OpenAI 語音合成模型" + }, + "stt": "語音識別設定", + "sttLocale": { + "desc": "語音輸入的語言,此選項可提高語音識別準確率", + "title": "語音識別語言" + }, + "sttPersisted": { + "desc": "開啟後,語音識別將不會自動結束,需要手動點擊結束按鈕", + "title": "手動結束語音識別" + }, + "tts": "語音合成設定", + "sttAutoStop": { + "desc": "關閉後,語音識別將不會自動結束,需要手動點擊結束按鈕", + "title": "自動結束語音識別" + } + }, + "settingTheme": { + "avatar": { + "title": "頭像" + }, + "fontSize": { + "desc": "聊天內容的字型大小", + "title": "字型大小" + }, + "lang": { + "title": "語言設定", + "autoMode": "跟隨系統" + }, + "neutralColor": { + "desc": "不同色彩傾向的灰階自訂", + "title": "中性色" + }, + "primaryColor": { + "desc": "自訂主題顏色", + "title": "主題顏色" + }, + "themeMode": { + "auto": "自動", + "dark": "深色", + "light": "淺色", + "title": "主題" + }, + "title": "主題設定" + }, + "submitAgentModal": { + "tooltips": "分享到助手市場", + "button": "提交助手", + "identifier": "助手識別符", + "metaMiss": "請補全助手資訊後提交,需要包含名稱、描述和標籤", + "placeholder": "請輸入助手的識別符,需要是唯一的,例如 web-development" + }, + "tab": { + "agent": "預設助理", + "common": "通用設定", + "llm": "語言模型", + "tts": "語音服務" + } +} diff --git a/locales/zh_TW/welcome.json b/locales/zh_TW/welcome.json new file mode 100644 index 0000000000000..edc6e1385eda4 --- /dev/null +++ b/locales/zh_TW/welcome.json @@ -0,0 +1,14 @@ +{ + "button": { + "import": "匯入設定檔", + "start": "馬上開始" + }, + "header": "歡迎", + "pickAgent": "或從以下助理範本中選擇", + "skip": "跳過建立步驟", + "slogan": { + "desc1": "釋放你腦力的潛能,點燃你的創意火花。你的智慧型助理,隨時待命。", + "desc2": "建立你的第一個助理,讓我們一起開始吧~", + "title": "為自己賦予一個更聰明的大腦" + } +} diff --git a/next.config.mjs b/next.config.mjs new file mode 100644 index 0000000000000..aace977641366 --- /dev/null +++ b/next.config.mjs @@ -0,0 +1,76 @@ +import nextPWA from '@ducanh2912/next-pwa'; +import analyzer from '@next/bundle-analyzer'; + +const isProd = process.env.NODE_ENV === 'production'; +const buildWithDocker = process.env.DOCKER === 'true'; + +const withBundleAnalyzer = analyzer({ + enabled: process.env.ANALYZE === 'true', +}); + +const withPWA = nextPWA({ + dest: 'public', + register: true, + workboxOptions: { + skipWaiting: true, + }, +}); + +/** @type {import('next').NextConfig} */ +const nextConfig = { + compress: isProd, + env: { + AGENTS_INDEX_URL: process.env.AGENTS_INDEX_URL ?? '', + PLUGINS_INDEX_URL: process.env.PLUGINS_INDEX_URL ?? '', + }, + experimental: { + forceSwcTransforms: true, + optimizePackageImports: [ + 'modern-screenshot', + 'emoji-mart', + '@emoji-mart/react', + '@emoji-mart/data', + '@icons-pack/react-simple-icons', + 'gpt-tokenizer', + 'chroma-js', + ], + webVitalsAttribution: ['CLS', 'LCP'], + }, + images: { + remotePatterns: [ + { + hostname: 'registry.npmmirror.com', + pathname: '/@lobehub/**', + port: '', + protocol: 'https', + }, + ], + unoptimized: !isProd, + }, + output: buildWithDocker ? 'standalone' : undefined, + + reactStrictMode: true, + + transpilePackages: ['antd-style', '@lobehub/ui', '@lobehub/tts'], + + webpack(config) { + config.experiments = { + asyncWebAssembly: true, + layers: true, + }; + + // to fix shikiji compile error + // refs: https://github.com/antfu/shikiji/issues/23 + config.module.rules.push({ + test: /\.m?js$/, + type: 'javascript/auto', + resolve: { + fullySpecified: false, + }, + }); + + return config; + }, +}; + +export default isProd ? withBundleAnalyzer(withPWA(nextConfig)) : nextConfig; diff --git a/package.json b/package.json new file mode 100644 index 0000000000000..2840130077cad --- /dev/null +++ b/package.json @@ -0,0 +1,171 @@ +{ + "name": "@lobehub/chat", + "version": "0.105.0", + "description": "An open-source, extensible (Function Calling), high-performance chatbot framework. It supports one-click free deployment of your private ChatGPT/LLM web application", + "keywords": [ + "chatbot", + "ChatGPT", + "LobeHub", + "typescript", + "Vercel AI SDK", + "Next.js", + "OpenAI" + ], + "homepage": "https://github.com/lobehub/lobe-chat", + "bugs": { + "url": "https://github.com/lobehub/lobe-chat/issues/new/choose" + }, + "repository": { + "type": "git", + "url": "https://github.com/lobehub/lobe-chat.git" + }, + "license": "MIT", + "author": "LobeHub ", + "sideEffects": false, + "scripts": { + "build": "next build", + "build:analyze": "ANALYZE=true next build", + "build:docker": "DOCKER=true next build", + "dev": "next dev -p 3010", + "i18n": "npm run workflow:i18n && lobe-i18n", + "lint": "npm run lint:ts && npm run lint:style && npm run type-check && npm run lint:circular", + "lint:circular": "dpdm src/**/*.ts --warning false --tree false --exit-code circular:1 -T true", + "lint:md": "remark . --quiet --frail --output", + "lint:style": "stylelint \"{src,tests}/**/*.{js,jsx,ts,tsx}\" --fix", + "lint:ts": "eslint \"{src,tests}/**/*.{js,jsx,ts,tsx}\" --fix", + "prepare": "husky install", + "prettier": "prettier -c --write \"**/**\"", + "pull": "git pull", + "release": "semantic-release", + "start": "next start", + "stylelint": "stylelint \"src/**/*.{js,jsx,ts,tsx}\" --fix", + "test": "vitest --passWithNoTests", + "test:coverage": "vitest run --coverage --passWithNoTests", + "test:update": "vitest -u", + "type-check": "tsc --noEmit", + "workflow:i18n": "ts-node --project ./tsconfig.json scripts/i18nWorkflow/index.ts", + "workflow:readme": "bun scripts/readmeWorkflow/index.ts" + }, + "lint-staged": { + "*.md": [ + "remark --quiet --output --", + "prettier --write --no-error-on-unmatched-pattern" + ], + "*.json": [ + "prettier --write --no-error-on-unmatched-pattern" + ], + "*.{js,jsx}": [ + "prettier --write", + "stylelint --fix", + "eslint --fix" + ], + "*.{ts,tsx}": [ + "prettier --parser=typescript --write", + "stylelint --fix", + "eslint --fix" + ] + }, + "dependencies": { + "@ant-design/icons": "^5", + "@icons-pack/react-simple-icons": "^9", + "@lobehub/chat-plugin-sdk": "latest", + "@lobehub/chat-plugins-gateway": "latest", + "@lobehub/tts": "latest", + "@lobehub/ui": "latest", + "@vercel/analytics": "^1", + "ahooks": "^3", + "ai": "^2.2.22", + "antd": "^5", + "antd-style": "^3", + "brotli-wasm": "^1", + "chroma-js": "^2", + "copy-to-clipboard": "^3", + "dayjs": "^1", + "dexie": "^3", + "fast-deep-equal": "^3", + "gpt-tokenizer": "^2", + "i18next": "^23", + "i18next-browser-languagedetector": "^7", + "i18next-resources-for-ts": "^1", + "i18next-resources-to-backend": "^1", + "idb-keyval": "^6", + "immer": "^10", + "lodash-es": "^4", + "lucide-react": "latest", + "modern-screenshot": "^4", + "nanoid": "^5", + "next": "^14.0.2", + "openai": "^4.17.3", + "polished": "^4", + "posthog-js": "^1", + "query-string": "^8", + "react": "^18", + "react-dom": "^18", + "react-hotkeys-hook": "^4", + "react-i18next": "^13", + "react-intersection-observer": "^9", + "react-layout-kit": "^1", + "react-lazy-load": "^4", + "react-spring-lightbox": "^1", + "remark": "^14", + "remark-gfm": "^3", + "remark-html": "^15", + "semver": "^7", + "sharp": "^0.32.6", + "swr": "^2", + "systemjs": "^6", + "ts-md5": "^1", + "ua-parser-js": "^1", + "url-join": "^5", + "use-merge-value": "^1", + "utility-types": "^3", + "uuid": "^9", + "zod": "^3", + "zustand": "^4.4", + "zustand-utils": "^1" + }, + "devDependencies": { + "@commitlint/cli": "^18", + "@ducanh2912/next-pwa": "^9.7.2", + "@lobehub/i18n-cli": "latest", + "@lobehub/lint": "latest", + "@next/bundle-analyzer": "^14.0.3", + "@next/eslint-plugin-next": "^14.0.3", + "@testing-library/jest-dom": "^6", + "@testing-library/react": "^14", + "@types/chroma-js": "^2", + "@types/lodash": "^4", + "@types/lodash-es": "^4", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "@types/semver": "^7", + "@types/systemjs": "^6", + "@types/ua-parser-js": "^0.7", + "@types/uuid": "^9", + "@umijs/lint": "^4", + "@vitest/coverage-v8": "latest", + "commitlint": "^18", + "consola": "^3", + "dpdm": "^3", + "eslint": "^8", + "fake-indexeddb": "^5", + "husky": "^8", + "jsdom": "^22", + "lint-staged": "^15", + "lodash": "^4", + "markdown-table": "^3", + "node-fetch": "^3", + "prettier": "^3", + "remark-cli": "^11", + "semantic-release": "^21", + "stylelint": "^15", + "ts-node": "^10", + "typescript": "^5", + "vitest": "latest" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + } +} diff --git a/public/icons/icon-192x192.png b/public/icons/icon-192x192.png new file mode 100644 index 0000000000000..cc29879cf45b0 Binary files /dev/null and b/public/icons/icon-192x192.png differ diff --git a/public/icons/icon-512x512.png b/public/icons/icon-512x512.png new file mode 100644 index 0000000000000..3794e502aac65 Binary files /dev/null and b/public/icons/icon-512x512.png differ diff --git a/public/icons/maskable-icon-192x192.png b/public/icons/maskable-icon-192x192.png new file mode 100644 index 0000000000000..8b1a6416bf615 Binary files /dev/null and b/public/icons/maskable-icon-192x192.png differ diff --git a/public/icons/maskable-icon-512x512.png b/public/icons/maskable-icon-512x512.png new file mode 100644 index 0000000000000..47ae021586d94 Binary files /dev/null and b/public/icons/maskable-icon-512x512.png differ diff --git a/public/images/banner_market_modal.webp b/public/images/banner_market_modal.webp new file mode 100644 index 0000000000000..f7174b6824f1c Binary files /dev/null and b/public/images/banner_market_modal.webp differ diff --git a/public/images/chatmode_chat_dark.webp b/public/images/chatmode_chat_dark.webp new file mode 100644 index 0000000000000..394f095ab8d74 Binary files /dev/null and b/public/images/chatmode_chat_dark.webp differ diff --git a/public/images/chatmode_chat_light.webp b/public/images/chatmode_chat_light.webp new file mode 100644 index 0000000000000..3e4726edbbd2e Binary files /dev/null and b/public/images/chatmode_chat_light.webp differ diff --git a/public/images/chatmode_docs_dark.webp b/public/images/chatmode_docs_dark.webp new file mode 100644 index 0000000000000..301f97db47fe1 Binary files /dev/null and b/public/images/chatmode_docs_dark.webp differ diff --git a/public/images/chatmode_docs_light.webp b/public/images/chatmode_docs_light.webp new file mode 100644 index 0000000000000..be67b3e606d1f Binary files /dev/null and b/public/images/chatmode_docs_light.webp differ diff --git a/public/images/empty_topic_dark.webp b/public/images/empty_topic_dark.webp new file mode 100644 index 0000000000000..064fa1304539e Binary files /dev/null and b/public/images/empty_topic_dark.webp differ diff --git a/public/images/empty_topic_light.webp b/public/images/empty_topic_light.webp new file mode 100644 index 0000000000000..846c64dfd0d05 Binary files /dev/null and b/public/images/empty_topic_light.webp differ diff --git a/public/images/screenshot_background.webp b/public/images/screenshot_background.webp new file mode 100644 index 0000000000000..97b0b82825477 Binary files /dev/null and b/public/images/screenshot_background.webp differ diff --git a/public/images/theme_auto.webp b/public/images/theme_auto.webp new file mode 100644 index 0000000000000..4361a797a9793 Binary files /dev/null and b/public/images/theme_auto.webp differ diff --git a/public/images/theme_dark.webp b/public/images/theme_dark.webp new file mode 100644 index 0000000000000..c02dd0b5625c7 Binary files /dev/null and b/public/images/theme_dark.webp differ diff --git a/public/images/theme_light.webp b/public/images/theme_light.webp new file mode 100644 index 0000000000000..054518566feb6 Binary files /dev/null and b/public/images/theme_light.webp differ diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000000000..c7a3d45da034a --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,61 @@ +{ + "background_color": "#000000", + "description": "An open-source, extensible (Function Calling), high-performance chatbot framework. It supports one-click free deployment of your private ChatGPT/LLM web application", + "display": "standalone", + "icons": [ + { + "src": "/icons/icon-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/maskable-icon-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/icons/icon-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/maskable-icon-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ], + "id": "/", + "name": "ChatGPT Power", + "orientation": "portrait", + "scope": "/", + "screenshots": [ + { + "src": "/screenshots/screenshot-1.png", + "sizes": "750x1334", + "type": "image/png" + }, + { + "src": "/screenshots/screenshot-2.png", + "sizes": "750x1334", + "type": "image/png" + }, + { + "src": "/screenshots/screenshot-3.png", + "sizes": "750x1334", + "type": "image/png" + }, + { + "src": "/screenshots/screenshot-4.png", + "sizes": "750x1334", + "type": "image/png" + } + ], + "short_name": "ChatGPT Power", + "splash_pages": null, + "start_url": ".", + "theme_color": "#000000" +} diff --git a/public/screenshots/screenshot-1.png b/public/screenshots/screenshot-1.png new file mode 100644 index 0000000000000..207e57fb4d723 Binary files /dev/null and b/public/screenshots/screenshot-1.png differ diff --git a/public/screenshots/screenshot-2.png b/public/screenshots/screenshot-2.png new file mode 100644 index 0000000000000..a6f9d3e95ddbd Binary files /dev/null and b/public/screenshots/screenshot-2.png differ diff --git a/public/screenshots/screenshot-3.png b/public/screenshots/screenshot-3.png new file mode 100644 index 0000000000000..170597363382d Binary files /dev/null and b/public/screenshots/screenshot-3.png differ diff --git a/public/screenshots/screenshot-4.png b/public/screenshots/screenshot-4.png new file mode 100644 index 0000000000000..4772d31ec9901 Binary files /dev/null and b/public/screenshots/screenshot-4.png differ diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000000000..99c84e1f74955 --- /dev/null +++ b/renovate.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "automerge": false, + "dependencyDashboard": true, + "ignoreDeps": [], + "labels": ["dependencies"], + "postUpdateOptions": ["yarnDedupeHighest"], + "prConcurrentLimit": 30, + "prHourlyLimit": 0, + "rebaseWhen": "conflicted", + "schedule": "on sunday before 6:00am", + "timezone": "UTC" +} diff --git a/scripts/i18nWorkflow/const.ts b/scripts/i18nWorkflow/const.ts new file mode 100644 index 0000000000000..07c1d266b19a0 --- /dev/null +++ b/scripts/i18nWorkflow/const.ts @@ -0,0 +1,19 @@ +import { readdirSync } from 'node:fs'; +import { resolve } from 'node:path'; + +import i18nConfig from '../../.i18nrc'; + +export const root = resolve(__dirname, '../..'); +export const localesDir = resolve(root, i18nConfig.output); +export const localeDir = (locale: string) => resolve(localesDir, locale); +export const localeDirJsonList = (locale: string) => + readdirSync(localeDir(locale)).filter((name) => name.includes('.json')); +export const srcLocalesDir = resolve(root, './src/locales'); +export const entryLocaleJsonFilepath = (file: string) => + resolve(localesDir, i18nConfig.entryLocale, file); +export const outputLocaleJsonFilepath = (locale: string, file: string) => + resolve(localesDir, locale, file); +export const srcLocalesResources = resolve(root, srcLocalesDir, 'resources'); +export const localesResourcesFilepath = (locale: string) => resolve(srcLocalesResources, locale); + +export { default as i18nConfig } from '../../.i18nrc'; diff --git a/scripts/i18nWorkflow/genDefaultLocale.ts b/scripts/i18nWorkflow/genDefaultLocale.ts new file mode 100644 index 0000000000000..cd441fddc221f --- /dev/null +++ b/scripts/i18nWorkflow/genDefaultLocale.ts @@ -0,0 +1,19 @@ +import { consola } from 'consola'; +import { colors } from 'consola/utils'; + +import { entryLocaleJsonFilepath, i18nConfig, localesResourcesFilepath } from './const'; +import { tagWhite, writeJSON } from './utils'; + +export const genDefaultLocale = () => { + consola.info(`Default locale is ${i18nConfig.entryLocale}...`); + + const resources = require(localesResourcesFilepath(i18nConfig.entryLocale)); + const data = Object.entries(resources.default); + consola.start(`Generate default locale json, found ${data.length} namespaces...`); + + for (const [ns, value] of data) { + const filepath = entryLocaleJsonFilepath(`${ns}.json`); + writeJSON(filepath, value); + consola.success(tagWhite(ns), colors.gray(filepath)); + } +}; diff --git a/scripts/i18nWorkflow/genDiff.ts b/scripts/i18nWorkflow/genDiff.ts new file mode 100644 index 0000000000000..3afe473f30d78 --- /dev/null +++ b/scripts/i18nWorkflow/genDiff.ts @@ -0,0 +1,51 @@ +import { consola } from 'consola'; +import { colors } from 'consola/utils'; +import { unset } from 'lodash'; +import { existsSync } from 'node:fs'; + +import { + entryLocaleJsonFilepath, + i18nConfig, + localesResourcesFilepath, + outputLocaleJsonFilepath, +} from './const'; +import { diff, readJSON, tagWhite, tagYellow, writeJSON } from './utils'; + +export const genDiff = () => { + consola.start(`Diff between Dev/Prod local...`); + + const resources = require(localesResourcesFilepath(i18nConfig.entryLocale)); + const data = Object.entries(resources.default); + + for (const [ns, devJSON] of data) { + const filepath = entryLocaleJsonFilepath(`${ns}.json`); + if (!existsSync(filepath)) continue; + const prodJSON = readJSON(filepath); + + const diffKeys = diff(devJSON, prodJSON); + + if (diffKeys.length === 0) { + consola.success(tagWhite(ns), colors.gray(filepath)); + continue; + } + + consola.warn(tagYellow(ns), diffKeys); + + const clearLocals = []; + + for (const locale of [i18nConfig.entryLocale, ...i18nConfig.outputLocales]) { + const localeFilepath = outputLocaleJsonFilepath(locale, `${ns}.json`); + if (!existsSync(localeFilepath)) continue; + const localeJSON = readJSON(localeFilepath); + + for (const key of diffKeys) { + unset(localeJSON, key); + } + + writeJSON(localeFilepath, localeJSON); + clearLocals.push(locale); + } + consola.info('clear', clearLocals); + consola.success(tagWhite(ns), colors.gray(filepath)); + } +}; diff --git a/scripts/i18nWorkflow/genResources.ts b/scripts/i18nWorkflow/genResources.ts new file mode 100644 index 0000000000000..437b866e2d4b8 --- /dev/null +++ b/scripts/i18nWorkflow/genResources.ts @@ -0,0 +1,26 @@ +import { consola } from 'consola'; +import { colors } from 'consola/utils'; +import { writeFileSync } from 'node:fs'; + +import { i18nConfig, localeDirJsonList, localesResourcesFilepath } from './const'; +import { genResourcesContent, genToc, tagBlue, tagGreen } from './utils'; + +const locales = [i18nConfig.entryLocale, ...i18nConfig.outputLocales]; + +export const genResources = () => { + consola.start(`Generate locale resources and types, found ${locales.length} locales...`); + + for (const locale of locales) { + const files = localeDirJsonList(locale); + const toc = genToc(files, locale); + + const filepath = localesResourcesFilepath(`${locale}.ts`); + writeFileSync(filepath, toc); + consola.success(tagBlue(locale), colors.gray(filepath)); + } + + const indexFilepath = localesResourcesFilepath(`index.ts`); + writeFileSync(indexFilepath, genResourcesContent(locales)); + + consola.success(tagGreen('INDEX'), colors.gray(indexFilepath)); +}; diff --git a/scripts/i18nWorkflow/index.ts b/scripts/i18nWorkflow/index.ts new file mode 100644 index 0000000000000..8bd0c35eb78cc --- /dev/null +++ b/scripts/i18nWorkflow/index.ts @@ -0,0 +1,15 @@ +import { genDefaultLocale } from './genDefaultLocale'; +import { genDiff } from './genDiff'; +import { genResources } from './genResources'; +import { split } from './utils'; + +split('DIFF ANALYSIS'); +genDiff(); + +split('GENERATE DEFAULT LOCALE'); +genDefaultLocale(); + +split('GENERATE RESOURCE & TOC'); +genResources(); + +split('GENERATE I18N FILES'); diff --git a/scripts/i18nWorkflow/utils.ts b/scripts/i18nWorkflow/utils.ts new file mode 100644 index 0000000000000..763c35de77ab7 --- /dev/null +++ b/scripts/i18nWorkflow/utils.ts @@ -0,0 +1,82 @@ +import { consola } from 'consola'; +import { colors } from 'consola/utils'; +import { tocForResources } from 'i18next-resources-for-ts'; +import { isObject } from 'lodash'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { resolve } from 'node:path'; + +import i18nConfig from '../../.i18nrc'; +import { srcLocalesResources } from './const'; + +export const readJSON = (filePath: string) => { + const data = readFileSync(filePath, 'utf8'); + return JSON.parse(data); +}; + +export const replaceAssistantToAgent = (text: string) => + text.replaceAll('assistant', 'agent').replaceAll('Assistant', 'Agent'); + +export const writeJSON = (filePath: string, data: any) => { + const jsonStr = JSON.stringify(data, null, 2); + writeFileSync(filePath, replaceAssistantToAgent(jsonStr), 'utf8'); +}; + +export const genResourcesContent = (locales: string[]) => { + let index = ''; + let indexObj = ''; + + for (const locale of locales) { + index += `import ${locale} from "./${locale}";\n`; + indexObj += ` "${locale.replace('_', '-')}": ${locale},\n`; + } + + return `${index} +const resources = { +${indexObj}} as const; +export default resources; +export const defaultResources = ${i18nConfig.entryLocale}; +export type Resources = typeof resources; +export type DefaultResources = typeof defaultResources; +export type Namespaces = keyof DefaultResources; +export type Locales = keyof Resources; +`; +}; + +export const genNamespaceList = (files: string[], locale: string) => { + return files.map((file) => ({ + name: file.replace('.json', ''), + path: resolve(i18nConfig.output, locale, file), + })); +}; + +export const genToc = (files: string[], locale: string) => { + const ns = genNamespaceList(files, locale); + let toc = tocForResources(ns, srcLocalesResources).replaceAll('\\', '/'); + if (locale === i18nConfig.entryLocale) { + toc = toc.replaceAll('.json', '').replaceAll('../../../locales/zh_CN', '../default'); + } + return toc; +}; + +export const diff = (obj1: any, obj2: any, prefix: string = ''): string[] => { + let result: string[] = []; + for (const key in obj1) { + if (!obj2[key]) continue; + if (isObject(obj1[key]) && isObject(obj2[key])) { + result = [...result, ...diff(obj1[key], obj2[key], `${prefix}${key}.`)]; + } else if (obj1[key] !== obj2[key]) { + result.push(`${prefix}${key}`); + } + } + return result; +}; + +export const tagBlue = (text: string) => colors.bgBlueBright(colors.black(` ${text} `)); +export const tagYellow = (text: string) => colors.bgYellowBright(colors.black(` ${text} `)); +export const tagGreen = (text: string) => colors.bgGreenBright(colors.black(` ${text} `)); +export const tagWhite = (text: string) => colors.bgWhiteBright(colors.black(` ${text} `)); + +export const split = (name: string) => { + consola.log(''); + consola.log(colors.gray(`========================== ${name} ==============================`)); +}; diff --git a/scripts/readmeWorkflow/const.ts b/scripts/readmeWorkflow/const.ts new file mode 100644 index 0000000000000..b5d667fbed49b --- /dev/null +++ b/scripts/readmeWorkflow/const.ts @@ -0,0 +1,19 @@ +export interface DataItem { + author: string; + createAt: string; + homepage: string; + identifier: string; + meta: { avatar: string; description: string; tags: string[]; title: string }; +} + +export const MARKET_URL = 'https://chat-preview.lobehub.com/market'; +export const PLGUIN_URL = 'https://chat-preview.lobehub.com/settings/agent'; +export const AGENT_EN_URL = 'https://chat-agents.lobehub.com/index.json'; +export const AGENT_CN_URL = 'https://chat-agents.lobehub.com/index.zh-CN.json'; +export const AGENT_REPO = 'https://github.com/lobehub/lobe-chat-agents'; +export const PLUGIN_EN_URL = 'https://chat-plugins.lobehub.com/index.json'; +export const PLUGIN_CN_URL = 'https://chat-plugins.lobehub.com/index.zh-CN.json'; +export const PLUGIN_REPO = 'https://github.com/lobehub/lobe-chat-plugins'; + +export const AGENT_SPLIT = ''; +export const PLUGIN_SPLIT = ''; diff --git a/scripts/readmeWorkflow/index.ts b/scripts/readmeWorkflow/index.ts new file mode 100644 index 0000000000000..2fdcbcdb6ee65 --- /dev/null +++ b/scripts/readmeWorkflow/index.ts @@ -0,0 +1,12 @@ +import { consola } from 'consola'; + +import syncAgentIndex from './syncAgentIndex'; +import syncPluginIndex from './syncPluginIndex'; + +const runSync = async () => { + consola.start('Start sync readme workflow...'); + await syncAgentIndex(); + await syncPluginIndex(); +}; + +runSync(); diff --git a/scripts/readmeWorkflow/syncAgentIndex.ts b/scripts/readmeWorkflow/syncAgentIndex.ts new file mode 100644 index 0000000000000..8f364d682465c --- /dev/null +++ b/scripts/readmeWorkflow/syncAgentIndex.ts @@ -0,0 +1,47 @@ +import { consola } from 'consola'; +import { markdownTable } from 'markdown-table'; +import qs from 'query-string'; + +import { AGENT_REPO, AGENT_SPLIT, DataItem, MARKET_URL } from './const'; +import { fetchAgentIndex, genLink, genTags, readReadme, updateReadme, writeReadme } from './utlis'; + +const genAgentTable = (data: DataItem[], lang: string) => { + const isCN = lang === 'zh-CN'; + const content = data.slice(0, 4).map((item) => [ + [ + genLink( + item.meta.title, + qs.stringifyUrl({ + query: { agent: item.identifier }, + url: MARKET_URL, + }), + ), + `By **${genLink(item.author, item.homepage)}** on **${item.createAt}**`, + ].join('
'), + [item.meta.description, genTags(item.meta.tags)].join('
'), + ]); + return markdownTable([ + isCN ? ['最近新增', '助手说明'] : ['Recent Submits', 'Description'], + ...content, + ]); +}; + +const runAgentTable = async (lang: string) => { + const data = await fetchAgentIndex(lang); + const md = readReadme(lang); + const mdTable = genAgentTable(data, lang); + const newMd = updateReadme( + AGENT_SPLIT, + md, + [mdTable, `> 📊 Total agents: ${genLink(`**${data.length}** `, AGENT_REPO)}`].join( + '\n\n', + ), + ); + writeReadme(newMd, lang); + consola.success('Sync agent index success!'); +}; + +export default async () => { + await runAgentTable('en-US'); + await runAgentTable('zh-CN'); +}; diff --git a/scripts/readmeWorkflow/syncPluginIndex.ts b/scripts/readmeWorkflow/syncPluginIndex.ts new file mode 100644 index 0000000000000..db2c1fcf54a93 --- /dev/null +++ b/scripts/readmeWorkflow/syncPluginIndex.ts @@ -0,0 +1,43 @@ +import { consola } from 'consola'; +import { markdownTable } from 'markdown-table'; + +import { DataItem, PLGUIN_URL, PLUGIN_REPO, PLUGIN_SPLIT } from './const'; +import { fetchPluginIndex, genLink, genTags, readReadme, updateReadme, writeReadme } from './utlis'; + +const genPluginTable = (data: DataItem[], lang: string) => { + const isCN = lang === 'zh-CN'; + const content = data + .filter((item) => item.author === 'LobeHub') + .map((item) => [ + [ + genLink(item.meta.title, PLGUIN_URL), + `By **${item.author}** on **${item.createAt}**`, + ].join('
'), + genLink(item.homepage.split('github.com/')[1], item.homepage), + [item.meta.description, genTags(item.meta.tags)].join('
'), + ]); + return markdownTable([ + isCN ? ['官方插件', '仓库', '插件描述'] : ['Official Plugin', 'Repository', 'Description'], + ...content, + ]); +}; + +const runPluginTable = async (lang: string) => { + const data = await fetchPluginIndex(lang); + const md = readReadme(lang); + const mdTable = genPluginTable(data, lang); + const newMd = updateReadme( + PLUGIN_SPLIT, + md, + [mdTable, `> 📊 Total plugins: ${genLink(`**${data.length}**`, PLUGIN_REPO)}`].join( + '\n\n', + ), + ); + writeReadme(newMd, lang); + consola.success('Sync plugin index success!'); +}; + +export default async () => { + await runPluginTable('en-US'); + await runPluginTable('zh-CN'); +}; diff --git a/scripts/readmeWorkflow/utlis.ts b/scripts/readmeWorkflow/utlis.ts new file mode 100644 index 0000000000000..11cd322e20f88 --- /dev/null +++ b/scripts/readmeWorkflow/utlis.ts @@ -0,0 +1,52 @@ +import { kebabCase } from 'lodash'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { resolve } from 'node:path'; + +import { AGENT_CN_URL, AGENT_EN_URL, PLUGIN_CN_URL, PLUGIN_EN_URL } from './const'; + +const fetchIndex = async (url: string) => { + const res = await fetch(url); + return await res.json(); +}; + +export const fetchAgentIndex = async (lang: string) => { + const isCN = lang === 'zh-CN'; + const url = isCN ? AGENT_CN_URL : AGENT_EN_URL; + const data = await fetchIndex(url); + return data.agents; +}; + +export const fetchPluginIndex = async (lang: string) => { + const isCN = lang === 'zh-CN'; + const url = isCN ? PLUGIN_CN_URL : PLUGIN_EN_URL; + const data = await fetchIndex(url); + return data.plugins; +}; + +export const genLink = (title: string, url: string) => `[${title}](${url})`; + +export const genTags = (tags: string[]) => + tags + .filter(Boolean) + .map((tag) => `\`${kebabCase(tag)}\``) + .join(' '); + +const getReadmePath = (lang: string) => { + const isCN = lang === 'zh-CN'; + return resolve(__dirname, '../../', isCN ? `./README.zh-CN.md` : `./README.md`); +}; + +export const readReadme = (lang: string): string => { + return readFileSync(getReadmePath(lang), 'utf8'); +}; + +export const writeReadme = (content: string, lang: string) => { + writeFileSync(getReadmePath(lang), content, 'utf8'); +}; + +export const updateReadme = (split: string, md: string, content: string): string => { + const mds = md.split(split); + mds[1] = [' ', content, ' '].join('\n\n'); + + return mds.join(split); +}; diff --git a/src/app/StyleRegistry.tsx b/src/app/StyleRegistry.tsx new file mode 100644 index 0000000000000..bf625ae9e355a --- /dev/null +++ b/src/app/StyleRegistry.tsx @@ -0,0 +1,24 @@ +'use client'; + +import { StyleProvider, extractStaticStyle } from 'antd-style'; +import { useServerInsertedHTML } from 'next/navigation'; +import { PropsWithChildren, useRef } from 'react'; + +const StyleRegistry = ({ children }: PropsWithChildren) => { + const isInsert = useRef(false); + + useServerInsertedHTML(() => { + // avoid duplicate css insert + // refs: https://github.com/vercel/next.js/discussions/49354#discussioncomment-6279917 + if (isInsert.current) return; + + isInsert.current = true; + + // @ts-ignore + return extractStaticStyle().map((item) => item.style); + }); + + return {children}; +}; + +export default StyleRegistry; diff --git a/src/app/api/auth.ts b/src/app/api/auth.ts new file mode 100644 index 0000000000000..e997953918be0 --- /dev/null +++ b/src/app/api/auth.ts @@ -0,0 +1,25 @@ +import { getServerConfig } from '@/config/server'; +import { ChatErrorType } from '@/types/fetch'; + +interface AuthConfig { + accessCode?: string | null; + apiKey?: string | null; +} + +export const checkAuth = ({ apiKey, accessCode }: AuthConfig) => { + const { ACCESS_CODE } = getServerConfig(); + + // if apiKey exist + if (apiKey) { + return { auth: true }; + } + + // if accessCode doesn't exist + if (!ACCESS_CODE) return { auth: true }; + + if (accessCode !== ACCESS_CODE) { + return { auth: false, error: ChatErrorType.InvalidAccessCode }; + } + + return { auth: true }; +}; diff --git a/src/app/api/config.test.ts b/src/app/api/config.test.ts new file mode 100644 index 0000000000000..503d0b2a521e6 --- /dev/null +++ b/src/app/api/config.test.ts @@ -0,0 +1,42 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { getPreferredRegion } from './config'; + +// Stub the global process object to safely mock environment variables +vi.stubGlobal('process', { + ...process, // Preserve the original process object + env: { ...process.env }, // Clone the environment variables object for modification +}); + +describe('getPreferredRegion', () => { + beforeEach(() => { + // Reset environment variables before each test case + vi.restoreAllMocks(); + }); + + it('returns default value when get config error', () => { + const originalProcess = global.process; + const originalError = console.error; + // @ts-ignore + global.process = undefined; + console.error = () => {}; + + const preferredRegion = getPreferredRegion(); + expect(preferredRegion).toBe('auto'); + + global.process = originalProcess; + console.error = originalError; + }); + + it('return default value when preferredRegion is empty', () => { + process.env.OPENAI_FUNCTION_REGIONS = ''; + const preferredRegion = getPreferredRegion(); + expect(preferredRegion).toBe('auto'); + }); + + it('return correct list values when preferredRegion is correctly passed', () => { + process.env.OPENAI_FUNCTION_REGIONS = 'ida1,sfo1'; + const preferredRegion = getPreferredRegion(); + expect(preferredRegion).toStrictEqual(['ida1', 'sfo1']); + }); +}); diff --git a/src/app/api/config.ts b/src/app/api/config.ts new file mode 100644 index 0000000000000..e12c12153a51c --- /dev/null +++ b/src/app/api/config.ts @@ -0,0 +1,15 @@ +import { getServerConfig } from '@/config/server'; + +export const getPreferredRegion = () => { + try { + const cfg = getServerConfig(); + if (cfg.OPENAI_FUNCTION_REGIONS.length <= 0) { + return 'auto'; + } + + return cfg.OPENAI_FUNCTION_REGIONS; + } catch (error) { + console.error('get server config failed, error:', error); + return 'auto'; + } +}; diff --git a/src/app/api/files/image/imgur.ts b/src/app/api/files/image/imgur.ts new file mode 100644 index 0000000000000..d8f37d5d5e85b --- /dev/null +++ b/src/app/api/files/image/imgur.ts @@ -0,0 +1,72 @@ +import { getServerConfig } from '@/config/server'; + +interface UploadResponse { + data: UploadData; + status: number; + success: boolean; +} + +interface UploadData { + account_id: any; + account_url: any; + ad_type: any; + ad_url: any; + animated: boolean; + bandwidth: number; + datetime: number; + deletehash: string; + description: any; + favorite: boolean; + has_sound: boolean; + height: number; + hls: string; + id: string; + in_gallery: boolean; + in_most_viral: boolean; + is_ad: boolean; + link: string; + mp4: string; + name: string; + nsfw: any; + section: any; + size: number; + tags: any[]; + title: any; + type: string; + views: number; + vote: any; + width: number; +} + +export class Imgur { + clientId: string; + api = 'https://api.imgur.com/3'; + + constructor() { + this.clientId = getServerConfig().IMGUR_CLIENT_ID; + } + + async upload(image: Blob) { + const formData = new FormData(); + + formData.append('image', image, 'image.png'); + + const res = await fetch(`${this.api}/upload`, { + body: formData, + headers: { + Authorization: `Client-ID ${this.clientId}`, + }, + method: 'POST', + }); + + if (!res.ok) { + console.log(await res.text()); + } + + const data: UploadResponse = await res.json(); + if (data.success) { + return data.data.link; + } + return undefined; + } +} diff --git a/src/app/api/files/image/route.ts b/src/app/api/files/image/route.ts new file mode 100644 index 0000000000000..d6ccb672e2373 --- /dev/null +++ b/src/app/api/files/image/route.ts @@ -0,0 +1,42 @@ +import { Imgur } from './imgur'; + +const updateByImgur = async ({ url, blob }: { blob?: Blob; url?: string }) => { + let imageBlob: Blob; + + if (url) { + const res = await fetch(url); + imageBlob = await res.blob(); + } else if (blob) { + imageBlob = blob; + } else { + // TODO: error handle + return; + } + + const imgur = new Imgur(); + + return await imgur.upload(imageBlob); +}; + +export const POST = async (req: Request) => { + const { url } = await req.json(); + + const cdnUrl = await updateByImgur({ url }); + + return new Response(JSON.stringify({ url: cdnUrl })); +}; +// import { Imgur } from './imgur'; + +export const runtime = 'edge'; + +// export const POST = async (req: Request) => { +// const { url } = await req.json(); +// +// const imgur = new Imgur(); +// +// const image = await fetch(url); +// +// const cdnUrl = await imgur.upload(await image.blob()); +// +// return new Response(JSON.stringify({ url: cdnUrl })); +// }; diff --git a/src/app/api/market/[id]/route.ts b/src/app/api/market/[id]/route.ts new file mode 100644 index 0000000000000..e8185561f0d41 --- /dev/null +++ b/src/app/api/market/[id]/route.ts @@ -0,0 +1,19 @@ +import { DEFAULT_LANG } from '@/const/locale'; +import { getAgentJSON } from '@/const/url'; + +export const runtime = 'edge'; + +export const GET = async (req: Request, { params }: { params: { id: string } }) => { + const { searchParams } = new URL(req.url); + + const locale = searchParams.get('locale'); + + let res: Response; + + res = await fetch(getAgentJSON(params.id, locale as any)); + if (res.status === 404) { + res = await fetch(getAgentJSON(params.id, DEFAULT_LANG)); + } + + return res; +}; diff --git a/src/app/api/market/route.ts b/src/app/api/market/route.ts new file mode 100644 index 0000000000000..933e262b4e5d6 --- /dev/null +++ b/src/app/api/market/route.ts @@ -0,0 +1,18 @@ +import { DEFAULT_LANG } from '@/const/locale'; +import { getAgentIndexJSON } from '@/const/url'; + +export const runtime = 'edge'; + +export const GET = async (req: Request) => { + const locale = new URL(req.url).searchParams.get('locale'); + + let res: Response; + + res = await fetch(getAgentIndexJSON(locale as any)); + + if (res.status === 404) { + res = await fetch(getAgentIndexJSON(DEFAULT_LANG)); + } + + return res; +}; diff --git a/src/app/api/openai/chat/createChatCompletion.test.ts b/src/app/api/openai/chat/createChatCompletion.test.ts new file mode 100644 index 0000000000000..fcde3b5ce520e --- /dev/null +++ b/src/app/api/openai/chat/createChatCompletion.test.ts @@ -0,0 +1,129 @@ +import OpenAI, { APIError } from 'openai'; +import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { createChatCompletion } from './createChatCompletion'; + +// Mock the console.error to avoid polluting test output +vi.spyOn(console, 'error').mockImplementation(() => {}); + +describe('createChatCompletion', () => { + let openaiInstance: OpenAI; + + beforeEach(() => { + openaiInstance = new OpenAI({ apiKey: 'test', dangerouslyAllowBrowser: true }); + + // 使用 vi.spyOn 来模拟 chat.completions.create 方法 + vi.spyOn(openaiInstance.chat.completions, 'create').mockResolvedValue( + new ReadableStream() as any, + ); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it('should return a StreamingTextResponse on successful API call', async () => { + // Arrange + const mockStream = new ReadableStream(); + const mockResponse = Promise.resolve(mockStream); + + (openaiInstance.chat.completions.create as Mock).mockResolvedValue(mockResponse); + + // Act + const result = await createChatCompletion({ + openai: openaiInstance, + payload: { + messages: [{ content: 'Hello', name: 'User', role: 'user' }], + model: 'text-davinci-003', + temperature: 0, + }, + }); + + // Assert + expect(result).toBeInstanceOf(Response); // 注意这里的改动 + }); + + it('should return an openai error response when OpenAI.APIError is thrown', async () => { + // Arrange + const apiError = new OpenAI.APIError( + 400, + { + status: 400, + error: { + message: 'Bad Request', + }, + }, + 'Error message', + {}, + ); + + vi.spyOn(openaiInstance.chat.completions, 'create').mockRejectedValue(apiError); + + // Act + const result = await createChatCompletion({ + openai: openaiInstance, + payload: { + messages: [{ content: 'Hello', name: 'User', role: 'user' }], + model: 'text-davinci-003', + temperature: 0, + }, + }); + + // Assert + expect(result).toBeInstanceOf(Response); + expect(result.status).toBe(577); // Your custom error status code + }); + it('should return an cause response when OpenAI.APIError is thrown with cause', async () => { + // Arrange + const errorInfo = { + stack: 'abc', + cause: { + message: 'api is undefined', + }, + }; + const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {}); + + vi.spyOn(openaiInstance.chat.completions, 'create').mockRejectedValue(apiError); + + // Act + const result = await createChatCompletion({ + openai: openaiInstance, + payload: { + messages: [{ content: 'Hello', name: 'User', role: 'user' }], + model: 'text-davinci-003', + temperature: 0, + }, + }); + + // Assert + expect(result).toBeInstanceOf(Response); + expect(result.status).toBe(577); // Your custom error status code + + const content = await result.json(); + expect(content.body).toHaveProperty('endpoint'); + expect(content.body.error).toEqual(errorInfo); + }); + + it('should return a 500 error response for non-OpenAI errors', async () => { + // Arrange + const genericError = new Error('Generic Error'); + + vi.spyOn(openaiInstance.chat.completions, 'create').mockRejectedValue(genericError); + + // Act + const result = await createChatCompletion({ + openai: openaiInstance, + payload: { + messages: [{ content: 'Hello', name: 'User', role: 'user' }], + model: 'text-davinci-003', + temperature: 0, + }, + }); + + // Assert + expect(result.status).toBe(500); + const content = await result.json(); + expect(content.body).toHaveProperty('endpoint'); + expect(content.body).toHaveProperty('error'); + }); +}); diff --git a/src/app/api/openai/chat/createChatCompletion.ts b/src/app/api/openai/chat/createChatCompletion.ts new file mode 100644 index 0000000000000..11c1a4a0fcb4b --- /dev/null +++ b/src/app/api/openai/chat/createChatCompletion.ts @@ -0,0 +1,74 @@ +import { OpenAIStream, StreamingTextResponse } from 'ai'; +import OpenAI from 'openai'; + +import { createErrorResponse } from '@/app/api/openai/errorResponse'; +import { ChatErrorType } from '@/types/fetch'; +import { OpenAIChatStreamPayload } from '@/types/openai/chat'; + +interface CreateChatCompletionOptions { + openai: OpenAI; + payload: OpenAIChatStreamPayload; +} + +export const createChatCompletion = async ({ payload, openai }: CreateChatCompletionOptions) => { + // ============ 1. preprocess messages ============ // + const { messages, ...params } = payload; + + // remove unnecessary fields like `plugins` or `files` by lobe-chat + const formatMessages = messages.map((m) => ({ + content: m.content, + name: m.name, + role: m.role, + })) as OpenAI.ChatCompletionMessageParam[]; + + // ============ 2. send api ============ // + + try { + const response = await openai.chat.completions.create( + { + messages: formatMessages, + ...params, + stream: true, + }, + { headers: { Accept: '*/*' } }, + ); + const stream = OpenAIStream(response); + return new StreamingTextResponse(stream); + } catch (error) { + // Check if the error is an OpenAI APIError + if (error instanceof OpenAI.APIError) { + let errorResult: any; + + // if error is definitely OpenAI APIError, there will be an error object + if (error.error) { + errorResult = error.error; + } + // Or if there is a cause, we use error cause + // This often happened when there is a bug of the `openai` package. + else if (error.cause) { + errorResult = error.cause; + } + // if there is no other request error, the error object is a Response like object + else { + errorResult = { headers: error.headers, stack: error.stack, status: error.status }; + } + + // track the error at server side + console.error(errorResult); + + return createErrorResponse(ChatErrorType.OpenAIBizError, { + endpoint: openai.baseURL, + error: errorResult, + }); + } + + // track the non-openai error + console.error(error); + + // return as a GatewayTimeout error + return createErrorResponse(ChatErrorType.InternalServerError, { + endpoint: openai.baseURL, + error: JSON.stringify(error), + }); + } +}; diff --git a/src/app/api/openai/chat/route.ts b/src/app/api/openai/chat/route.ts new file mode 100644 index 0000000000000..ba9a6a589db8e --- /dev/null +++ b/src/app/api/openai/chat/route.ts @@ -0,0 +1,19 @@ +import { OpenAIChatStreamPayload } from '@/types/openai/chat'; + +import { getPreferredRegion } from '../../config'; +import { createBizOpenAI } from '../createBizOpenAI'; +import { createChatCompletion } from './createChatCompletion'; + +export const runtime = 'edge'; +export const preferredRegion = getPreferredRegion(); + +export const POST = async (req: Request) => { + const payload = (await req.json()) as OpenAIChatStreamPayload; + + const openaiOrErrResponse = createBizOpenAI(req, payload.model); + + // if resOrOpenAI is a Response, it means there is an error,just return it + if (openaiOrErrResponse instanceof Response) return openaiOrErrResponse; + + return createChatCompletion({ openai: openaiOrErrResponse, payload }); +}; diff --git a/src/app/api/openai/createBizOpenAI/createAzureOpenai.ts b/src/app/api/openai/createBizOpenAI/createAzureOpenai.ts new file mode 100644 index 0000000000000..0905f0818e1e3 --- /dev/null +++ b/src/app/api/openai/createBizOpenAI/createAzureOpenai.ts @@ -0,0 +1,33 @@ +import OpenAI, { ClientOptions } from 'openai'; +import urlJoin from 'url-join'; + +import { getServerConfig } from '@/config/server'; +import { ChatErrorType } from '@/types/fetch'; + +// create Azure OpenAI Instance +export const createAzureOpenai = (params: { + apiVersion?: string | null; + endpoint?: string | null; + model: string; + userApiKey?: string | null; +}) => { + const { OPENAI_PROXY_URL = '', AZURE_API_VERSION, AZURE_API_KEY } = getServerConfig(); + + const endpoint = !params.endpoint ? OPENAI_PROXY_URL : params.endpoint; + const baseURL = urlJoin(endpoint, `/openai/deployments/${params.model.replace('.', '')}`); // refs: https://test-001.openai.azure.com/openai/deployments/gpt-35-turbo + + const defaultApiVersion = AZURE_API_VERSION || '2023-08-01-preview'; + const apiVersion = !params.apiVersion ? defaultApiVersion : params.apiVersion; + const apiKey = !params.userApiKey ? AZURE_API_KEY : params.userApiKey; + + if (!apiKey) throw new Error('AZURE_API_KEY is empty', { cause: ChatErrorType.NoAPIKey }); + + const config: ClientOptions = { + apiKey, + baseURL, + defaultHeaders: { 'api-key': apiKey }, + defaultQuery: { 'api-version': apiVersion }, + }; + + return new OpenAI(config); +}; diff --git a/src/app/api/openai/createBizOpenAI/createOpenai.ts b/src/app/api/openai/createBizOpenAI/createOpenai.ts new file mode 100644 index 0000000000000..95a6422592c8f --- /dev/null +++ b/src/app/api/openai/createBizOpenAI/createOpenai.ts @@ -0,0 +1,17 @@ +import OpenAI from 'openai'; + +import { getServerConfig } from '@/config/server'; +import { ChatErrorType } from '@/types/fetch'; + +// create OpenAI instance +export const createOpenai = (userApiKey: string | null, endpoint?: string | null) => { + const { OPENAI_API_KEY, OPENAI_PROXY_URL } = getServerConfig(); + + const baseURL = endpoint ? endpoint : OPENAI_PROXY_URL ? OPENAI_PROXY_URL : undefined; + + const apiKey = !userApiKey ? OPENAI_API_KEY : userApiKey; + + if (!apiKey) throw new Error('OPENAI_API_KEY is empty', { cause: ChatErrorType.NoAPIKey }); + + return new OpenAI({ apiKey, baseURL }); +}; diff --git a/src/app/api/openai/createBizOpenAI/index.ts b/src/app/api/openai/createBizOpenAI/index.ts new file mode 100644 index 0000000000000..dbf515e01c6ad --- /dev/null +++ b/src/app/api/openai/createBizOpenAI/index.ts @@ -0,0 +1,46 @@ +import OpenAI from 'openai/index'; + +import { checkAuth } from '@/app/api/auth'; +import { getServerConfig } from '@/config/server'; +import { getOpenAIAuthFromRequest } from '@/const/fetch'; +import { ChatErrorType, ErrorType } from '@/types/fetch'; + +import { createErrorResponse } from '../errorResponse'; +import { createAzureOpenai } from './createAzureOpenai'; +import { createOpenai } from './createOpenai'; + +/** + * createOpenAI Instance with Auth and azure openai support + * if auth not pass ,just return error response + */ +export const createBizOpenAI = (req: Request, model: string): Response | OpenAI => { + const { apiKey, accessCode, endpoint, useAzure, apiVersion } = getOpenAIAuthFromRequest(req); + + const result = checkAuth({ accessCode, apiKey }); + + if (!result.auth) { + return createErrorResponse(result.error as ErrorType); + } + + let openai: OpenAI; + + const { USE_AZURE_OPENAI } = getServerConfig(); + const useAzureOpenAI = useAzure || USE_AZURE_OPENAI; + + try { + if (useAzureOpenAI) { + openai = createAzureOpenai({ apiVersion, endpoint, model, userApiKey: apiKey }); + } else { + openai = createOpenai(apiKey, endpoint); + } + } catch (error) { + if ((error as Error).cause === ChatErrorType.NoAPIKey) { + return createErrorResponse(ChatErrorType.NoAPIKey); + } + + console.error(error); // log error to trace it + return createErrorResponse(ChatErrorType.InternalServerError); + } + + return openai; +}; diff --git a/src/app/api/openai/errorResponse.test.ts b/src/app/api/openai/errorResponse.test.ts new file mode 100644 index 0000000000000..5bc2679ecb062 --- /dev/null +++ b/src/app/api/openai/errorResponse.test.ts @@ -0,0 +1,55 @@ +import { describe, expect, it } from 'vitest'; + +import { ChatErrorType, ErrorResponse, ErrorType } from '@/types/fetch'; + +import { createErrorResponse } from './errorResponse'; + +describe('createErrorResponse', () => { + // 测试各种错误类型的状态码 + it('returns a 401 status for NoAPIKey error type', () => { + const errorType = ChatErrorType.NoAPIKey; + const response = createErrorResponse(errorType); + expect(response.status).toBe(401); + }); + + it('returns a 401 status for InvalidAccessCode error type', () => { + const errorType = ChatErrorType.InvalidAccessCode; + const response = createErrorResponse(errorType); + expect(response.status).toBe(401); + }); + + it('returns a 577 status for OpenAIBizError error type', () => { + const errorType = ChatErrorType.OpenAIBizError; + const response = createErrorResponse(errorType); + expect(response.status).toBe(577); + }); + + // 测试默认情况 + it('returns the same error type as status for unknown error types', () => { + const errorType = 500; // 假设500是一个未知的错误类型 + const response = createErrorResponse(errorType); + expect(response.status).toBe(errorType); + }); + + // 测试返回的Response对象是否包含正确的body和errorType + it('returns a Response object with the correct body and errorType', () => { + const errorType = ChatErrorType.NoAPIKey; + const body = { message: 'No API key provided' }; + const response = createErrorResponse(errorType, body); + return response.json().then((data) => { + expect(data).toEqual({ + body, + errorType, + }); + }); + }); + + // 测试没有提供body时,返回的Response对象的body是否为undefined + it('returns a Response object with an undefined body when no body is provided', () => { + const errorType = ChatErrorType.NoAPIKey; + const response = createErrorResponse(errorType); + return response.json().then((data) => { + expect(data.body).toBeUndefined(); + }); + }); +}); diff --git a/src/app/api/openai/errorResponse.ts b/src/app/api/openai/errorResponse.ts new file mode 100644 index 0000000000000..7039fad899551 --- /dev/null +++ b/src/app/api/openai/errorResponse.ts @@ -0,0 +1,23 @@ +import { ChatErrorType, ErrorResponse, ErrorType } from '@/types/fetch'; + +const getStatus = (errorType: ErrorType) => { + switch (errorType) { + case ChatErrorType.NoAPIKey: + case ChatErrorType.InvalidAccessCode: { + return 401; + } + + case ChatErrorType.OpenAIBizError: { + return 577; + } + } + return errorType; +}; + +export const createErrorResponse = (errorType: ErrorType, body?: any) => { + const statusCode = getStatus(errorType); + + const data: ErrorResponse = { body, errorType }; + + return new Response(JSON.stringify(data), { status: statusCode }); +}; diff --git a/src/app/api/openai/models/route.ts b/src/app/api/openai/models/route.ts new file mode 100644 index 0000000000000..c9827d0e52411 --- /dev/null +++ b/src/app/api/openai/models/route.ts @@ -0,0 +1,17 @@ +import { getOpenAIAuthFromRequest } from '@/const/fetch'; + +import { createOpenai } from '../createBizOpenAI/createOpenai'; + +export const runtime = 'edge'; + +export const POST = async (req: Request) => { + const { apiKey, endpoint } = getOpenAIAuthFromRequest(req); + + const openAI = createOpenai(apiKey, endpoint); + + const res = await openAI.models.list(); + + const modelList = res.data.map((i) => i.id); + + return new Response(JSON.stringify(modelList)); +}; diff --git a/src/app/api/openai/stt/route.ts b/src/app/api/openai/stt/route.ts new file mode 100644 index 0000000000000..b927e5274de4c --- /dev/null +++ b/src/app/api/openai/stt/route.ts @@ -0,0 +1,31 @@ +import { OpenAISTTPayload } from '@lobehub/tts'; +import { createOpenaiAudioTranscriptions } from '@lobehub/tts/server'; + +import { getPreferredRegion } from '../../config'; +import { createBizOpenAI } from '../createBizOpenAI'; + +export const runtime = 'edge'; +export const preferredRegion = getPreferredRegion(); + +export const POST = async (req: Request) => { + const formData = await req.formData(); + const speechBlob = formData.get('speech') as Blob; + const optionsString = formData.get('options') as string; + const payload = { + options: JSON.parse(optionsString), + speech: speechBlob, + } as OpenAISTTPayload; + + const openaiOrErrResponse = createBizOpenAI(req, payload.options.model); + + // if resOrOpenAI is a Response, it means there is an error,just return it + if (openaiOrErrResponse instanceof Response) return openaiOrErrResponse; + + const res = await createOpenaiAudioTranscriptions({ openai: openaiOrErrResponse, payload }); + + return new Response(JSON.stringify(res), { + headers: { + 'content-type': 'application/json;charset=UTF-8', + }, + }); +}; diff --git a/src/app/api/openai/tts/route.ts b/src/app/api/openai/tts/route.ts new file mode 100644 index 0000000000000..09954361bb254 --- /dev/null +++ b/src/app/api/openai/tts/route.ts @@ -0,0 +1,19 @@ +import { OpenAITTSPayload } from '@lobehub/tts'; +import { createOpenaiAudioSpeech } from '@lobehub/tts/server'; + +import { getPreferredRegion } from '../../config'; +import { createBizOpenAI } from '../createBizOpenAI'; + +export const runtime = 'edge'; +export const preferredRegion = getPreferredRegion(); + +export const POST = async (req: Request) => { + const payload = (await req.json()) as OpenAITTSPayload; + + const openaiOrErrResponse = createBizOpenAI(req, payload.options.model); + + // if resOrOpenAI is a Response, it means there is an error,just return it + if (openaiOrErrResponse instanceof Response) return openaiOrErrResponse; + + return await createOpenaiAudioSpeech({ openai: openaiOrErrResponse, payload }); +}; diff --git a/src/app/api/plugins/route.ts b/src/app/api/plugins/route.ts new file mode 100644 index 0000000000000..936d627251e8d --- /dev/null +++ b/src/app/api/plugins/route.ts @@ -0,0 +1,7 @@ +import { createLobeChatPluginGateway } from '@lobehub/chat-plugins-gateway'; + +import { PLUGINS_INDEX_URL } from '@/const/url'; + +export const runtime = 'edge'; + +export const POST = createLobeChatPluginGateway({ pluginsIndexUrl: PLUGINS_INDEX_URL }); diff --git a/src/app/api/tts/edge-speech/route.ts b/src/app/api/tts/edge-speech/route.ts new file mode 100644 index 0000000000000..c8df174ba3825 --- /dev/null +++ b/src/app/api/tts/edge-speech/route.ts @@ -0,0 +1,9 @@ +import { EdgeSpeechPayload, EdgeSpeechTTS } from '@lobehub/tts'; + +export const runtime = 'edge'; + +export const POST = async (req: Request) => { + const payload = (await req.json()) as EdgeSpeechPayload; + + return await EdgeSpeechTTS.createRequest({ payload }); +}; diff --git a/src/app/api/tts/microsoft-speech/route.ts b/src/app/api/tts/microsoft-speech/route.ts new file mode 100644 index 0000000000000..5e37c5d32b501 --- /dev/null +++ b/src/app/api/tts/microsoft-speech/route.ts @@ -0,0 +1,9 @@ +import { MicrosoftSpeechPayload, MicrosoftSpeechTTS } from '@lobehub/tts'; + +export const runtime = 'edge'; + +export const POST = async (req: Request) => { + const payload = (await req.json()) as MicrosoftSpeechPayload; + + return await MicrosoftSpeechTTS.createRequest({ payload }); +}; diff --git a/src/app/chat/(desktop)/features/ChatHeader.tsx b/src/app/chat/(desktop)/features/ChatHeader.tsx new file mode 100644 index 0000000000000..3a3337c5347c1 --- /dev/null +++ b/src/app/chat/(desktop)/features/ChatHeader.tsx @@ -0,0 +1,108 @@ +import { SiOpenai } from '@icons-pack/react-simple-icons'; +import { ActionIcon, Avatar, ChatHeader, ChatHeaderTitle, Tag } from '@lobehub/ui'; +import { Skeleton } from 'antd'; +import { PanelRightClose, PanelRightOpen, Settings } from 'lucide-react'; +import { useRouter } from 'next/navigation'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens'; +import { useGlobalStore } from '@/store/global'; +import { useSessionChatInit, useSessionStore } from '@/store/session'; +import { agentSelectors, sessionSelectors } from '@/store/session/selectors'; +import { pathString } from '@/utils/url'; + +import PluginTag from '../../features/ChatHeader/PluginTag'; +import ShareButton from '../../features/ChatHeader/ShareButton'; + +const Header = memo(() => { + const init = useSessionChatInit(); + const router = useRouter(); + + const { t } = useTranslation('chat'); + + const [isInbox, title, description, avatar, backgroundColor, model, plugins] = useSessionStore( + (s) => [ + sessionSelectors.isInboxSession(s), + agentSelectors.currentAgentTitle(s), + agentSelectors.currentAgentDescription(s), + agentSelectors.currentAgentAvatar(s), + agentSelectors.currentAgentBackgroundColor(s), + agentSelectors.currentAgentModel(s), + agentSelectors.currentAgentPlugins(s), + ], + ); + + const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [ + s.preference.showChatSideBar, + s.toggleChatSideBar, + ]); + + const displayTitle = isInbox ? t('inbox.title') : title; + const displayDesc = isInbox ? t('inbox.desc') : description; + + return ( + + + + ) : ( + + + isInbox + ? router.push('/settings/agent') + : router.push(pathString('/chat/settings', { hash: location.hash })) + } + size={40} + title={title} + /> + + }>{model} + {plugins?.length > 0 && } + + } + title={displayTitle} + /> + + ) + } + right={ + <> + + toggleConfig()} + size={DESKTOP_HEADER_ICON_SIZE} + title={t('roleAndArchive')} + /> + {!isInbox && ( + { + router.push(pathString('/chat/settings', { hash: location.hash })); + }} + size={DESKTOP_HEADER_ICON_SIZE} + title={t('header.session', { ns: 'setting' })} + /> + )} + + } + /> + ); +}); + +export default Header; diff --git a/src/app/chat/(desktop)/features/ChatInput/DragUpload.tsx b/src/app/chat/(desktop)/features/ChatInput/DragUpload.tsx new file mode 100644 index 0000000000000..ce8063fd3472e --- /dev/null +++ b/src/app/chat/(desktop)/features/ChatInput/DragUpload.tsx @@ -0,0 +1,166 @@ +import { Icon } from '@lobehub/ui'; +import { createStyles } from 'antd-style'; +import { FileImage, FileText, FileUpIcon } from 'lucide-react'; +import { rgba } from 'polished'; +import { memo, useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Center, Flexbox } from 'react-layout-kit'; + +import { useFileStore } from '@/store/files'; + +const useStyles = createStyles(({ css, token, stylish }) => { + return { + container: css` + width: 300px; + height: 300px; + padding: 16px; + + color: ${token.colorWhite}; + + background: ${token.geekblue}; + border-radius: 16px; + box-shadow: + ${rgba(token.geekblue, 0.1)} 0 1px 1px 0 inset, + ${rgba(token.geekblue, 0.1)} 0 50px 100px -20px, + ${rgba(token.geekblue, 0.3)} 0 30px 60px -30px; + `, + content: css` + width: 100%; + height: 100%; + padding: 16px; + + border: 2px dashed ${token.colorWhite}; + border-radius: 12px; + `, + desc: css` + color: ${rgba(token.colorTextLightSolid, 0.6)}; + `, + title: css` + font-size: 24px; + font-weight: bold; + `, + wrapper: css` + position: fixed; + z-index: 10000000; + top: 0; + left: 0; + + width: 100%; + height: 100%; + + transition: all 0.3s ease-in-out; + + background: ${token.colorBgMask}; + ${stylish.blur}; + `, + }; +}); + +const handleDragOver = (e: DragEvent) => { + e.preventDefault(); +}; + +const DragUpload = memo(() => { + const { styles } = useStyles(); + const { t } = useTranslation('chat'); + const [isDragging, setIsDragging] = useState(false); + // When a file is dragged to a different area, the 'dragleave' event may be triggered, + // causing isDragging to be mistakenly set to false. + // to fix this issue, use a counter to ensure the status change only when drag event left the browser window . + const dragCounter = useRef(0); + + const uploadFile = useFileStore((s) => s.uploadFile); + + const uploadImages = async (fileList: FileList | undefined) => { + if (!fileList || fileList.length === 0) return; + + const pools = Array.from(fileList).map(async (file) => { + // skip none-file items + if (!file.type.startsWith('image')) return; + await uploadFile(file); + }); + + await Promise.all(pools); + }; + + const handleDragEnter = (e: DragEvent) => { + e.preventDefault(); + + dragCounter.current += 1; + if (e.dataTransfer?.items && e.dataTransfer.items.length > 0) { + setIsDragging(true); + } + }; + + const handleDragLeave = (e: DragEvent) => { + e.preventDefault(); + + // reset counter + dragCounter.current -= 1; + + if (dragCounter.current === 0) { + setIsDragging(false); + } + }; + + const handleDrop = async (e: DragEvent) => { + e.preventDefault(); + // reset counter + dragCounter.current = 0; + + setIsDragging(false); + + // get filesList + // TODO: support folder files upload + const files = e.dataTransfer?.files; + + // upload files + uploadImages(files); + }; + + const handlePaste = (event: ClipboardEvent) => { + // get files from clipboard + + const files = event.clipboardData?.files; + + uploadImages(files); + }; + + useEffect(() => { + window.addEventListener('dragenter', handleDragEnter); + window.addEventListener('dragover', handleDragOver); + window.addEventListener('dragleave', handleDragLeave); + window.addEventListener('drop', handleDrop); + window.addEventListener('paste', handlePaste); + + return () => { + window.removeEventListener('dragenter', handleDragEnter); + window.removeEventListener('dragover', handleDragOver); + window.removeEventListener('dragleave', handleDragLeave); + window.removeEventListener('drop', handleDrop); + window.removeEventListener('paste', handlePaste); + }; + }, []); + + return ( + isDragging && ( +
+
+
+ + + + + + + {t('upload.dragTitle')} + {t('upload.dragDesc')} + +
+
+
+ ) + ); +}); + +export default DragUpload; diff --git a/src/app/chat/(desktop)/features/ChatInput/Footer/LocalFiles.tsx b/src/app/chat/(desktop)/features/ChatInput/Footer/LocalFiles.tsx new file mode 100644 index 0000000000000..d5163b060273d --- /dev/null +++ b/src/app/chat/(desktop)/features/ChatInput/Footer/LocalFiles.tsx @@ -0,0 +1,10 @@ +import { memo } from 'react'; + +import FileList from '@/app/chat/components/FileList'; +import { useFileStore } from '@/store/files'; + +export const LocalFiles = memo(() => { + const inputFilesList = useFileStore((s) => s.inputFilesList); + + return ; +}); diff --git a/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx b/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx new file mode 100644 index 0000000000000..17d61323a3805 --- /dev/null +++ b/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx @@ -0,0 +1,64 @@ +import { Icon } from '@lobehub/ui'; +import { Button } from 'antd'; +import { useTheme } from 'antd-style'; +import { ArrowBigUp, CornerDownLeft, Loader2 } from 'lucide-react'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import SaveTopic from '@/app/chat/features/ChatInput/Topic'; +import { useSendMessage } from '@/app/chat/features/ChatInput/useSend'; +import { useSessionStore } from '@/store/session'; +import { agentSelectors } from '@/store/session/selectors'; + +import { LocalFiles } from './LocalFiles'; + +const Footer = memo(() => { + const { t } = useTranslation('chat'); + const theme = useTheme(); + const [loading, onStop] = useSessionStore((s) => [!!s.chatLoadingId, s.stopGenerateMessage]); + + const onSend = useSendMessage(); + const canUpload = useSessionStore(agentSelectors.modelHasVisionAbility); + + return ( + + {canUpload && } + + + + {t('send')} + / + + + + + {t('warp')} + + + {loading ? ( + + ) : ( + + )} + + + ); +}); + +export default Footer; diff --git a/src/app/chat/(desktop)/features/ChatInput/InputArea.tsx b/src/app/chat/(desktop)/features/ChatInput/InputArea.tsx new file mode 100644 index 0000000000000..96ca134ae9d99 --- /dev/null +++ b/src/app/chat/(desktop)/features/ChatInput/InputArea.tsx @@ -0,0 +1,30 @@ +import { createStyles } from 'antd-style'; +import { memo } from 'react'; + +import InputAreaInner from '@/app/chat/features/ChatInput/InputAreaInner'; + +const useStyles = createStyles(({ css }) => { + return { + textarea: css` + height: 100% !important; + padding: 0 24px; + line-height: 1.5; + `, + textareaContainer: css` + position: relative; + flex: 1; + `, + }; +}); + +const InputArea = memo(() => { + const { styles } = useStyles(); + + return ( +
+ +
+ ); +}); + +export default InputArea; diff --git a/src/app/chat/(desktop)/features/ChatInput/index.tsx b/src/app/chat/(desktop)/features/ChatInput/index.tsx new file mode 100644 index 0000000000000..55bac43bbb4e7 --- /dev/null +++ b/src/app/chat/(desktop)/features/ChatInput/index.tsx @@ -0,0 +1,78 @@ +import { ActionIcon, DraggablePanel } from '@lobehub/ui'; +import { createStyles } from 'antd-style'; +import { Maximize2, Minimize2 } from 'lucide-react'; +import { memo, useState } from 'react'; + +import ActionBar from '@/app/chat/features/ChatInput/ActionBar'; +import { CHAT_TEXTAREA_HEIGHT, HEADER_HEIGHT } from '@/const/layoutTokens'; +import { useGlobalStore } from '@/store/global'; +import { useSessionStore } from '@/store/session'; +import { agentSelectors } from '@/store/session/selectors'; + +import DragUpload from './DragUpload'; +import Footer from './Footer'; +import InputArea from './InputArea'; + +const useStyles = createStyles(({ css }) => { + return { + container: css` + position: relative; + + display: flex; + flex-direction: column; + gap: 8px; + + height: 100%; + padding: 12px 0 16px; + `, + }; +}); + +const ChatInputDesktopLayout = memo(() => { + const { styles } = useStyles(); + const [expand, setExpand] = useState(false); + + const [inputHeight, updatePreference] = useGlobalStore((s) => [ + s.preference.inputHeight, + s.updatePreference, + ]); + + const canUpload = useSessionStore(agentSelectors.modelHasVisionAbility); + return ( + <> + {canUpload && } + { + if (!size) return; + updatePreference({ + inputHeight: + typeof size.height === 'string' ? Number.parseInt(size.height) : size.height, + }); + }} + placement="bottom" + size={{ height: inputHeight, width: '100%' }} + style={{ zIndex: 10 }} + > +
+ { + setExpand(!expand); + }} + /> + } + /> + +
+
+
+ + ); +}); + +export default ChatInputDesktopLayout; diff --git a/src/app/chat/(desktop)/features/SessionHeader.tsx b/src/app/chat/(desktop)/features/SessionHeader.tsx new file mode 100644 index 0000000000000..2c40470f6eb49 --- /dev/null +++ b/src/app/chat/(desktop)/features/SessionHeader.tsx @@ -0,0 +1,45 @@ +import { ActionIcon, Logo } from '@lobehub/ui'; +import { createStyles } from 'antd-style'; +import { MessageSquarePlus } from 'lucide-react'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens'; +import { useSessionStore } from '@/store/session'; + +import SessionSearchBar from '../../features/SessionSearchBar'; + +export const useStyles = createStyles(({ css, token }) => ({ + logo: css` + fill: ${token.colorText}; + `, + top: css` + position: sticky; + top: 0; + `, +})); + +const Header = memo(() => { + const { styles } = useStyles(); + const { t } = useTranslation('chat'); + const [createSession] = useSessionStore((s) => [s.createSession]); + + return ( + + + + createSession()} + size={DESKTOP_HEADER_ICON_SIZE} + style={{ flex: 'none' }} + title={t('newAgent')} + /> + + + + ); +}); + +export default Header; diff --git a/src/app/chat/(desktop)/features/SessionList.tsx b/src/app/chat/(desktop)/features/SessionList.tsx new file mode 100644 index 0000000000000..5394872cd2e6e --- /dev/null +++ b/src/app/chat/(desktop)/features/SessionList.tsx @@ -0,0 +1,35 @@ +import { DraggablePanelBody } from '@lobehub/ui'; +import { createStyles } from 'antd-style'; +import { memo } from 'react'; + +import FolderPanel from '@/features/FolderPanel'; + +import SessionListContent from '../../features/SessionListContent'; +import Header from './SessionHeader'; + +const useStyles = createStyles(({ stylish, css, cx }) => + cx( + stylish.noScrollbar, + css` + display: flex; + flex-direction: column; + gap: 2px; + padding: 8px 8px 0; + `, + ), +); + +const Sessions = memo(() => { + const { styles } = useStyles(); + + return ( + +
+ + + + + ); +}); + +export default Sessions; diff --git a/src/app/chat/(desktop)/features/SideBar.tsx b/src/app/chat/(desktop)/features/SideBar.tsx new file mode 100644 index 0000000000000..d43b92420d005 --- /dev/null +++ b/src/app/chat/(desktop)/features/SideBar.tsx @@ -0,0 +1,67 @@ +import { DraggablePanel, DraggablePanelContainer } from '@lobehub/ui'; +import { createStyles } from 'antd-style'; +import dynamic from 'next/dynamic'; +import { memo } from 'react'; + +import SafeSpacing from '@/components/SafeSpacing'; +import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens'; +import { useGlobalStore } from '@/store/global'; +import { useSessionStore } from '@/store/session'; +import { sessionSelectors } from '@/store/session/selectors'; + +import TopicListContent from '../../features/TopicListContent'; + +const SystemRole = dynamic(() => import('../../features/SystemRole')); + +const useStyles = createStyles(({ css, token }) => ({ + content: css` + display: flex; + flex-direction: column; + `, + drawer: css` + background: ${token.colorBgLayout}; + `, + header: css` + border-bottom: 1px solid ${token.colorBorder}; + `, +})); + +const Desktop = memo(() => { + const { styles } = useStyles(); + const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [ + s.preference.showChatSideBar, + s.toggleChatSideBar, + ]); + + const isInbox = useSessionStore(sessionSelectors.isInboxSession); + + return ( + + + + {!isInbox && } + + + + ); +}); + +export default Desktop; diff --git a/src/app/chat/(desktop)/index.tsx b/src/app/chat/(desktop)/index.tsx new file mode 100644 index 0000000000000..635f400bc0f1a --- /dev/null +++ b/src/app/chat/(desktop)/index.tsx @@ -0,0 +1,30 @@ +'use client'; + +import dynamic from 'next/dynamic'; +import { FC, memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import ResponsiveIndex from '@/components/ResponsiveIndex'; + +import Conversation from '../features/Conversation'; +import PageTitle from '../features/PageTitle'; +import ChatHeader from './features/ChatHeader'; +import ChatInput from './features/ChatInput'; +import SideBar from './features/SideBar'; +import Layout from './layout.desktop'; + +const Mobile: FC = dynamic(() => import('../(mobile)'), { ssr: false }) as FC; + +const DesktopPage = memo(() => ( + + + + + + } /> + + + + +)); +export default DesktopPage; diff --git a/src/app/chat/(desktop)/layout.desktop.tsx b/src/app/chat/(desktop)/layout.desktop.tsx new file mode 100644 index 0000000000000..7894b7bc2e4ce --- /dev/null +++ b/src/app/chat/(desktop)/layout.desktop.tsx @@ -0,0 +1,27 @@ +'use client'; + +import { PropsWithChildren, memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import AppLayoutDesktop from '@/layout/AppLayout.desktop'; +import { useSwitchSideBarOnInit } from '@/store/global'; +import { SidebarTabKey } from '@/store/global/initialState'; + +import ResponsiveSessionList from './features/SessionList'; + +export default memo(({ children }: PropsWithChildren) => { + useSwitchSideBarOnInit(SidebarTabKey.Chat); + return ( + + + + {children} + + + ); +}); diff --git a/src/app/chat/(mobile)/features/ChatHeader.tsx b/src/app/chat/(mobile)/features/ChatHeader.tsx new file mode 100644 index 0000000000000..1767a0ba98b97 --- /dev/null +++ b/src/app/chat/(mobile)/features/ChatHeader.tsx @@ -0,0 +1,68 @@ +import { ActionIcon, Icon, MobileNavBar, MobileNavBarTitle } from '@lobehub/ui'; +import { Dropdown, MenuProps } from 'antd'; +import { Clock3, MoreHorizontal, Settings, Share2 } from 'lucide-react'; +import { useRouter } from 'next/navigation'; +import { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens'; +import { useGlobalStore } from '@/store/global'; +import { useSessionStore } from '@/store/session'; +import { agentSelectors, sessionSelectors } from '@/store/session/selectors'; +import { pathString } from '@/utils/url'; + +import ShareButton from '../../features/ChatHeader/ShareButton'; + +const MobileHeader = memo(() => { + const { t } = useTranslation('chat'); + const router = useRouter(); + const [open, setOpen] = useState(false); + + const [isInbox, title] = useSessionStore((s) => [ + sessionSelectors.isInboxSession(s), + agentSelectors.currentAgentTitle(s), + ]); + + const [toggleConfig] = useGlobalStore((s) => [s.toggleMobileTopic]); + + const displayTitle = isInbox ? t('inbox.title') : title; + + const items: MenuProps['items'] = [ + { + icon: , + key: 'share', + label: t('share', { ns: 'common' }), + onClick: () => setOpen(true), + }, + !isInbox && { + icon: , + key: 'settings', + label: t('header.session', { ns: 'setting' }), + onClick: () => router.push(pathString('/chat/settings', { hash: location.hash })), + }, + ].filter(Boolean) as MenuProps['items']; + + return ( + } + onBackClick={() => router.push('/chat')} + right={ + <> + toggleConfig()} size={MOBILE_HEADER_ICON_SIZE} /> + + + + + + } + showBackButton + /> + ); +}); + +export default MobileHeader; diff --git a/src/app/chat/(mobile)/features/ChatInput/Files.tsx b/src/app/chat/(mobile)/features/ChatInput/Files.tsx new file mode 100644 index 0000000000000..9b5439d32ec13 --- /dev/null +++ b/src/app/chat/(mobile)/features/ChatInput/Files.tsx @@ -0,0 +1,17 @@ +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import FileList from '@/app/chat/components/FileList'; +import { useFileStore } from '@/store/files'; + +const Files = memo(() => { + const inputFilesList = useFileStore((s) => s.inputFilesList); + + return ( + + + + ); +}); + +export default Files; diff --git a/src/app/chat/(mobile)/features/ChatInput/Mobile.tsx b/src/app/chat/(mobile)/features/ChatInput/Mobile.tsx new file mode 100644 index 0000000000000..69a96286940ab --- /dev/null +++ b/src/app/chat/(mobile)/features/ChatInput/Mobile.tsx @@ -0,0 +1,41 @@ +import { createStyles } from 'antd-style'; +import { rgba } from 'polished'; +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import ActionBar from '@/app/chat/features/ChatInput/ActionBar'; +import InputAreaInner from '@/app/chat/features/ChatInput/InputAreaInner'; +import STT from '@/app/chat/features/ChatInput/STT'; +import SaveTopic from '@/app/chat/features/ChatInput/Topic'; + +import SendButton from './SendButton'; + +const useStyles = createStyles(({ css, token }) => { + return { + container: css` + padding: 12px 0; + background: ${token.colorBgLayout}; + border-top: 1px solid ${rgba(token.colorBorder, 0.25)}; + `, + inner: css` + padding: 0 8px; + `, + }; +}); + +const ChatInputArea = memo(() => { + const { styles } = useStyles(); + + return ( + + } /> + + + + + + + ); +}); + +export default ChatInputArea; diff --git a/src/app/chat/(mobile)/features/ChatInput/SendButton.tsx b/src/app/chat/(mobile)/features/ChatInput/SendButton.tsx new file mode 100644 index 0000000000000..fbfdff2902871 --- /dev/null +++ b/src/app/chat/(mobile)/features/ChatInput/SendButton.tsx @@ -0,0 +1,30 @@ +import { Icon } from '@lobehub/ui'; +import { Button } from 'antd'; +import { Loader2, SendHorizonal } from 'lucide-react'; +import { memo } from 'react'; + +import { useSendMessage } from '@/app/chat/features/ChatInput/useSend'; +import { useSessionStore } from '@/store/session'; + +const SendButton = memo(() => { + const [loading, onStop] = useSessionStore((s) => [!!s.chatLoadingId, s.stopGenerateMessage]); + + const handleSend = useSendMessage(); + + return loading ? ( + + )} + + + ); +}); + +export default Inner; diff --git a/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx b/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx new file mode 100644 index 0000000000000..183d8c555a300 --- /dev/null +++ b/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx @@ -0,0 +1,155 @@ +import { SiOpenai } from '@icons-pack/react-simple-icons'; +import { Avatar, ChatHeaderTitle, Logo, Markdown, Tag } from '@lobehub/ui'; +import { Button, SegmentedProps } from 'antd'; +import dayjs from 'dayjs'; +import { domToJpeg, domToPng, domToSvg, domToWebp } from 'modern-screenshot'; +import { memo, useCallback, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; +import ChatList from 'src/app/chat/features/Conversation/ChatList'; + +import pkg from '@/../package.json'; +import { useSessionStore } from '@/store/session'; +import { agentSelectors, sessionSelectors } from '@/store/session/selectors'; + +import PluginTag from '../../ChatHeader/PluginTag'; +import { useStyles } from './style'; + +export enum ImageType { + JPG = 'jpg', + PNG = 'png', + SVG = 'svg', + WEBP = 'webp', +} + +export const imageTypeOptions: SegmentedProps['options'] = [ + { + label: 'JPG', + value: ImageType.JPG, + }, + { + label: 'PNG', + value: ImageType.PNG, + }, + { + label: 'SVG', + value: ImageType.SVG, + }, + { + label: 'WEBP', + value: ImageType.WEBP, + }, +]; + +interface PreviewProps { + imageType: ImageType; + withBackground: boolean; + withFooter: boolean; + withSystemRole: boolean; +} + +const Preview = memo(({ withSystemRole, imageType, withBackground, withFooter }) => { + const [loading, setLoading] = useState(false); + const [isInbox, title, description, avatar, backgroundColor, model, plugins, systemRole] = + useSessionStore((s) => [ + sessionSelectors.isInboxSession(s), + agentSelectors.currentAgentTitle(s), + agentSelectors.currentAgentDescription(s), + agentSelectors.currentAgentAvatar(s), + agentSelectors.currentAgentBackgroundColor(s), + agentSelectors.currentAgentModel(s), + agentSelectors.currentAgentPlugins(s), + agentSelectors.currentAgentSystemRole(s), + ]); + const { t } = useTranslation('chat'); + const { styles } = useStyles(withBackground); + + const displayTitle = isInbox ? t('inbox.title') : title; + const displayDesc = isInbox ? t('inbox.desc') : description; + + const handleDownload = useCallback(async () => { + setLoading(true); + try { + let screenshotFn: any; + switch (imageType) { + case ImageType.JPG: { + screenshotFn = domToJpeg; + break; + } + case ImageType.PNG: { + screenshotFn = domToPng; + break; + } + case ImageType.SVG: { + screenshotFn = domToSvg; + break; + } + case ImageType.WEBP: { + screenshotFn = domToWebp; + break; + } + } + + const dataUrl = await screenshotFn(document.querySelector('#preview') as HTMLDivElement, { + features: { + // 不启用移除控制符,否则会导致 safari emoji 报错 + removeControlCharacter: false, + }, + scale: 2, + }); + const link = document.createElement('a'); + link.download = `ChatGPT Power_${title}_${dayjs().format('YYYY-MM-DD')}.${imageType}`; + link.href = dataUrl; + link.click(); + setLoading(false); + } catch (error) { + console.error('Failed to download image', error); + setLoading(false); + } + }, [imageType, title]); + + return ( + <> +
+
+ +
+ + + + }>{model} + {plugins?.length > 0 && } + + } + title={displayTitle} + /> + + {withSystemRole && systemRole && ( +
+ {systemRole} +
+ )} +
+ + {withFooter ? ( + + +
{pkg.homepage}
+
+ ) : ( +
+ )} + +
+
+ + + ); +}); + +export default Preview; diff --git a/src/app/chat/features/ChatHeader/ShareButton/index.tsx b/src/app/chat/features/ChatHeader/ShareButton/index.tsx new file mode 100644 index 0000000000000..3eaa9f8c677c3 --- /dev/null +++ b/src/app/chat/features/ChatHeader/ShareButton/index.tsx @@ -0,0 +1,51 @@ +import { ActionIcon, Modal } from '@lobehub/ui'; +import { Share2 } from 'lucide-react'; +import dynamic from 'next/dynamic'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import useMergeState from 'use-merge-value'; + +import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens'; +import { useSessionStore } from '@/store/session'; + +const Inner = dynamic(() => import('./Inner')); +interface ShareButtonProps { + mobile?: boolean; + open?: boolean; + setOpen?: (open: boolean) => void; +} + +const ShareButton = memo(({ mobile, setOpen, open }) => { + const [isModalOpen, setIsModalOpen] = useMergeState(false, { + defaultValue: false, + onChange: setOpen, + value: open, + }); + const { t } = useTranslation('common'); + const [shareLoading] = useSessionStore((s) => [s.shareLoading]); + + return ( + <> + {!mobile && ( + setIsModalOpen(true)} + size={DESKTOP_HEADER_ICON_SIZE} + title={t('share')} + /> + )} + setIsModalOpen(false)} + open={isModalOpen} + title={t('share')} + > + + + + ); +}); + +export default ShareButton; diff --git a/src/app/chat/features/ChatHeader/ShareButton/style.ts b/src/app/chat/features/ChatHeader/ShareButton/style.ts new file mode 100644 index 0000000000000..b590e5d9d5f0b --- /dev/null +++ b/src/app/chat/features/ChatHeader/ShareButton/style.ts @@ -0,0 +1,71 @@ +import { createStyles } from 'antd-style'; + +export const useStyles = createStyles(({ css, token, stylish, cx }, withBackground: boolean) => ({ + background: css` + padding: 24px; + + background-color: ${token.colorBgLayout}; + background-image: url('/images/screenshot_background.webp'); + background-position: center; + background-size: 120% 120%; + `, + container: cx( + withBackground && + css` + overflow: hidden; + border: 2px solid ${token.colorBorder}; + border-radius: ${token.borderRadiusLG}px; + `, + + css` + background: ${token.colorBgLayout}; + `, + ), + footer: css` + padding: 16px; + border-top: 1px solid ${token.colorBorder}; + `, + header: css` + margin-bottom: -24px; + padding: 16px; + background: ${token.colorBgContainer}; + border-bottom: 1px solid ${token.colorBorder}; + `, + markdown: stylish.markdownInChat, + preview: cx( + stylish.noScrollbar, + css` + overflow: hidden scroll; + + width: 100%; + max-height: 40vh; + + background: ${token.colorBgLayout}; + border: 1px solid ${token.colorBorder}; + border-radius: ${token.borderRadiusLG}px; + + * { + pointer-events: none; + overflow: hidden; + + ::-webkit-scrollbar { + width: 0 !important; + height: 0 !important; + } + } + `, + ), + role: css` + margin-top: 12px; + padding-top: 12px; + opacity: 0.75; + border-top: 1px dashed ${token.colorBorderSecondary}; + + * { + font-size: 12px !important; + } + `, + url: css` + color: ${token.colorTextDescription}; + `, +})); diff --git a/src/app/chat/features/ChatInput/ActionBar/Clear.tsx b/src/app/chat/features/ChatInput/ActionBar/Clear.tsx new file mode 100644 index 0000000000000..34a6b7790fb63 --- /dev/null +++ b/src/app/chat/features/ChatInput/ActionBar/Clear.tsx @@ -0,0 +1,48 @@ +import { ActionIcon } from '@lobehub/ui'; +import { Popconfirm } from 'antd'; +import { Eraser } from 'lucide-react'; +import { memo, useCallback } from 'react'; +import { useHotkeys } from 'react-hotkeys-hook'; +import { useTranslation } from 'react-i18next'; + +import HotKeys from '@/components/HotKeys'; +import { CLEAN_MESSAGE_KEY, PREFIX_KEY } from '@/const/hotkeys'; +import { useFileStore } from '@/store/files'; +import { useSessionStore } from '@/store/session'; + +const Clear = memo(() => { + const { t } = useTranslation('setting'); + const [clearMessage] = useSessionStore((s) => [s.clearMessage]); + const [clearImageList] = useFileStore((s) => [s.clearImageList]); + const hotkeys = [PREFIX_KEY, CLEAN_MESSAGE_KEY].join('+'); + + const resetConversation = useCallback(() => { + clearMessage(); + clearImageList(); + }, []); + + useHotkeys(hotkeys, resetConversation, { + preventDefault: true, + }); + + return ( + { + resetConversation(); + }} + placement={'topRight'} + title={t('confirmClearCurrentMessages', { ns: 'chat' })} + > + ) as any} + /> + + ); +}); + +export default Clear; diff --git a/src/app/chat/features/ChatInput/ActionBar/FileUpload.tsx b/src/app/chat/features/ChatInput/ActionBar/FileUpload.tsx new file mode 100644 index 0000000000000..256dfbecfcc5e --- /dev/null +++ b/src/app/chat/features/ChatInput/ActionBar/FileUpload.tsx @@ -0,0 +1,53 @@ +import { ActionIcon, Icon } from '@lobehub/ui'; +import { Upload } from 'antd'; +import { useTheme } from 'antd-style'; +import { LucideImage, LucideLoader2 } from 'lucide-react'; +import { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Center } from 'react-layout-kit'; + +import { useFileStore } from '@/store/files'; +import { useSessionStore } from '@/store/session'; +import { agentSelectors } from '@/store/session/selectors'; + +const FileUpload = memo(() => { + const { t } = useTranslation('chat'); + const [loading, setLoading] = useState(false); + const theme = useTheme(); + const upload = useFileStore((s) => s.uploadFile); + + const canUpload = useSessionStore(agentSelectors.modelHasVisionAbility); + + if (!canUpload) return null; + + return ( + { + setLoading(true); + + await upload(file); + + setLoading(false); + return false; + }} + multiple={true} + showUploadList={false} + > + {loading ? ( +
+ +
+ ) : ( + + )} +
+ ); +}); + +export default FileUpload; diff --git a/src/app/chat/features/ChatInput/ActionBar/History.tsx b/src/app/chat/features/ChatInput/ActionBar/History.tsx new file mode 100644 index 0000000000000..ca42efe67ca11 --- /dev/null +++ b/src/app/chat/features/ChatInput/ActionBar/History.tsx @@ -0,0 +1,64 @@ +import { ActionIcon, SliderWithInput } from '@lobehub/ui'; +import { Popover, Switch } from 'antd'; +import { Timer, TimerOff } from 'lucide-react'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import { useSessionStore } from '@/store/session'; +import { agentSelectors } from '@/store/session/selectors'; + +const History = memo(() => { + const { t } = useTranslation('setting'); + + const [historyCount, unlimited, updateAgentConfig] = useSessionStore((s) => { + const config = agentSelectors.currentAgentConfig(s); + return [config.historyCount, !config.enableHistoryCount, s.updateAgentConfig]; + }); + + return ( + + { + updateAgentConfig({ historyCount: v }); + }} + step={1} + style={{ width: 160 }} + value={historyCount} + /> + + { + updateAgentConfig({ enableHistoryCount: !checked }); + }} + size={'small'} + /> + {t('settingChat.enableHistoryCount.alias')} + + + } + placement={'top'} + trigger={'click'} + > + + + ); +}); + +export default History; diff --git a/src/app/chat/features/ChatInput/ActionBar/ModelSwitch.tsx b/src/app/chat/features/ChatInput/ActionBar/ModelSwitch.tsx new file mode 100644 index 0000000000000..8dfc2675179aa --- /dev/null +++ b/src/app/chat/features/ChatInput/ActionBar/ModelSwitch.tsx @@ -0,0 +1,41 @@ +import { ActionIcon } from '@lobehub/ui'; +import { Dropdown } from 'antd'; +import { BrainCog } from 'lucide-react'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { settingsSelectors, useGlobalStore } from '@/store/global'; +import { useSessionStore } from '@/store/session'; +import { agentSelectors } from '@/store/session/selectors'; +import { LanguageModel } from '@/types/llm'; + +const ModelSwitch = memo(() => { + const { t } = useTranslation('setting'); + + const [model, updateAgentConfig] = useSessionStore((s) => { + return [agentSelectors.currentAgentModel(s), s.updateAgentConfig]; + }); + + const modelList = useGlobalStore(settingsSelectors.modelList); + + return ( + ({ key: i, label: i })), + onClick: (e) => { + updateAgentConfig({ model: e.key as LanguageModel }); + }, + style: { + maxHeight: 400, + overflow: 'scroll', + }, + }} + trigger={['click']} + > + + + ); +}); + +export default ModelSwitch; diff --git a/src/app/chat/features/ChatInput/ActionBar/Temperature.tsx b/src/app/chat/features/ChatInput/ActionBar/Temperature.tsx new file mode 100644 index 0000000000000..31633b8b7cd62 --- /dev/null +++ b/src/app/chat/features/ChatInput/ActionBar/Temperature.tsx @@ -0,0 +1,47 @@ +import { ActionIcon, SliderWithInput } from '@lobehub/ui'; +import { Popover } from 'antd'; +import { Thermometer } from 'lucide-react'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { useSessionStore } from '@/store/session'; +import { agentSelectors } from '@/store/session/selectors'; + +const Temperature = memo(() => { + const { t } = useTranslation('setting'); + + const [temperature, updateAgentConfig] = useSessionStore((s) => { + const config = agentSelectors.currentAgentConfig(s); + return [config.params.temperature, s.updateAgentConfig]; + }); + + return ( + { + updateAgentConfig({ params: { temperature: v } }); + }} + size={'small'} + step={0.1} + style={{ width: 160 }} + value={temperature} + /> + } + placement={'top'} + trigger={'click'} + > + + + ); +}); + +export default Temperature; diff --git a/src/app/chat/features/ChatInput/ActionBar/Token/TokenTag.tsx b/src/app/chat/features/ChatInput/ActionBar/Token/TokenTag.tsx new file mode 100644 index 0000000000000..f04741e194933 --- /dev/null +++ b/src/app/chat/features/ChatInput/ActionBar/Token/TokenTag.tsx @@ -0,0 +1,42 @@ +import { TokenTag, Tooltip } from '@lobehub/ui'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { ModelTokens } from '@/const/modelTokens'; +import { useTokenCount } from '@/hooks/useTokenCount'; +import { useSessionStore } from '@/store/session'; +import { agentSelectors, chatSelectors } from '@/store/session/selectors'; +import { LanguageModel } from '@/types/llm'; + +const Token = memo(() => { + const { t } = useTranslation('chat'); + + const [input, messageString, systemRole, model] = useSessionStore((s) => [ + s.inputMessage, + chatSelectors.chatsMessageString(s), + agentSelectors.currentAgentSystemRole(s), + agentSelectors.currentAgentModel(s) as LanguageModel, + ]); + const inputTokenCount = useTokenCount(input); + + const systemRoleToken = useTokenCount(systemRole); + const chatsToken = useTokenCount(messageString); + + const totalToken = systemRoleToken + chatsToken; + return ( + + + + ); +}); + +export default Token; diff --git a/src/app/chat/features/ChatInput/ActionBar/Token/index.tsx b/src/app/chat/features/ChatInput/ActionBar/Token/index.tsx new file mode 100644 index 0000000000000..c139065e3d954 --- /dev/null +++ b/src/app/chat/features/ChatInput/ActionBar/Token/index.tsx @@ -0,0 +1,21 @@ +import dynamic from 'next/dynamic'; +import { Suspense, memo } from 'react'; + +import { useSessionStore } from '@/store/session'; +import { agentSelectors } from '@/store/session/selectors'; + +const LargeTokenContent = dynamic(() => import('./TokenTag'), { ssr: false }); + +const Token = memo(() => { + const [showTokenTag] = useSessionStore((s) => [agentSelectors.showTokenTag(s)]); + + return ( + showTokenTag && ( + + + + ) + ); +}); + +export default Token; diff --git a/src/app/chat/features/ChatInput/ActionBar/config.ts b/src/app/chat/features/ChatInput/ActionBar/config.ts new file mode 100644 index 0000000000000..45e86a5048b56 --- /dev/null +++ b/src/app/chat/features/ChatInput/ActionBar/config.ts @@ -0,0 +1,31 @@ +import STT from '../STT'; +import Clear from './Clear'; +import FileUpload from './FileUpload'; +import History from './History'; +import ModelSwitch from './ModelSwitch'; +import Temperature from './Temperature'; +import Token from './Token'; + +export const actionMap = { + clear: Clear, + fileUpload: FileUpload, + history: History, + model: ModelSwitch, + stt: STT, + temperature: Temperature, + token: Token, +} as const; + +type ActionMap = typeof actionMap; + +export type ActionKeys = keyof ActionMap; + +type getActionList = (mobile?: boolean) => ActionKeys[]; + +// we can make these action lists configurable in the future +export const getLeftActionList: getActionList = (mobile) => + ['model', 'fileUpload', 'temperature', 'history', !mobile && 'stt', 'token'].filter( + Boolean, + ) as ActionKeys[]; + +export const getRightActionList: getActionList = () => ['clear'].filter(Boolean) as ActionKeys[]; diff --git a/src/app/chat/features/ChatInput/ActionBar/index.tsx b/src/app/chat/features/ChatInput/ActionBar/index.tsx new file mode 100644 index 0000000000000..e257261ae72f1 --- /dev/null +++ b/src/app/chat/features/ChatInput/ActionBar/index.tsx @@ -0,0 +1,59 @@ +import { ReactNode, memo, useMemo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import { ActionKeys, actionMap, getLeftActionList, getRightActionList } from './config'; + +const RenderActionList = ({ dataSource }: { dataSource: ActionKeys[] }) => ( + <> + {dataSource.map((key) => { + const Render = actionMap[key]; + return ; + })} + +); + +export interface ActionBarProps { + leftAreaEndRender?: ReactNode; + leftAreaStartRender?: ReactNode; + mobile?: boolean; + padding?: number | string; + rightAreaEndRender?: ReactNode; + rightAreaStartRender?: ReactNode; +} + +const ActionBar = memo( + ({ + padding = '0 16px', + mobile, + rightAreaStartRender, + rightAreaEndRender, + leftAreaStartRender, + leftAreaEndRender, + }) => { + const leftActionList = useMemo(() => getLeftActionList(mobile), [mobile]); + const rightActionList = useMemo(() => getRightActionList(mobile), [mobile]); + + return ( + + + {leftAreaStartRender} + + {leftAreaEndRender} + + + {rightAreaStartRender} + + {rightAreaEndRender} + + + ); + }, +); + +export default ActionBar; diff --git a/src/app/chat/features/ChatInput/InputAreaInner/index.tsx b/src/app/chat/features/ChatInput/InputAreaInner/index.tsx new file mode 100644 index 0000000000000..938e91a922539 --- /dev/null +++ b/src/app/chat/features/ChatInput/InputAreaInner/index.tsx @@ -0,0 +1,57 @@ +import { Input, TextArea } from '@lobehub/ui'; +import { memo, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { useSessionStore } from '@/store/session'; + +import { useSendMessage } from '../useSend'; + +export interface InputAreaInnerProps { + className?: string; + mobile?: boolean; +} + +const InputAreaInner = memo(({ className, mobile }) => { + const { t } = useTranslation('chat'); + const isChineseInput = useRef(false); + + const [loading, message, updateInputMessage] = useSessionStore((s) => [ + !!s.chatLoadingId, + s.inputMessage, + s.updateInputMessage, + ]); + + const handleSend = useSendMessage(); + + const Render = mobile ? Input : TextArea; + + return ( + { + updateInputMessage(e.target.value); + }} + onChange={(e) => { + updateInputMessage(e.target.value); + }} + onCompositionEnd={() => { + isChineseInput.current = false; + }} + onCompositionStart={() => { + isChineseInput.current = true; + }} + onPressEnter={(e) => { + if (!loading && !e.shiftKey && !isChineseInput.current) { + e.preventDefault(); + handleSend(); + } + }} + placeholder={t('sendPlaceholder')} + resize={false} + type={mobile ? 'block' : 'pure'} + value={message} + /> + ); +}); + +export default InputAreaInner; diff --git a/src/app/chat/features/ChatInput/STT/index.tsx b/src/app/chat/features/ChatInput/STT/index.tsx new file mode 100644 index 0000000000000..981bdba6ab9f7 --- /dev/null +++ b/src/app/chat/features/ChatInput/STT/index.tsx @@ -0,0 +1,146 @@ +import { ActionIcon, Alert, Highlighter, Icon } from '@lobehub/ui'; +import { Button, Dropdown } from 'antd'; +import { createStyles } from 'antd-style'; +import { Mic, MicOff } from 'lucide-react'; +import { memo, useCallback, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import { useSTT } from '@/hooks/useSTT'; +import { useSessionStore } from '@/store/session'; +import { ChatMessageError } from '@/types/chatMessage'; +import { getMessageError } from '@/utils/fetch'; + +const useStyles = createStyles(({ css, token }) => ({ + recording: css` + width: 8px; + height: 8px; + background: ${token.colorError}; + border-radius: 50%; + `, +})); + +const STT = memo<{ mobile?: boolean }>(({ mobile }) => { + const [error, setError] = useState(); + const { t } = useTranslation('chat'); + const { styles } = useStyles(); + + const [loading, updateInputMessage] = useSessionStore((s) => [ + !!s.chatLoadingId, + s.updateInputMessage, + ]); + + const setDefaultError = useCallback( + (err?: any) => { + setError({ body: err, message: t('stt.responseError', { ns: 'error' }), type: 500 }); + }, + [t], + ); + + const { start, isLoading, stop, formattedTime, time, response, isRecording } = useSTT({ + onError: (err) => { + stop(); + setDefaultError(err); + }, + onErrorRetry: (err) => { + stop(); + setDefaultError(err); + }, + onSuccess: async () => { + if (!response) return; + if (response.status === 200) return; + const message = await getMessageError(response); + if (message) { + setError(message); + } else { + setDefaultError(); + } + stop(); + }, + onTextChange: (text) => { + if (loading) stop(); + if (text) updateInputMessage(text); + }, + }); + + const icon = isLoading ? MicOff : Mic; + const Render: any = !mobile ? ActionIcon : Button; + const iconRender: any = !mobile ? icon : ; + const desc = t('stt.action'); + + const handleTriggerStartStop = useCallback(() => { + if (loading) return; + if (!isLoading) { + start(); + } else { + stop(); + } + }, [loading, isLoading, start, stop]); + + const handleCloseError = useCallback(() => { + setError(undefined); + stop(); + }, [stop]); + + const handleRetry = useCallback(() => { + setError(undefined); + start(); + }, [start]); + + return ( + ( + + {t('retry', { ns: 'common' })} + + } + closable + extra={ + error.body && ( + + {JSON.stringify(error.body, null, 2)} + + ) + } + message={error.message} + onClose={handleCloseError} + style={{ alignItems: 'center' }} + type="error" + /> + ) + : undefined + } + menu={{ + activeKey: 'time', + items: [ + { + key: 'time', + label: ( + +
+ {time > 0 ? formattedTime : t(isRecording ? 'stt.loading' : 'stt.prettifying')} + + ), + }, + ], + }} + open={!!error || isRecording || isLoading} + placement={mobile ? 'topRight' : 'top'} + trigger={['click']} + > + + + ); +}); + +export default STT; diff --git a/src/app/chat/features/ChatInput/Topic/index.tsx b/src/app/chat/features/ChatInput/Topic/index.tsx new file mode 100644 index 0000000000000..b6d2df25bda96 --- /dev/null +++ b/src/app/chat/features/ChatInput/Topic/index.tsx @@ -0,0 +1,37 @@ +import { ActionIcon, Icon, Tooltip } from '@lobehub/ui'; +import { Button } from 'antd'; +import { LucideGalleryVerticalEnd, LucideMessageSquarePlus } from 'lucide-react'; +import { memo } from 'react'; +import { useHotkeys } from 'react-hotkeys-hook'; +import { useTranslation } from 'react-i18next'; + +import HotKeys from '@/components/HotKeys'; +import { PREFIX_KEY, SAVE_TOPIC_KEY } from '@/const/hotkeys'; +import { useSessionStore } from '@/store/session'; + +const SaveTopic = memo<{ mobile?: boolean }>(({ mobile }) => { + const { t } = useTranslation('chat'); + const [hasTopic, openNewTopicOrSaveTopic] = useSessionStore((s) => [ + !!s.activeTopicId, + s.openNewTopicOrSaveTopic, + ]); + + const icon = hasTopic ? LucideMessageSquarePlus : LucideGalleryVerticalEnd; + const Render = mobile ? ActionIcon : Button; + const iconRender: any = mobile ? icon : ; + const desc = t(hasTopic ? 'topic.openNewTopic' : 'topic.saveCurrentMessages'); + + const hotkeys = [PREFIX_KEY, SAVE_TOPIC_KEY].join('+'); + useHotkeys(hotkeys, openNewTopicOrSaveTopic, { + enableOnFormTags: true, + preventDefault: true, + }); + + return ( + }> + + + ); +}); + +export default SaveTopic; diff --git a/src/app/chat/features/ChatInput/useSend.ts b/src/app/chat/features/ChatInput/useSend.ts new file mode 100644 index 0000000000000..cc3f70495d21b --- /dev/null +++ b/src/app/chat/features/ChatInput/useSend.ts @@ -0,0 +1,21 @@ +import { useCallback } from 'react'; + +import { filesSelectors, useFileStore } from '@/store/files'; +import { useSessionStore } from '@/store/session'; + +export const useSendMessage = () => { + const [sendMessage, updateInputMessage] = useSessionStore((s) => [ + s.sendMessage, + s.updateInputMessage, + ]); + + return useCallback(() => { + const store = useSessionStore.getState(); + if (!!store.chatLoadingId) return; + const imageList = filesSelectors.imageUrlOrBase64List(useFileStore.getState()); + + sendMessage(store.inputMessage, imageList); + updateInputMessage(''); + useFileStore.getState().clearImageList(); + }, []); +}; diff --git a/src/app/chat/features/Conversation/ChatList/Actions/Assistant.tsx b/src/app/chat/features/Conversation/ChatList/Actions/Assistant.tsx new file mode 100644 index 0000000000000..ac74ce5bda56a --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Actions/Assistant.tsx @@ -0,0 +1,22 @@ +import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui'; +import { memo } from 'react'; + +import { ErrorActionsBar } from './Error'; +import { useCustomActions } from './customAction'; + +export const AssistantActionsBar: RenderAction = memo(({ text, id, onActionClick, error }) => { + const { regenerate, edit, copy, divider, del } = useChatListActionsBar(text); + const { translate, tts } = useCustomActions(); + if (id === 'default') return; + + if (error) return ; + + return ( + + ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Actions/Error.tsx b/src/app/chat/features/Conversation/ChatList/Actions/Error.tsx new file mode 100644 index 0000000000000..4907d6deb9388 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Actions/Error.tsx @@ -0,0 +1,9 @@ +import { ActionIconGroup, useChatListActionsBar } from '@lobehub/ui'; +import { ActionsBarProps } from '@lobehub/ui/es/ChatList/ActionsBar'; +import { memo } from 'react'; + +export const ErrorActionsBar = memo(({ text, onActionClick }) => { + const { regenerate, del } = useChatListActionsBar(text); + + return ; +}); diff --git a/src/app/chat/features/Conversation/ChatList/Actions/Fallback.tsx b/src/app/chat/features/Conversation/ChatList/Actions/Fallback.tsx new file mode 100644 index 0000000000000..33f15c4bb3eaa --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Actions/Fallback.tsx @@ -0,0 +1,9 @@ +import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui'; +import { memo } from 'react'; + +export const DefaultActionsBar: RenderAction = memo(({ text, onActionClick }) => { + const { del } = useChatListActionsBar(text); + return ( + + ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Actions/Function.tsx b/src/app/chat/features/Conversation/ChatList/Actions/Function.tsx new file mode 100644 index 0000000000000..e05f3fe28881a --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Actions/Function.tsx @@ -0,0 +1,14 @@ +import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui'; +import { memo } from 'react'; + +export const FunctionActionsBar: RenderAction = memo(({ text, onActionClick }) => { + const { regenerate, divider, del } = useChatListActionsBar(text); + return ( + + ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Actions/User.tsx b/src/app/chat/features/Conversation/ChatList/Actions/User.tsx new file mode 100644 index 0000000000000..277fefedd2362 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Actions/User.tsx @@ -0,0 +1,18 @@ +import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui'; +import { memo } from 'react'; + +import { useCustomActions } from './customAction'; + +export const UserActionsBar: RenderAction = memo(({ text, onActionClick }) => { + const { regenerate, edit, copy, divider, del } = useChatListActionsBar(text); + const { translate, tts } = useCustomActions(); + + return ( + + ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Actions/customAction.ts b/src/app/chat/features/Conversation/ChatList/Actions/customAction.ts new file mode 100644 index 0000000000000..ef900f2ad2452 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Actions/customAction.ts @@ -0,0 +1,30 @@ +import { ActionIconGroupItems } from '@lobehub/ui/es/ActionIconGroup'; +import { LanguagesIcon, Play } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; + +import { localeOptions } from '@/locales/options'; + +export const useCustomActions = () => { + const { t } = useTranslation('chat'); + + const translate = { + children: localeOptions.map((i) => ({ + key: i.value, + label: t(`lang.${i.value}`, { ns: 'common' }), + })), + icon: LanguagesIcon, + key: 'translate', + label: t('translate.action'), + } as ActionIconGroupItems; + + const tts = { + icon: Play, + key: 'tts', + label: t('tts.action'), + } as ActionIconGroupItems; + + return { + translate, + tts, + }; +}; diff --git a/src/app/chat/features/Conversation/ChatList/Actions/index.ts b/src/app/chat/features/Conversation/ChatList/Actions/index.ts new file mode 100644 index 0000000000000..cc07d7229f733 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Actions/index.ts @@ -0,0 +1,68 @@ +import { ChatListProps } from '@lobehub/ui'; + +import { useSessionStore } from '@/store/session'; + +import { AssistantActionsBar } from './Assistant'; +import { DefaultActionsBar } from './Fallback'; +import { FunctionActionsBar } from './Function'; +import { UserActionsBar } from './User'; + +export const renderActions: ChatListProps['renderActions'] = { + assistant: AssistantActionsBar, + function: FunctionActionsBar, + system: DefaultActionsBar, + user: UserActionsBar, +}; + +interface ActionsClick { + onClick: () => void; + trigger: boolean; +} + +export const useActionsClick = (): ChatListProps['onActionsClick'] => { + const [deleteMessage, resendMessage, translateMessage, ttsMessage] = useSessionStore((s) => [ + s.deleteMessage, + s.resendMessage, + s.translateMessage, + s.ttsMessage, + ]); + + return (action, { id, error }) => { + const actionsClick: ActionsClick[] = [ + { + onClick: () => { + deleteMessage(id); + }, + trigger: action.key === 'del', + }, + { + onClick: () => { + resendMessage(id); + // if this message is an error message, we need to delete it + if (error) deleteMessage(id); + }, + trigger: action.key === 'regenerate', + }, + { + onClick: () => { + ttsMessage(id); + }, + trigger: action.key === 'tts', + }, + { + onClick: () => { + /** + * @description Click the menu item with translate item, the result is: + * @key 'en-US' + * @keyPath ['en-US','translate'] + */ + const lang = action.keyPath[0]; + translateMessage(id, lang); + }, + trigger: action.keyPath.at(-1) === 'translate', + }, + ]; + + actionsClick.find((item) => item.trigger)?.onClick(); + }; +}; diff --git a/src/app/chat/features/Conversation/ChatList/Error/ApiKeyForm.tsx b/src/app/chat/features/Conversation/ChatList/Error/ApiKeyForm.tsx new file mode 100644 index 0000000000000..15425c858d4f4 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Error/ApiKeyForm.tsx @@ -0,0 +1,85 @@ +import { Icon } from '@lobehub/ui'; +import { Button, Input } from 'antd'; +import { Network } from 'lucide-react'; +import { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Center, Flexbox } from 'react-layout-kit'; + +import { settingsSelectors, useGlobalStore } from '@/store/global'; +import { useSessionStore } from '@/store/session'; + +import { FormAction } from './style'; + +const APIKeyForm = memo<{ id: string }>(({ id }) => { + const { t } = useTranslation('error'); + const [showProxy, setShow] = useState(false); + + const [apiKey, proxyUrl, setConfig] = useGlobalStore((s) => [ + settingsSelectors.openAIAPI(s), + settingsSelectors.openAIProxyUrl(s), + s.setOpenAIConfig, + ]); + + const [resend, deleteMessage] = useSessionStore((s) => [s.resendMessage, s.deleteMessage]); + + return ( +
+ + { + setConfig({ OPENAI_API_KEY: e.target.value }); + }} + placeholder={'sk-*****************************************'} + type={'block'} + value={apiKey} + /> + {showProxy ? ( + { + setConfig({ endpoint: e.target.value }); + }} + placeholder={'https://api.openai.com/v1'} + type={'block'} + value={proxyUrl} + /> + ) : ( + + )} + + + + + +
+ ); +}); + +export default APIKeyForm; diff --git a/src/app/chat/features/Conversation/ChatList/Error/ErrorActionContainer.tsx b/src/app/chat/features/Conversation/ChatList/Error/ErrorActionContainer.tsx new file mode 100644 index 0000000000000..136ae4ee1fd9a --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Error/ErrorActionContainer.tsx @@ -0,0 +1,23 @@ +import { createStyles } from 'antd-style'; +import { ReactNode, memo } from 'react'; +import { Center } from 'react-layout-kit'; + +const useStyles = createStyles(({ css, token }) => ({ + container: css` + background: ${token.colorBgContainer}; + border: 1px solid ${token.colorSplit}; + border-radius: 8px; + `, +})); + +const ErrorActionContainer = memo<{ children: ReactNode }>(({ children }) => { + const { styles } = useStyles(); + + return ( +
+ {children} +
+ ); +}); + +export default ErrorActionContainer; diff --git a/src/app/chat/features/Conversation/ChatList/Error/InvalidAccess.tsx b/src/app/chat/features/Conversation/ChatList/Error/InvalidAccess.tsx new file mode 100644 index 0000000000000..832fc70bca94e --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Error/InvalidAccess.tsx @@ -0,0 +1,84 @@ +import { Icon, RenderErrorMessage } from '@lobehub/ui'; +import { Button, Input, Segmented } from 'antd'; +import { KeySquare, SquareAsterisk } from 'lucide-react'; +import { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import { useGlobalStore } from '@/store/global'; +import { useSessionStore } from '@/store/session'; + +import APIKeyForm from './ApiKeyForm'; +import { ErrorActionContainer, FormAction } from './style'; + +enum Tab { + Api = 'api', + Password = 'password', +} + +const InvalidAccess: RenderErrorMessage['Render'] = memo(({ id }) => { + const { t } = useTranslation('error'); + const [mode, setMode] = useState(Tab.Password); + const [password, setSettings] = useGlobalStore((s) => [s.settings.password, s.setSettings]); + const [resend, deleteMessage] = useSessionStore((s) => [s.resendMessage, s.deleteMessage]); + + return ( + + setMode(value as Tab)} + options={[ + { + icon: , + label: t('password', { ns: 'common' }), + value: Tab.Password, + }, + { icon: , label: 'OpenAI API Key', value: Tab.Api }, + ]} + style={{ width: '100%' }} + value={mode} + /> + + {mode === Tab.Password && ( + <> + + { + setSettings({ password: e.target.value }); + }} + placeholder={t('unlock.password.placeholder')} + type={'block'} + value={password} + /> + + + + + + + )} + {mode === Tab.Api && } + + + ); +}); + +export default InvalidAccess; diff --git a/src/app/chat/features/Conversation/ChatList/Error/OpenAPIKey.tsx b/src/app/chat/features/Conversation/ChatList/Error/OpenAPIKey.tsx new file mode 100644 index 0000000000000..3515db1c7c377 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Error/OpenAPIKey.tsx @@ -0,0 +1,13 @@ +import { RenderErrorMessage } from '@lobehub/ui'; +import { memo } from 'react'; + +import APIKeyForm from './ApiKeyForm'; +import { ErrorActionContainer } from './style'; + +const OpenAPIKey: RenderErrorMessage['Render'] = memo(({ id }) => ( + + + +)); + +export default OpenAPIKey; diff --git a/src/app/chat/features/Conversation/ChatList/Error/OpenAiBizError.tsx b/src/app/chat/features/Conversation/ChatList/Error/OpenAiBizError.tsx new file mode 100644 index 0000000000000..788aacd3c1dbf --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Error/OpenAiBizError.tsx @@ -0,0 +1,36 @@ +import { Highlighter, RenderErrorMessage } from '@lobehub/ui'; +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import OpenAPIKey from './OpenAPIKey'; + +interface OpenAIError { + code: 'invalid_api_key' | string; + message: string; + param?: any; + type: string; +} + +interface OpenAIErrorResponse { + error: OpenAIError; +} + +const OpenAiBizError: RenderErrorMessage['Render'] = memo(({ error, id, ...props }) => { + const errorBody: OpenAIErrorResponse = (error as any)?.body; + + const errorCode = errorBody.error?.code; + + if (errorCode === 'invalid_api_key') + // @ts-ignore + return ; + + return ( + + + {JSON.stringify(errorBody, null, 2)} + + + ); +}); + +export default OpenAiBizError; diff --git a/src/app/chat/features/Conversation/ChatList/Error/Plugin/PluginError.tsx b/src/app/chat/features/Conversation/ChatList/Error/Plugin/PluginError.tsx new file mode 100644 index 0000000000000..fa9977b4a3385 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Error/Plugin/PluginError.tsx @@ -0,0 +1,28 @@ +import { Highlighter, RenderErrorMessage } from '@lobehub/ui'; +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +interface OpenAIError { + code: 'invalid_api_key' | string; + message: string; + param?: any; + type: string; +} + +interface OpenAIErrorResponse { + error: OpenAIError; +} + +const PluginError: RenderErrorMessage['Render'] = memo(({ error, id }) => { + const errorBody: OpenAIErrorResponse = (error as any)?.body; + + return ( + + + {JSON.stringify(errorBody, null, 2)} + + + ); +}); + +export default PluginError; diff --git a/src/app/chat/features/Conversation/ChatList/Error/Plugin/PluginSettings.tsx b/src/app/chat/features/Conversation/ChatList/Error/Plugin/PluginSettings.tsx new file mode 100644 index 0000000000000..3505b51b44189 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Error/Plugin/PluginSettings.tsx @@ -0,0 +1,58 @@ +import { Avatar, RenderErrorMessage } from '@lobehub/ui'; +import { Button, Divider } from 'antd'; +import { useTheme } from 'antd-style'; +import isEqual from 'fast-deep-equal'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Center, Flexbox } from 'react-layout-kit'; + +import PluginSettingsConfig from '@/features/PluginSettings'; +import { pluginHelpers, usePluginStore } from '@/store/plugin'; +import { pluginSelectors } from '@/store/plugin/selectors'; +import { useSessionStore } from '@/store/session'; + +import { ErrorActionContainer, useStyles } from '../style'; + +const PluginSettings: RenderErrorMessage['Render'] = memo(({ id, plugin }) => { + const { styles } = useStyles(); + const { t } = useTranslation('error'); + const theme = useTheme(); + const [resend, deleteMessage] = useSessionStore((s) => [s.resendMessage, s.deleteMessage]); + const pluginIdentifier = plugin?.identifier as string; + const pluginMeta = usePluginStore(pluginSelectors.getPluginMetaById(pluginIdentifier), isEqual); + const manifest = usePluginStore(pluginSelectors.getPluginManifestById(pluginIdentifier), isEqual); + + return ( + +
+ + + {t('pluginSettings.title', { name: pluginHelpers.getPluginTitle(pluginMeta?.meta) })} + + {t('pluginSettings.desc')} + + {manifest.settings && ( + + )} + +
+
+ ); +}); + +export default PluginSettings; diff --git a/src/app/chat/features/Conversation/ChatList/Error/index.tsx b/src/app/chat/features/Conversation/ChatList/Error/index.tsx new file mode 100644 index 0000000000000..98799fa010711 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Error/index.tsx @@ -0,0 +1,72 @@ +import { PluginErrorType } from '@lobehub/chat-plugin-sdk'; +import { ChatListProps } from '@lobehub/ui'; + +import { ChatErrorType } from '@/types/fetch'; + +import InvalidAccess from './InvalidAccess'; +import OpenAPIKey from './OpenAPIKey'; +import OpenAiBizError from './OpenAiBizError'; +import PluginError from './Plugin/PluginError'; +import PluginSettings from './Plugin/PluginSettings'; + +export const renderErrorMessages: ChatListProps['renderErrorMessages'] = { + [PluginErrorType.PluginMarketIndexNotFound]: { + Render: PluginError, + }, + [PluginErrorType.PluginMarketIndexInvalid]: { + Render: PluginError, + }, + [PluginErrorType.PluginMetaInvalid]: { + Render: PluginError, + }, + [PluginErrorType.PluginMetaNotFound]: { + Render: PluginError, + }, + [PluginErrorType.PluginManifestInvalid]: { + Render: PluginError, + }, + [PluginErrorType.PluginManifestNotFound]: { + Render: PluginError, + }, + [PluginErrorType.PluginApiNotFound]: { + Render: PluginError, + }, + [PluginErrorType.PluginApiParamsError]: { + Render: PluginError, + }, + [PluginErrorType.PluginServerError]: { + Render: PluginError, + }, + [PluginErrorType.PluginSettingsInvalid]: { + Render: PluginSettings, + config: { + extraDefaultExpand: true, + extraIsolate: true, + type: 'warning', + }, + }, + [ChatErrorType.InvalidAccessCode]: { + Render: InvalidAccess, + config: { + extraDefaultExpand: true, + extraIsolate: true, + type: 'warning', + }, + }, + [ChatErrorType.NoAPIKey]: { + Render: OpenAPIKey, + config: { + extraDefaultExpand: true, + extraIsolate: true, + type: 'warning', + }, + }, + [ChatErrorType.OpenAIBizError]: { + Render: OpenAiBizError, + config: { + extraDefaultExpand: true, + extraIsolate: true, + type: 'warning', + }, + }, +}; diff --git a/src/app/chat/features/Conversation/ChatList/Error/style.tsx b/src/app/chat/features/Conversation/ChatList/Error/style.tsx new file mode 100644 index 0000000000000..19fef10a4feba --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Error/style.tsx @@ -0,0 +1,45 @@ +import { Avatar } from '@lobehub/ui'; +import { createStyles } from 'antd-style'; +import { ReactNode, memo } from 'react'; +import { Center, Flexbox } from 'react-layout-kit'; + +export const useStyles = createStyles(({ css, token }) => ({ + container: css` + color: ${token.colorText}; + background: ${token.colorBgContainer}; + border: 1px solid ${token.colorSplit}; + border-radius: 8px; + `, + desc: css` + color: ${token.colorTextTertiary}; + text-align: center; + `, +})); + +export const ErrorActionContainer = memo<{ children: ReactNode }>(({ children }) => { + const { styles } = useStyles(); + + return ( +
+ {children} +
+ ); +}); + +export const FormAction = memo<{ + avatar: string; + children: ReactNode; + description: string; + title: string; +}>(({ children, title, description, avatar }) => { + const { styles, theme } = useStyles(); + + return ( +
+ + {title} + {description} + {children} +
+ ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Extras/Assistant.test.tsx b/src/app/chat/features/Conversation/ChatList/Extras/Assistant.test.tsx new file mode 100644 index 0000000000000..cfd18d58281d4 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Extras/Assistant.test.tsx @@ -0,0 +1,86 @@ +import { render, screen } from '@testing-library/react'; +import { Mock, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { useSessionStore } from '@/store/session'; +import { agentSelectors } from '@/store/session/selectors'; +import { ChatMessage } from '@/types/chatMessage'; + +import { AssistantMessageExtra } from './Assistant'; + +// Mock TTS and Translate components +vi.mock('./TTS', () => ({ + default: vi.fn(() =>
TTS Component
), +})); +vi.mock('./Translate', () => ({ + default: vi.fn(() =>
Translate Component
), +})); + +// Mock dependencies +vi.mock('@/store/session', () => ({ + useSessionStore: vi.fn(), +})); +vi.mock('@/store/session/selectors', () => ({ + agentSelectors: { + currentAgentModel: vi.fn(), + }, +})); + +const mockData: ChatMessage = { + content: 'test-content', + createAt: 0, + id: 'abc', + meta: { avatar: '', backgroundColor: '', description: '', tags: [], title: '' }, + role: 'assistant', + updateAt: 0, +}; + +describe('AssistantMessageExtra', () => { + beforeEach(() => { + // Set default mock return values + (useSessionStore as unknown as Mock).mockImplementation(() => ({ + chatLoadingId: null, + })); + (agentSelectors.currentAgentModel as Mock).mockReturnValue('defaultModel'); + }); + + it('should not render content if extra is undefined', async () => { + render(); + expect(screen.queryByText('defaultModel')).toBeNull(); + expect(screen.queryByText('TTS Component')).toBeNull(); + expect(screen.queryByText('Translate Component')).toBeNull(); + }); + + it('should not render content if extra is defined but does not contain fromModel, tts, or translate', async () => { + render(); + expect(screen.queryByText('defaultModel')).toBeNull(); + expect(screen.queryByText('TTS Component')).toBeNull(); + expect(screen.queryByText('Translate Component')).toBeNull(); + }); + + it('should render Tag component if extra.fromModel exists and does not match the current model', async () => { + render(); + + expect(screen.getByText('otherModel')).toBeInTheDocument(); + }); + + it('should render TTS component if extra.fromModel and extra.tts coexist', async () => { + render(); + + expect(screen.getByText('otherModel')).toBeInTheDocument(); + expect(screen.getByText('TTS Component')).toBeInTheDocument(); + }); + + it('should render Translate component if extra.translate exists', async () => { + render(); + expect(screen.getByText('Translate Component')).toBeInTheDocument(); + }); + + it('should receive the correct loading attribute if loading is true for TTS and Translate components', async () => { + (useSessionStore as unknown as Mock).mockImplementation(() => ({ + chatLoadingId: 'test-id', + })); + render(); + expect(screen.getByText('TTS Component')).toBeInTheDocument(); + expect(screen.getByText('Translate Component')).toBeInTheDocument(); + }); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Extras/Assistant.tsx b/src/app/chat/features/Conversation/ChatList/Extras/Assistant.tsx new file mode 100644 index 0000000000000..284a40d80a5d1 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Extras/Assistant.tsx @@ -0,0 +1,49 @@ +import { SiOpenai } from '@icons-pack/react-simple-icons'; +import { RenderMessageExtra, Tag } from '@lobehub/ui'; +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import { useSessionStore } from '@/store/session'; +import { agentSelectors } from '@/store/session/selectors'; +import { ChatMessage } from '@/types/chatMessage'; + +import ExtraContainer from './ExtraContainer'; +import TTS from './TTS'; +import Translate from './Translate'; + +export const AssistantMessageExtra: RenderMessageExtra = memo( + ({ extra, id, content }) => { + const model = useSessionStore(agentSelectors.currentAgentModel); + const loading = useSessionStore((s) => s.chatLoadingId === id); + + const showModelTag = extra?.fromModel && model !== extra?.fromModel; + const showTranslate = !!extra?.translate; + const showTTS = !!extra?.tts; + + const showExtra = showModelTag || showTranslate || showTTS; + + if (!showExtra) return; + + return ( + + {showModelTag && ( +
+ }>{extra?.fromModel as string} +
+ )} +
+ {extra?.tts && ( + + + + )} + {extra?.translate && ( + + + + )} +
+
+ ); + }, +); diff --git a/src/app/chat/features/Conversation/ChatList/Extras/ExtraContainer.tsx b/src/app/chat/features/Conversation/ChatList/Extras/ExtraContainer.tsx new file mode 100644 index 0000000000000..1998662d079af --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Extras/ExtraContainer.tsx @@ -0,0 +1,13 @@ +import { Divider } from 'antd'; +import { PropsWithChildren, memo } from 'react'; + +const ExtraContainer = memo(({ children }) => { + return ( +
+ + {children} +
+ ); +}); + +export default ExtraContainer; diff --git a/src/app/chat/features/Conversation/ChatList/Extras/TTS.tsx b/src/app/chat/features/Conversation/ChatList/Extras/TTS.tsx new file mode 100644 index 0000000000000..98e0b17ddf87d --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Extras/TTS.tsx @@ -0,0 +1,122 @@ +import { AudioPlayer } from '@lobehub/tts/react'; +import { ActionIcon, Alert, Highlighter } from '@lobehub/ui'; +import { Button } from 'antd'; +import { TrashIcon } from 'lucide-react'; +import { memo, useCallback, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import { useTTS } from '@/hooks/useTTS'; +import { useSessionStore } from '@/store/session'; +import { ChatMessageError, ChatTTS } from '@/types/chatMessage'; +import { getMessageError } from '@/utils/fetch'; + +interface TTSProps extends ChatTTS { + content: string; + id: string; + loading?: boolean; +} + +const TTS = memo(({ id, init, content }) => { + const [isStart, setIsStart] = useState(false); + const [error, setError] = useState(); + const { t } = useTranslation('chat'); + + const [ttsMessage, clearTTS] = useSessionStore((s) => [s.ttsMessage, s.clearTTS]); + + const setDefaultError = useCallback( + (err?: any) => { + setError({ body: err, message: t('tts.responseError', { ns: 'error' }), type: 500 }); + }, + [t], + ); + + const { isGlobalLoading, audio, start, stop, response } = useTTS(content, { + onError: (err) => { + stop(); + setDefaultError(err); + }, + onErrorRetry: (err) => { + stop(); + setDefaultError(err); + }, + onSuccess: async () => { + if (!response) return; + if (response.status === 200) return ttsMessage(id, true); + const message = await getMessageError(response); + if (message) { + setError(message); + } else { + setDefaultError(); + } + stop(); + }, + }); + + const handleInitStart = useCallback(() => { + if (isStart) return; + start(); + setIsStart(true); + }, [isStart]); + + const handleDelete = useCallback(() => { + stop(); + clearTTS(id); + }, [stop, id]); + + const handleRetry = useCallback(() => { + setError(undefined); + start(); + }, [start]); + + useEffect(() => { + if (init) return; + handleInitStart(); + }, [init]); + + return ( + + {error ? ( + + {t('retry', { ns: 'common' })} + + } + closable + extra={ + error.body && ( + + {JSON.stringify(error.body, null, 2)} + + ) + } + message={error.message} + onClose={handleDelete} + style={{ alignItems: 'center', width: '100%' }} + type="error" + /> + ) : ( + <> + + + + )} + + ); +}); + +export default TTS; diff --git a/src/app/chat/features/Conversation/ChatList/Extras/Translate.tsx b/src/app/chat/features/Conversation/ChatList/Extras/Translate.tsx new file mode 100644 index 0000000000000..f7610bf1533fd --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Extras/Translate.tsx @@ -0,0 +1,77 @@ +import { ActionIcon, Icon, Markdown, Tag } from '@lobehub/ui'; +import { App } from 'antd'; +import { createStyles } from 'antd-style'; +import copy from 'copy-to-clipboard'; +import { ChevronDown, ChevronUp, ChevronsRight, CopyIcon, TrashIcon } from 'lucide-react'; +import { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import { useSessionStore } from '@/store/session'; +import { ChatTranslate } from '@/types/chatMessage'; + +import BubblesLoading from '../Loading'; + +const useStyles = createStyles(({ stylish }) => ({ + markdown: stylish.markdownInChat, +})); + +interface TranslateProps extends ChatTranslate { + id: string; + loading?: boolean; +} + +const Translate = memo(({ content = '', from, to, id, loading }) => { + const { theme, styles } = useStyles(); + const { t } = useTranslation('common'); + const [show, setShow] = useState(true); + const clearTranslate = useSessionStore((s) => s.clearTranslate); + + const { message } = App.useApp(); + return ( + + +
+ + {from ? t(`lang.${from}` as any) : '...'} + + {t(`lang.${to}` as any)} + +
+ + { + copy(content); + message.success(t('copySuccess')); + }} + size={'small'} + title={t('copy')} + /> + { + clearTranslate(id); + }} + size={'small'} + title={t('translate.clear', { ns: 'chat' })} + /> + { + setShow(!show); + }} + size={'small'} + /> + +
+ {!show ? null : loading && !content ? ( + + ) : ( + {content} + )} +
+ ); +}); + +export default Translate; diff --git a/src/app/chat/features/Conversation/ChatList/Extras/User.tsx b/src/app/chat/features/Conversation/ChatList/Extras/User.tsx new file mode 100644 index 0000000000000..0acc825ab38c2 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Extras/User.tsx @@ -0,0 +1,31 @@ +import { RenderMessageExtra } from '@lobehub/ui'; +import { memo } from 'react'; + +import { useSessionStore } from '@/store/session'; +import { ChatMessage } from '@/types/chatMessage'; + +import ExtraContainer from './ExtraContainer'; +import TTS from './TTS'; +import Translate from './Translate'; + +export const UserMessageExtra: RenderMessageExtra = memo(({ extra, id, content }) => { + const loading = useSessionStore((s) => s.chatLoadingId === id); + + const showExtra = extra?.translate || extra?.tts; + if (!showExtra) return; + + return ( +
+ {extra?.tts && ( + + + + )} + {extra?.translate && ( + + + + )} +
+ ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Extras/index.ts b/src/app/chat/features/Conversation/ChatList/Extras/index.ts new file mode 100644 index 0000000000000..2b7fc63ab8993 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Extras/index.ts @@ -0,0 +1,9 @@ +import { ChatListProps } from '@lobehub/ui'; + +import { AssistantMessageExtra } from './Assistant'; +import { UserMessageExtra } from './User'; + +export const renderMessagesExtra: ChatListProps['renderMessagesExtra'] = { + assistant: AssistantMessageExtra, + user: UserMessageExtra, +}; diff --git a/src/app/chat/features/Conversation/ChatList/Loading.tsx b/src/app/chat/features/Conversation/ChatList/Loading.tsx new file mode 100644 index 0000000000000..adbc08b255331 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Loading.tsx @@ -0,0 +1,53 @@ +import { useTheme } from 'antd-style'; + +const Svg = () => ( + + + + + + + + + + + +); + +const BubblesLoading = () => { + const { colorTextTertiary } = useTheme(); + return ( +
+ +
+ ); +}; + +export default BubblesLoading; diff --git a/src/app/chat/features/Conversation/ChatList/Messages/Assistant.tsx b/src/app/chat/features/Conversation/ChatList/Messages/Assistant.tsx new file mode 100644 index 0000000000000..21ccfd6aa9a6e --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Messages/Assistant.tsx @@ -0,0 +1,22 @@ +import { RenderMessage } from '@lobehub/ui'; +import { memo } from 'react'; + +import { useSessionStore } from '@/store/session'; +import { chatSelectors } from '@/store/session/selectors'; +import { isFunctionMessageAtStart } from '@/utils/message'; + +import Inspector from '../Plugins/Inspector'; +import { DefaultMessage } from './Default'; + +export const AssistantMessage: RenderMessage = memo(({ id, plugin, content, ...props }) => { + const fcProps = useSessionStore(chatSelectors.getFunctionMessageProps({ content, id, plugin })); + + if (!isFunctionMessageAtStart(content)) + return ; + + return ( +
+ +
+ ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Messages/Default.tsx b/src/app/chat/features/Conversation/ChatList/Messages/Default.tsx new file mode 100644 index 0000000000000..b5d71bbe72c8e --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Messages/Default.tsx @@ -0,0 +1,12 @@ +import { RenderMessage } from '@lobehub/ui'; +import { memo } from 'react'; + +import { LOADING_FLAT } from '@/const/message'; + +import BubblesLoading from '../Loading'; + +export const DefaultMessage: RenderMessage = memo(({ id, editableContent, content }) => { + if (content === LOADING_FLAT) return ; + + return
{editableContent}
; +}); diff --git a/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx b/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx new file mode 100644 index 0000000000000..b251ee64b43f5 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx @@ -0,0 +1,34 @@ +import { RenderMessage } from '@lobehub/ui'; +import isEqual from 'fast-deep-equal'; +import { memo, useState } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import { useSessionStore } from '@/store/session'; +import { chatSelectors } from '@/store/session/selectors'; + +import Inspector from '../Plugins/Inspector'; +import PluginRender from '../Plugins/Render'; + +export const FunctionMessage: RenderMessage = memo(({ id, content, plugin, name }) => { + const fcProps = useSessionStore( + chatSelectors.getFunctionMessageProps({ content, id, plugin }), + isEqual, + ); + const [showRender, setShow] = useState(true); + + return ( + + + {showRender && ( + + )} + + ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Messages/User.tsx b/src/app/chat/features/Conversation/ChatList/Messages/User.tsx new file mode 100644 index 0000000000000..f906582fc3675 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Messages/User.tsx @@ -0,0 +1,23 @@ +import { ReactNode, memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import FileList from '@/app/chat/components/FileList'; +import { LOADING_FLAT } from '@/const/message'; +import { ChatMessage } from '@/types/chatMessage'; + +import BubblesLoading from '../Loading'; + +export const UserMessage = memo< + ChatMessage & { + editableContent: ReactNode; + } +>(({ id, editableContent, content, ...res }) => { + if (content === LOADING_FLAT) return ; + + return ( + + {editableContent} + {res.files && } + + ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Messages/index.ts b/src/app/chat/features/Conversation/ChatList/Messages/index.ts new file mode 100644 index 0000000000000..77039d8170086 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Messages/index.ts @@ -0,0 +1,40 @@ +import { ChatListProps } from '@lobehub/ui'; +import { useResponsive } from 'antd-style'; +import { useRouter } from 'next/navigation'; + +import { useGlobalStore } from '@/store/global'; +import { useSessionStore } from '@/store/session'; +import { sessionSelectors } from '@/store/session/slices/session/selectors'; +import { pathString } from '@/utils/url'; + +import { AssistantMessage } from './Assistant'; +import { DefaultMessage } from './Default'; +import { FunctionMessage } from './Function'; +import { UserMessage } from './User'; + +export const renderMessages: ChatListProps['renderMessages'] = { + assistant: AssistantMessage, + default: DefaultMessage, + function: FunctionMessage, + user: UserMessage, +}; + +export const useAvatarsClick = (): ChatListProps['onAvatarsClick'] => { + const [isInbox] = useSessionStore((s) => [sessionSelectors.isInboxSession(s)]); + const [toggleSystemRole] = useGlobalStore((s) => [s.toggleSystemRole]); + const { mobile } = useResponsive(); + const router = useRouter(); + + return (role) => { + switch (role) { + case 'assistant': { + return () => + isInbox + ? router.push('/settings/agent') + : mobile + ? router.push(pathString('/chat/settings', { hash: location.hash })) + : toggleSystemRole(true); + } + } + }; +}; diff --git a/src/app/chat/features/Conversation/ChatList/OTPInput.tsx b/src/app/chat/features/Conversation/ChatList/OTPInput.tsx new file mode 100644 index 0000000000000..e2e2b7f4a68d2 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/OTPInput.tsx @@ -0,0 +1,136 @@ +import { useControllableValue } from 'ahooks'; +import { createStyles } from 'antd-style'; +import React, { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +const useStyles = createStyles( + ({ css, token }) => css` + width: ${token.controlHeight}px; + height: ${token.controlHeight}px; + + font-size: 16px; + color: ${token.colorText}; + text-align: center; + + background: ${token.colorBgContainer}; + border: 1px solid ${token.colorBorder}; + border-radius: 8px; + + &:focus, + &:focus-visible { + border-color: ${token.colorPrimary}; + outline: none; + } + `, +); + +/** + * Let's borrow some props from HTML "input". More info below: + * + * [Pick Documentation](https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys) + * + * [How to extend HTML Elements](https://reacthustle.com/blog/how-to-extend-html-elements-in-react-typescript) + */ +type PartialInputProps = Pick, 'className' | 'style'>; + +interface OtpInputProps extends PartialInputProps { + onChange?: (value: string) => void; + /** + * Number of characters/input for this component + */ + size?: number; + /** + * Validation pattern for each input. + * e.g: /[0-9]{1}/ for digits only or /[0-9a-zA-Z]{1}/ for alphanumeric + */ + validationPattern?: RegExp; + /** + * full value of the otp input, up to {size} characters + */ + value?: string; +} + +const handleKeyUp = (e: React.KeyboardEvent) => { + const current = e.currentTarget; + if (e.key === 'ArrowLeft' || e.key === 'Backspace') { + const prev = current.previousElementSibling as HTMLInputElement | null; + prev?.focus(); + prev?.setSelectionRange(0, 1); + return; + } + + if (e.key === 'ArrowRight') { + const prev = current.nextSibling as HTMLInputElement | null; + prev?.focus(); + prev?.setSelectionRange(0, 1); + return; + } +}; + +const OtpInput = memo((props) => { + const { + //Set the default size to 6 characters + size = 6, + //Default validation is digits + validationPattern = /\d/, + value: outerValue, + onChange, + className, + ...restProps + } = props; + const [value, setValue] = useControllableValue({ onChange, value: outerValue }); + + const { styles, cx } = useStyles(); + // Create an array based on the size. + const arr = Array.from({ length: size }).fill('-'); + + const handleInputChange = (e: React.ChangeEvent, index: number) => { + const elem = e.target; + const val = e.target.value; + + // check if the value is valid + if (!validationPattern.test(val) && val !== '') return; + + // change the value using onChange props + const valueArr = value?.split('') || []; + valueArr[index] = val; + const newVal = valueArr.join('').slice(0, 6); + setValue(newVal); + + //focus the next element if there's a value + if (val) { + const next = elem.nextElementSibling as HTMLInputElement | null; + next?.focus(); + } + }; + + const handlePaste = (e: React.ClipboardEvent) => { + e.preventDefault(); + const val = e.clipboardData.getData('text').slice(0, Math.max(0, size)); + + setValue(val); + }; + + return ( + + {arr.map((_, index) => { + return ( + handleInputChange(e, index)} + onKeyUp={handleKeyUp} + onPaste={handlePaste} + pattern={validationPattern.source} + type="text" + value={value?.at(index) ?? ''} + /> + ); + })} + + ); +}); + +export default OtpInput; diff --git a/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/PluginResultJSON.tsx b/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/PluginResultJSON.tsx new file mode 100644 index 0000000000000..10c3974683138 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/PluginResultJSON.tsx @@ -0,0 +1,24 @@ +import { Highlighter } from '@lobehub/ui'; +import { memo } from 'react'; + +export interface FunctionMessageProps { + content: string; +} + +const PluginResult = memo(({ content }) => { + let data; + + try { + data = JSON.stringify(JSON.parse(content), null, 2); + } catch { + data = content; + } + + return ( + + {data} + + ); +}); + +export default PluginResult; diff --git a/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/Settings.tsx b/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/Settings.tsx new file mode 100644 index 0000000000000..068ff05b3843c --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/Settings.tsx @@ -0,0 +1,37 @@ +import { ActionIcon } from '@lobehub/ui'; +import { LucideSettings } from 'lucide-react'; +import { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import PluginSettingsModal from '@/features/PluginSettingsModal'; +import { usePluginStore } from '@/store/plugin'; +import { pluginSelectors } from '@/store/plugin/selectors'; + +const Settings = memo<{ id: string }>(({ id }) => { + const item = usePluginStore(pluginSelectors.getPluginManifestById(id)); + const [open, setOpen] = useState(false); + const { t } = useTranslation('plugin'); + return ( + item?.settings && ( + <> + { + setOpen(true); + }} + title={t('setting')} + /> + { + setOpen(false); + }} + open={open} + schema={item.settings} + /> + + ) + ); +}); + +export default Settings; diff --git a/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/index.tsx b/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/index.tsx new file mode 100644 index 0000000000000..ce15af584bab2 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/index.tsx @@ -0,0 +1,127 @@ +import { Loading3QuartersOutlined } from '@ant-design/icons'; +import { LobePluginType } from '@lobehub/chat-plugin-sdk'; +import { ActionIcon, Avatar, Highlighter, Icon } from '@lobehub/ui'; +import { Tabs } from 'antd'; +import isEqual from 'fast-deep-equal'; +import { + LucideBug, + LucideBugOff, + LucideChevronDown, + LucideChevronUp, + LucideToyBrick, +} from 'lucide-react'; +import { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import { pluginHelpers, usePluginStore } from '@/store/plugin'; +import { pluginSelectors } from '@/store/plugin/selectors'; + +import PluginResult from './PluginResultJSON'; +import Settings from './Settings'; +import { useStyles } from './style'; + +export interface InspectorProps { + arguments?: string; + command?: any; + content: string; + id?: string; + loading?: boolean; + setShow?: (showRender: boolean) => void; + showRender?: boolean; + type?: LobePluginType; +} + +const Inspector = memo( + ({ + arguments: requestArgs = '{}', + command, + showRender, + loading, + setShow, + content, + id = 'unknown', + // type, + }) => { + const { t } = useTranslation('plugin'); + const { styles } = useStyles(); + const [open, setOpen] = useState(false); + + const item = usePluginStore(pluginSelectors.getPluginMetaById(id), isEqual); + const showRightAction = usePluginStore(pluginSelectors.hasPluginUI(id)); + const pluginAvatar = pluginHelpers.getPluginAvatar(item?.meta); + const pluginTitle = pluginHelpers.getPluginTitle(item?.meta); + + const avatar = pluginAvatar ? ( + + ) : ( + + ); + + const args = JSON.stringify(command, null, 2); + const params = JSON.stringify(JSON.parse(requestArgs), null, 2); + + return ( + + + { + setShow?.(!showRender); + }} + > + {loading ? ( +
+ +
+ ) : ( + avatar + )} + {pluginTitle ?? t('plugins.unknown')} + {showRightAction && } +
+ { + + {/*{type === 'standalone' && }*/} + { + setOpen(!open); + }} + title={t(open ? 'debug.off' : 'debug.on')} + /> + + + } +
+ {open && ( + {args}, + key: 'function_call', + label: t('debug.function_call'), + }, + { + children: {params}, + key: 'arguments', + label: t('debug.arguments'), + }, + { + children: , + key: 'response', + label: t('debug.response'), + }, + ]} + style={{ maxWidth: 800 }} + /> + )} +
+ ); + }, +); + +export default Inspector; diff --git a/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/style.ts b/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/style.ts new file mode 100644 index 0000000000000..42a5b0ed77eac --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/style.ts @@ -0,0 +1,26 @@ +import { createStyles } from 'antd-style'; + +export const useStyles = createStyles(({ css, token }) => ({ + container: css` + cursor: pointer; + + width: fit-content; + padding: 6px 8px; + padding-inline-end: 12px; + + color: ${token.colorText}; + + border: 1px solid ${token.colorBorder}; + border-radius: 8px; + + &:hover { + background: ${token.colorFillTertiary}; + } + `, + plugin: css` + display: flex; + gap: 4px; + align-items: center; + width: fit-content; + `, +})); diff --git a/src/app/chat/features/Conversation/ChatList/Plugins/Render/DefaultType/IFrameRender/index.tsx b/src/app/chat/features/Conversation/ChatList/Plugins/Render/DefaultType/IFrameRender/index.tsx new file mode 100644 index 0000000000000..d2eebb5bc2ea6 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Plugins/Render/DefaultType/IFrameRender/index.tsx @@ -0,0 +1,60 @@ +import { PluginRenderProps } from '@lobehub/chat-plugin-sdk/client'; +import { Skeleton } from 'antd'; +import { memo, useRef, useState } from 'react'; + +import { useOnPluginReadyForInteraction } from '../../utils/iframeOnReady'; +import { useOnPluginFetchMessage } from '../../utils/listenToPlugin'; +import { sendMessageContentToPlugin } from '../../utils/postMessage'; + +interface IFrameRenderProps extends PluginRenderProps { + height?: number; + url: string; + width?: number; +} + +const IFrameRender = memo(({ url, width = 800, height = 300, ...props }) => { + const iframeRef = useRef(null); + const [loading, setLoading] = useState(true); + + // 当 props 发生变化时,主动向 iframe 发送数据 + useOnPluginReadyForInteraction(() => { + const iframeWin = iframeRef.current?.contentWindow; + + if (iframeWin) { + sendMessageContentToPlugin(iframeWin, props); + } + }, [props]); + + // when get iframe fetch message ,send message content + useOnPluginFetchMessage(() => { + const iframeWin = iframeRef.current?.contentWindow; + if (iframeWin) { + sendMessageContentToPlugin(iframeWin, props); + } + }, [props]); + + return ( + <> + {loading && } +