Compare commits
201 Commits
main
...
build/upda
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1e8aa3603c | ||
![]() |
0dcbb34cab | ||
![]() |
0886d7bb8b | ||
![]() |
e65a47cff7 | ||
![]() |
36c01d89c9 | ||
![]() |
6726ca102e | ||
![]() |
e135707f88 | ||
![]() |
f2765b9d31 | ||
![]() |
1e0877dcbf | ||
![]() |
9a65c3391b | ||
![]() |
ca9e23d6ea | ||
![]() |
c4d6f9e179 | ||
![]() |
0cec6195a3 | ||
![]() |
966d42a4db | ||
![]() |
15c33ba7f3 | ||
![]() |
ed7f74c99c | ||
![]() |
1db4139b5a | ||
![]() |
0d85d44de5 | ||
![]() |
f0f1bfa5d9 | ||
![]() |
9161ce481e | ||
![]() |
c760902e72 | ||
![]() |
7c8c15ef1a | ||
![]() |
765eb282f3 | ||
![]() |
0e2b38dddc | ||
![]() |
92e4b3304c | ||
![]() |
c777d55a1c | ||
![]() |
cd27ae4319 | ||
![]() |
bd82c7edac | ||
![]() |
d5043c6628 | ||
![]() |
d9a0584052 | ||
![]() |
3e011109ad | ||
![]() |
bdb990eb90 | ||
![]() |
ae00211691 | ||
![]() |
0ef35a0ee0 | ||
![]() |
9a9d90ad7f | ||
![]() |
606fc7be0c | ||
![]() |
d7def41acc | ||
![]() |
b6a560ce86 | ||
![]() |
25f34f6703 | ||
![]() |
7daa365564 | ||
![]() |
13ccd294cb | ||
![]() |
d357f359ab | ||
![]() |
474cedf653 | ||
![]() |
5d3c88a0b3 | ||
![]() |
ae2c76bda2 | ||
![]() |
c46b5f2fd0 | ||
![]() |
2cb7b73ee7 | ||
![]() |
8d8d5b5235 | ||
![]() |
15acfffd60 | ||
![]() |
18a266eac2 | ||
![]() |
7751070da8 | ||
![]() |
fa8c3d0d7b | ||
![]() |
a567cff809 | ||
![]() |
583b0e9f97 | ||
![]() |
5fddb23516 | ||
![]() |
0e52971997 | ||
![]() |
1387f406a3 | ||
![]() |
ff31f0540a | ||
![]() |
4873e6e2a1 | ||
![]() |
510ce057f7 | ||
![]() |
0e53cc0e8c | ||
![]() |
0b8c896481 | ||
![]() |
15fe635465 | ||
![]() |
f8c3189f4d | ||
![]() |
f215db87e3 | ||
![]() |
67d02212b4 | ||
![]() |
cff9adaf8e | ||
![]() |
cdd2a40086 | ||
![]() |
024028bc52 | ||
![]() |
0ae085b48a | ||
![]() |
2094c54951 | ||
![]() |
f4f11135d3 | ||
![]() |
8e9d7a229d | ||
![]() |
8f49572f85 | ||
![]() |
5aa7696cc3 | ||
![]() |
15dd79e822 | ||
![]() |
4651ab4195 | ||
![]() |
5e3160e6f6 | ||
![]() |
973cd126bb | ||
![]() |
ebaf8766ef | ||
![]() |
d2190e9c3a | ||
![]() |
37f55098fe | ||
![]() |
b1771194cc | ||
![]() |
0279bd8c75 | ||
![]() |
5e077e4ce8 | ||
![]() |
64067e1f20 | ||
![]() |
5295c72ca1 | ||
![]() |
1ecea62052 | ||
![]() |
307af29b65 | ||
![]() |
10190a9aa5 | ||
![]() |
7c5c35600c | ||
![]() |
63b333cdb1 | ||
![]() |
a6776190bd | ||
![]() |
9577cbac27 | ||
![]() |
f6ae13abad | ||
![]() |
f3d501e7d5 | ||
![]() |
2eab8fcc33 | ||
![]() |
bdb81fe20d | ||
![]() |
0f60fe7f2a | ||
![]() |
425f624de5 | ||
![]() |
b1919745e2 | ||
![]() |
9a242bcac9 | ||
![]() |
a6109a60b8 | ||
![]() |
28f7bbf83a | ||
![]() |
cac04c5f3c | ||
![]() |
18f5f9cc37 | ||
![]() |
1787c5c93f | ||
![]() |
f981494613 | ||
![]() |
fbc853af92 | ||
![]() |
1a64c660ba | ||
![]() |
846555af1b | ||
![]() |
bca94854f7 | ||
![]() |
1bd70bd8bf | ||
![]() |
d1dcd39191 | ||
![]() |
35384bda41 | ||
![]() |
89fb6eb648 | ||
![]() |
aa61a890b2 | ||
![]() |
31ece363c3 | ||
![]() |
70a5d78cc5 | ||
![]() |
57f4dfdb6f | ||
![]() |
aa9028a607 | ||
![]() |
d83f94c55c | ||
![]() |
a8c5e0b0b0 | ||
![]() |
177e8cbf73 | ||
![]() |
23828fd15a | ||
![]() |
2cc37ac8e5 | ||
![]() |
c9ee1e9ff2 | ||
![]() |
4f10f5d5f4 | ||
![]() |
c48c84674e | ||
![]() |
1e9fbbf41b | ||
![]() |
4dd144ce43 | ||
![]() |
a387ff1c38 | ||
![]() |
a9e367e6de | ||
![]() |
e2fec587f8 | ||
![]() |
39a6f0943d | ||
![]() |
684896d100 | ||
![]() |
54f911f6cd | ||
![]() |
0e5c16d0c2 | ||
![]() |
b8cd6ea478 | ||
![]() |
fc61fd0f50 | ||
![]() |
2fbfc988c4 | ||
![]() |
99f5fea001 | ||
![]() |
ecd2a1be9f | ||
![]() |
49ee9ca5f1 | ||
![]() |
6d0eef12b1 | ||
![]() |
c1e0a939b0 | ||
![]() |
060a894bd1 | ||
![]() |
c75e02b5b2 | ||
![]() |
fcf43ee845 | ||
![]() |
466f61d044 | ||
![]() |
27ae74af50 | ||
![]() |
8dd941e3d2 | ||
![]() |
dec4bf6b98 | ||
![]() |
e2c33fc40f | ||
![]() |
c74e59d1f4 | ||
![]() |
1fcb902715 | ||
![]() |
c08f98218c | ||
![]() |
c6377f6e38 | ||
![]() |
3cb0a5bd68 | ||
![]() |
95777d23e0 | ||
![]() |
e7dc16fd08 | ||
![]() |
495dec143c | ||
![]() |
4cc6dfa232 | ||
![]() |
d1452d4af4 | ||
![]() |
d68ca56b3a | ||
![]() |
49856d8d17 | ||
![]() |
902de72cc0 | ||
![]() |
76f6b8d104 | ||
![]() |
f111e605c4 | ||
![]() |
b358ed3a5b | ||
![]() |
88dbf639e0 | ||
![]() |
aa8b525b48 | ||
![]() |
c990bc61db | ||
![]() |
6d7588f236 | ||
![]() |
8257c7bf02 | ||
![]() |
946068967b | ||
![]() |
19f5684960 | ||
![]() |
6d62840aff | ||
![]() |
ab868ac979 | ||
![]() |
1d74e693ea | ||
![]() |
fa43d4202f | ||
![]() |
6b29860788 | ||
![]() |
36800eeaba | ||
![]() |
67acd174ac | ||
![]() |
b5edc64b2a | ||
![]() |
d00b2724cc | ||
![]() |
43f87c0b86 | ||
![]() |
7a43f48c95 | ||
![]() |
58a913b09d | ||
![]() |
cd03795f2c | ||
![]() |
36f8b5711d | ||
![]() |
f9c48e9ea9 | ||
![]() |
3b48f8c98e | ||
![]() |
cef1010cb5 | ||
![]() |
cb4875a3a7 | ||
![]() |
bbca708832 | ||
![]() |
05aec43ee3 | ||
![]() |
e8127756e0 | ||
![]() |
792595a46f | ||
![]() |
d7d7281c93 | ||
![]() |
21193c2fbf |
@ -1,11 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
cd web && npm install
|
npm add -g pnpm@9.12.2
|
||||||
|
cd web && pnpm install
|
||||||
pipx install poetry
|
pipx install poetry
|
||||||
|
|
||||||
echo 'alias start-api="cd /workspaces/dify/api && poetry run python -m flask run --host 0.0.0.0 --port=5001 --debug"' >> ~/.bashrc
|
echo 'alias start-api="cd /workspaces/dify/api && poetry run python -m flask run --host 0.0.0.0 --port=5001 --debug"' >> ~/.bashrc
|
||||||
echo 'alias start-worker="cd /workspaces/dify/api && poetry run python -m celery -A app.celery worker -P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion"' >> ~/.bashrc
|
echo 'alias start-worker="cd /workspaces/dify/api && poetry run python -m celery -A app.celery worker -P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion"' >> ~/.bashrc
|
||||||
echo 'alias start-web="cd /workspaces/dify/web && npm run dev"' >> ~/.bashrc
|
echo 'alias start-web="cd /workspaces/dify/web && pnpm dev"' >> ~/.bashrc
|
||||||
echo 'alias start-containers="cd /workspaces/dify/docker && docker-compose -f docker-compose.middleware.yaml -p dify up -d"' >> ~/.bashrc
|
echo 'alias start-containers="cd /workspaces/dify/docker && docker-compose -f docker-compose.middleware.yaml -p dify up -d"' >> ~/.bashrc
|
||||||
|
|
||||||
source /home/vscode/.bashrc
|
source /home/vscode/.bashrc
|
6
.github/workflows/style.yml
vendored
6
.github/workflows/style.yml
vendored
@ -76,16 +76,16 @@ jobs:
|
|||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: yarn
|
cache: pnpm
|
||||||
cache-dependency-path: ./web/package.json
|
cache-dependency-path: ./web/package.json
|
||||||
|
|
||||||
- name: Web dependencies
|
- name: Web dependencies
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: yarn install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Web style check
|
- name: Web style check
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: yarn run lint
|
run: pnpm run lint
|
||||||
|
|
||||||
|
|
||||||
superlinter:
|
superlinter:
|
||||||
|
6
.github/workflows/tool-test-sdks.yaml
vendored
6
.github/workflows/tool-test-sdks.yaml
vendored
@ -32,10 +32,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: ''
|
cache: ''
|
||||||
cache-dependency-path: 'yarn.lock'
|
cache-dependency-path: 'pnpm-lock.yaml'
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: yarn install
|
run: pnpm install
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: yarn test
|
run: pnpm test
|
||||||
|
@ -38,11 +38,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
if: env.FILES_CHANGED == 'true'
|
if: env.FILES_CHANGED == 'true'
|
||||||
run: yarn install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Run npm script
|
- name: Run npm script
|
||||||
if: env.FILES_CHANGED == 'true'
|
if: env.FILES_CHANGED == 'true'
|
||||||
run: npm run auto-gen-i18n
|
run: pnpm run auto-gen-i18n
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
if: env.FILES_CHANGED == 'true'
|
if: env.FILES_CHANGED == 'true'
|
||||||
|
6
.github/workflows/web-tests.yml
vendored
6
.github/workflows/web-tests.yml
vendored
@ -34,13 +34,13 @@ jobs:
|
|||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: yarn
|
cache: pnpm
|
||||||
cache-dependency-path: ./web/package.json
|
cache-dependency-path: ./web/package.json
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: yarn install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: yarn test
|
run: pnpm test
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -190,3 +190,6 @@ api/.vscode
|
|||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
/.pnpm-store
|
||||||
|
@ -38,7 +38,6 @@ class AliYuqueDescribeDocumentContentTool(AliYuqueTool, BuiltinTool):
|
|||||||
book_id = index_page.get("data", {}).get("book", {}).get("id")
|
book_id = index_page.get("data", {}).get("book", {}).get("id")
|
||||||
if not book_id:
|
if not book_id:
|
||||||
raise Exception(f"can not parse book_id from {index_page}")
|
raise Exception(f"can not parse book_id from {index_page}")
|
||||||
|
|
||||||
new_params["book_id"] = book_id
|
new_params["book_id"] = book_id
|
||||||
new_params["id"] = doc_id
|
new_params["id"] = doc_id
|
||||||
data = self.request("GET", token, new_params, "/api/v2/repos/{book_id}/docs/{id}")
|
data = self.request("GET", token, new_params, "/api/v2/repos/{book_id}/docs/{id}")
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": [
|
|
||||||
"@babel/preset-env"
|
|
||||||
]
|
|
||||||
}
|
|
@ -10,6 +10,8 @@ NEXT_PUBLIC_API_PREFIX=http://localhost:5001/console/api
|
|||||||
# console or api domain.
|
# console or api domain.
|
||||||
# example: http://udify.app/api
|
# example: http://udify.app/api
|
||||||
NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api
|
NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api
|
||||||
|
# The URL for MARKETPLACE
|
||||||
|
NEXT_PUBLIC_MARKETPLACE_API_PREFIX=http://localhost:5002/api
|
||||||
|
|
||||||
# SENTRY
|
# SENTRY
|
||||||
NEXT_PUBLIC_SENTRY_DSN=
|
NEXT_PUBLIC_SENTRY_DSN=
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
/**/node_modules/*
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
dist/
|
|
||||||
build/
|
|
||||||
out/
|
|
||||||
.next/
|
|
@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": [
|
|
||||||
"next",
|
|
||||||
"@antfu",
|
|
||||||
"plugin:storybook/recommended"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/consistent-type-definitions": [
|
|
||||||
"error",
|
|
||||||
"type"
|
|
||||||
],
|
|
||||||
"@typescript-eslint/no-var-requires": "off",
|
|
||||||
"no-console": "off",
|
|
||||||
"indent": "off",
|
|
||||||
"@typescript-eslint/indent": [
|
|
||||||
"error",
|
|
||||||
2,
|
|
||||||
{
|
|
||||||
"SwitchCase": 1,
|
|
||||||
"flatTernaryExpressions": false,
|
|
||||||
"ignoredNodes": [
|
|
||||||
"PropertyDefinition[decorators]",
|
|
||||||
"TSUnionType",
|
|
||||||
"FunctionExpression[params]:has(Identifier[decorators])"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"react-hooks/exhaustive-deps": "warn",
|
|
||||||
"react/display-name": "warn"
|
|
||||||
}
|
|
||||||
}
|
|
7
web/.gitignore
vendored
7
web/.gitignore
vendored
@ -44,10 +44,9 @@ package-lock.json
|
|||||||
.pnp.cjs
|
.pnp.cjs
|
||||||
.pnp.loader.mjs
|
.pnp.loader.mjs
|
||||||
.yarn/
|
.yarn/
|
||||||
.yarnrc.yml
|
|
||||||
|
|
||||||
# pmpm
|
|
||||||
pnpm-lock.yaml
|
|
||||||
|
|
||||||
.favorites.json
|
.favorites.json
|
||||||
|
|
||||||
|
# storybook
|
||||||
|
/storybook-static
|
||||||
*storybook.log
|
*storybook.log
|
@ -1,6 +1,3 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
. "$(dirname -- "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
# get the list of modified files
|
# get the list of modified files
|
||||||
files=$(git diff --cached --name-only)
|
files=$(git diff --cached --name-only)
|
||||||
|
|
||||||
@ -50,7 +47,7 @@ fi
|
|||||||
if $web_modified; then
|
if $web_modified; then
|
||||||
echo "Running ESLint on web module"
|
echo "Running ESLint on web module"
|
||||||
cd ./web || exit 1
|
cd ./web || exit 1
|
||||||
npx lint-staged
|
lint-staged
|
||||||
|
|
||||||
echo "Running unit tests check"
|
echo "Running unit tests check"
|
||||||
modified_files=$(git diff --cached --name-only -- utils | grep -v '\.spec\.ts$' || true)
|
modified_files=$(git diff --cached --name-only -- utils | grep -v '\.spec\.ts$' || true)
|
||||||
@ -63,7 +60,7 @@ if $web_modified; then
|
|||||||
# check if the test file exists
|
# check if the test file exists
|
||||||
if [ -f "../$test_file" ]; then
|
if [ -f "../$test_file" ]; then
|
||||||
echo "Detected changes in $file, running corresponding unit tests..."
|
echo "Detected changes in $file, running corresponding unit tests..."
|
||||||
npm run test "../$test_file"
|
pnpm run test "../$test_file"
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Unit tests failed. Please fix the errors before committing."
|
echo "Unit tests failed. Please fix the errors before committing."
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import type { Preview } from '@storybook/react'
|
import type { Preview } from '@storybook/react'
|
||||||
import { withThemeByDataAttribute } from '@storybook/addon-themes';
|
import { withThemeByDataAttribute } from '@storybook/addon-themes'
|
||||||
import I18nServer from '../app/components/i18n-server'
|
import I18nServer from '../app/components/i18n-server'
|
||||||
|
|
||||||
import '../app/styles/globals.css'
|
import '../app/styles/globals.css'
|
||||||
@ -16,12 +16,12 @@ export const decorators = [
|
|||||||
defaultTheme: 'light',
|
defaultTheme: 'light',
|
||||||
attributeName: 'data-theme',
|
attributeName: 'data-theme',
|
||||||
}),
|
}),
|
||||||
Story => {
|
(Story) => {
|
||||||
return <I18nServer>
|
return <I18nServer>
|
||||||
<Story />
|
<Story />
|
||||||
</I18nServer>
|
</I18nServer>
|
||||||
}
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
const preview: Preview = {
|
const preview: Preview = {
|
||||||
parameters: {
|
parameters: {
|
||||||
|
3
web/.vscode/settings.example.json
vendored
3
web/.vscode/settings.example.json
vendored
@ -21,5 +21,6 @@
|
|||||||
"editor.defaultFormatter": "vscode.json-language-features"
|
"editor.defaultFormatter": "vscode.json-language-features"
|
||||||
},
|
},
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||||
|
"npm.packageManager": "pnpm"
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ LABEL maintainer="takatost@gmail.com"
|
|||||||
# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
|
# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
|
||||||
|
|
||||||
RUN apk add --no-cache tzdata
|
RUN apk add --no-cache tzdata
|
||||||
|
RUN npm install -g pnpm@9.12.2
|
||||||
|
ENV PNPM_HOME="/pnpm"
|
||||||
|
ENV PATH="$PNPM_HOME:$PATH"
|
||||||
|
|
||||||
|
|
||||||
# install packages
|
# install packages
|
||||||
@ -14,12 +17,12 @@ FROM base AS packages
|
|||||||
WORKDIR /app/web
|
WORKDIR /app/web
|
||||||
|
|
||||||
COPY package.json .
|
COPY package.json .
|
||||||
COPY yarn.lock .
|
COPY pnpm-lock.yaml .
|
||||||
|
|
||||||
# if you located in China, you can use taobao registry to speed up
|
# if you located in China, you can use taobao registry to speed up
|
||||||
# RUN yarn install --frozen-lockfile --registry https://registry.npmmirror.com/
|
# RUN pnpm install --frozen-lockfile --registry https://registry.npmmirror.com/
|
||||||
|
|
||||||
RUN yarn install --frozen-lockfile
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
# build resources
|
# build resources
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
@ -27,7 +30,7 @@ WORKDIR /app/web
|
|||||||
COPY --from=packages /app/web/ .
|
COPY --from=packages /app/web/ .
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN yarn build
|
RUN pnpm build
|
||||||
|
|
||||||
|
|
||||||
# production stage
|
# production stage
|
||||||
@ -57,8 +60,7 @@ COPY docker/entrypoint.sh ./entrypoint.sh
|
|||||||
|
|
||||||
|
|
||||||
# global runtime packages
|
# global runtime packages
|
||||||
RUN yarn global add pm2 \
|
RUN pnpm add -g pm2 \
|
||||||
&& yarn cache clean \
|
|
||||||
&& mkdir /.pm2 \
|
&& mkdir /.pm2 \
|
||||||
&& chown -R 1001:0 /.pm2 /app/web \
|
&& chown -R 1001:0 /.pm2 /app/web \
|
||||||
&& chmod -R g=u /.pm2 /app/web
|
&& chmod -R g=u /.pm2 /app/web
|
||||||
|
@ -6,14 +6,12 @@ This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next
|
|||||||
|
|
||||||
### Run by source code
|
### Run by source code
|
||||||
|
|
||||||
To start the web frontend service, you will need [Node.js v18.x (LTS)](https://nodejs.org/en) and [NPM version 8.x.x](https://www.npmjs.com/) or [Yarn](https://yarnpkg.com/).
|
To start the web frontend service, you will need [Node.js v18.x (LTS)](https://nodejs.org/en) and [pnpm version 9.12.2](https://pnpm.io).
|
||||||
|
|
||||||
First, install the dependencies:
|
First, install the dependencies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install
|
pnpm install
|
||||||
# or
|
|
||||||
yarn install --frozen-lockfile
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, configure the environment variables. Create a file named `.env.local` in the current directory and copy the contents from `.env.example`. Modify the values of these environment variables according to your requirements:
|
Then, configure the environment variables. Create a file named `.env.local` in the current directory and copy the contents from `.env.example`. Modify the values of these environment variables according to your requirements:
|
||||||
@ -43,9 +41,7 @@ NEXT_PUBLIC_SENTRY_DSN=
|
|||||||
Finally, run the development server:
|
Finally, run the development server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
pnpm run dev
|
||||||
# or
|
|
||||||
yarn dev
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
@ -59,19 +55,19 @@ You can start editing the file under folder `app`. The page auto-updates as you
|
|||||||
First, build the app for production:
|
First, build the app for production:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
pnpm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, start the server:
|
Then, start the server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run start
|
pnpm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want to customize the host and port:
|
If you want to customize the host and port:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run start --port=3001 --host=0.0.0.0
|
pnpm run start --port=3001 --host=0.0.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
## Storybook
|
## Storybook
|
||||||
@ -81,7 +77,7 @@ This project uses [Storybook](https://storybook.js.org/) for UI component develo
|
|||||||
To start the storybook server, run:
|
To start the storybook server, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn storybook
|
pnpm storybook
|
||||||
```
|
```
|
||||||
|
|
||||||
Open [http://localhost:6006](http://localhost:6006) with your browser to see the result.
|
Open [http://localhost:6006](http://localhost:6006) with your browser to see the result.
|
||||||
@ -99,7 +95,7 @@ You can create a test file with a suffix of `.spec` beside the file that to be t
|
|||||||
Run test:
|
Run test:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run test
|
pnpm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are not familiar with writing tests, here is some code to refer to:
|
If you are not familiar with writing tests, here is some code to refer to:
|
||||||
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import Main from '@/app/components/app/log-annotation'
|
import Main from '@/app/components/app/log-annotation'
|
||||||
import { PageType } from '@/app/components/base/features/new-feature-panel/annotation-reply/type'
|
import { PageType } from '@/app/components/base/features/new-feature-panel/annotation-reply/type'
|
||||||
|
|
||||||
export type IProps = {
|
export interface IProps {
|
||||||
params: { appId: string }
|
params: { appId: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { type Locale } from '@/i18n'
|
import type { Locale } from '@/i18n'
|
||||||
import DevelopMain from '@/app/components/develop'
|
import DevelopMain from '@/app/components/develop'
|
||||||
|
|
||||||
export type IDevelopProps = {
|
export type IDevelopProps = {
|
||||||
|
@ -4,7 +4,7 @@ import React from 'react'
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
label: string
|
label: string
|
||||||
labelClassName?: string
|
labelClassName?: string
|
||||||
|
@ -8,12 +8,11 @@ import { useBoolean } from 'ahooks'
|
|||||||
import {
|
import {
|
||||||
Cog8ToothIcon,
|
Cog8ToothIcon,
|
||||||
// CommandLineIcon,
|
// CommandLineIcon,
|
||||||
Squares2X2Icon,
|
|
||||||
// eslint-disable-next-line sort-imports
|
|
||||||
PuzzlePieceIcon,
|
|
||||||
DocumentTextIcon,
|
DocumentTextIcon,
|
||||||
PaperClipIcon,
|
PaperClipIcon,
|
||||||
|
PuzzlePieceIcon,
|
||||||
QuestionMarkCircleIcon,
|
QuestionMarkCircleIcon,
|
||||||
|
Squares2X2Icon,
|
||||||
} from '@heroicons/react/24/outline'
|
} from '@heroicons/react/24/outline'
|
||||||
import {
|
import {
|
||||||
Cog8ToothIcon as Cog8ToothSolidIcon,
|
Cog8ToothIcon as Cog8ToothSolidIcon,
|
||||||
|
18
web/app/(commonLayout)/plugins/page.tsx
Normal file
18
web/app/(commonLayout)/plugins/page.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import PluginPage from '@/app/components/plugins/plugin-page'
|
||||||
|
import PluginsPanel from '@/app/components/plugins/plugin-page/plugins-panel'
|
||||||
|
import Marketplace from '@/app/components/plugins/marketplace'
|
||||||
|
|
||||||
|
const PluginList = async () => {
|
||||||
|
return (
|
||||||
|
<PluginPage
|
||||||
|
plugins={<PluginsPanel />}
|
||||||
|
marketplace={<Marketplace />}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: 'Plugins - Dify',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PluginList
|
14
web/app/(commonLayout)/plugins/test/card/actions.ts
Normal file
14
web/app/(commonLayout)/plugins/test/card/actions.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use server'
|
||||||
|
|
||||||
|
import { revalidatePath } from 'next/cache'
|
||||||
|
|
||||||
|
// Server Actions
|
||||||
|
export async function handleDelete() {
|
||||||
|
// revalidatePath only invalidates the cache when the included path is next visited.
|
||||||
|
revalidatePath('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchPluginDetail(org: string, name: string) {
|
||||||
|
// Fetch plugin detail TODO
|
||||||
|
return { org, name }
|
||||||
|
}
|
74
web/app/(commonLayout)/plugins/test/card/page.tsx
Normal file
74
web/app/(commonLayout)/plugins/test/card/page.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { handleDelete } from './actions'
|
||||||
|
import Card from '@/app/components/plugins/card'
|
||||||
|
import { customTool, extensionDallE, modelGPT4, toolNotion } from '@/app/components/plugins/card/card-mock'
|
||||||
|
import PluginItem from '@/app/components/plugins/plugin-item'
|
||||||
|
import CardMoreInfo from '@/app/components/plugins/card/card-more-info'
|
||||||
|
import ProviderCard from '@/app/components/plugins/provider-card'
|
||||||
|
import Badge from '@/app/components/base/badge'
|
||||||
|
|
||||||
|
const PluginList = async () => {
|
||||||
|
const pluginList = [toolNotion, extensionDallE, modelGPT4, customTool]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='pb-3 bg-white'>
|
||||||
|
<div className='mx-3 '>
|
||||||
|
<h2 className='my-3'>Dify Plugin list</h2>
|
||||||
|
<div className='grid grid-cols-2 gap-3'>
|
||||||
|
{pluginList.map((plugin, index) => (
|
||||||
|
<PluginItem
|
||||||
|
key={index}
|
||||||
|
payload={plugin as any}
|
||||||
|
onDelete={handleDelete}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 className='my-3'>Install Plugin / Package under bundle</h2>
|
||||||
|
<div className='w-[512px] rounded-2xl bg-background-section-burn p-2'>
|
||||||
|
<Card
|
||||||
|
payload={toolNotion as any}
|
||||||
|
descriptionLineRows={1}
|
||||||
|
titleLeft={
|
||||||
|
<Badge className='ml-1' text={toolNotion.version} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h3 className='my-1'>Installed</h3>
|
||||||
|
<div className='w-[512px] rounded-2xl bg-background-section-burn p-2'>
|
||||||
|
<Card
|
||||||
|
payload={toolNotion as any}
|
||||||
|
descriptionLineRows={1}
|
||||||
|
installed
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 className='my-1'>Install model provide</h3>
|
||||||
|
<div className='grid grid-cols-2 gap-3'>
|
||||||
|
{pluginList.map((plugin, index) => (
|
||||||
|
<ProviderCard key={index} payload={plugin as any} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='my-3 h-[px] bg-gray-50'></div>
|
||||||
|
<h2 className='my-3'>Marketplace Plugin list</h2>
|
||||||
|
<div className='grid grid-cols-4 gap-3'>
|
||||||
|
{pluginList.map((plugin, index) => (
|
||||||
|
<Card
|
||||||
|
key={index}
|
||||||
|
payload={plugin as any}
|
||||||
|
footer={
|
||||||
|
<CardMoreInfo downloadCount={index % 2 === 0 ? 1234 : 6} tags={index % 2 === 0 ? ['Search', 'Tag that has very very long name', 'Productivity', 'Tag2'] : []} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: 'Plugins - Card',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PluginList
|
20
web/app/(commonLayout)/plugins/test/other/page.tsx
Normal file
20
web/app/(commonLayout)/plugins/test/other/page.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
'use client'
|
||||||
|
import { useBoolean } from 'ahooks'
|
||||||
|
import UpdatePlugin from '@/app/components/plugins/update-plugin'
|
||||||
|
|
||||||
|
const Page = () => {
|
||||||
|
const [isShowUpdateModal, {
|
||||||
|
setTrue: showUpdateModal,
|
||||||
|
setFalse: hideUpdateModal,
|
||||||
|
}] = useBoolean(false)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div onClick={showUpdateModal}>Show Upgrade</div>
|
||||||
|
{isShowUpdateModal && (
|
||||||
|
<UpdatePlugin onHide={hideUpdateModal} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page
|
39
web/app/(commonLayout)/plugins/test/tools-picker/page.tsx
Normal file
39
web/app/(commonLayout)/plugins/test/tools-picker/page.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
'use client'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import AllTools from '@/app/components/workflow/block-selector/all-tools'
|
||||||
|
import {
|
||||||
|
fetchAllBuiltInTools,
|
||||||
|
fetchAllCustomTools,
|
||||||
|
fetchAllWorkflowTools,
|
||||||
|
} from '@/service/tools'
|
||||||
|
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
|
const ToolsPicker = () => {
|
||||||
|
const [buildInTools, setBuildInTools] = useState<ToolWithProvider[]>([])
|
||||||
|
const [customTools, setCustomTools] = useState<ToolWithProvider[]>([])
|
||||||
|
const [workflowTools, setWorkflowTools] = useState<ToolWithProvider[]>([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
const buildInTools = await fetchAllBuiltInTools()
|
||||||
|
const customTools = await fetchAllCustomTools()
|
||||||
|
const workflowTools = await fetchAllWorkflowTools()
|
||||||
|
setBuildInTools(buildInTools)
|
||||||
|
setCustomTools(customTools)
|
||||||
|
setWorkflowTools(workflowTools)
|
||||||
|
})()
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
<div className="relative mt-5 mx-auto w-[320px] bg-white">
|
||||||
|
<AllTools
|
||||||
|
searchText=""
|
||||||
|
onSelect={() => { }}
|
||||||
|
buildInTools={buildInTools}
|
||||||
|
customTools={customTools}
|
||||||
|
workflowTools={workflowTools}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToolsPicker
|
@ -8,7 +8,7 @@ import { logout } from '@/service/common'
|
|||||||
import { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general'
|
import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
|
|
||||||
export type IAppSelector = {
|
export interface IAppSelector {
|
||||||
isMobile: boolean
|
isMobile: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ import useSWR from 'swr'
|
|||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
import { fetchAnnotationsCount } from '@/service/log'
|
import { fetchAnnotationsCount } from '@/service/log'
|
||||||
|
|
||||||
export type QueryParam = {
|
export interface QueryParam {
|
||||||
keyword?: string
|
keyword?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type IFilterProps = {
|
interface IFilterProps {
|
||||||
appId: string
|
appId: string
|
||||||
queryParams: QueryParam
|
queryParams: QueryParam
|
||||||
setQueryParams: (v: QueryParam) => void
|
setQueryParams: (v: QueryParam) => void
|
||||||
|
@ -27,7 +27,7 @@ import AnnotationFullModal from '@/app/components/billing/annotation-full/modal'
|
|||||||
import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
|
import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
import type { App } from '@/types/app'
|
import type { App } from '@/types/app'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
appDetail: App
|
appDetail: App
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import RemoveAnnotationConfirmModal from './remove-annotation-confirm-modal'
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import useTimestamp from '@/hooks/use-timestamp'
|
import useTimestamp from '@/hooks/use-timestamp'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
list: AnnotationItem[]
|
list: AnnotationItem[]
|
||||||
onRemove: (id: string) => void
|
onRemove: (id: string) => void
|
||||||
onView: (item: AnnotationItem) => void
|
onView: (item: AnnotationItem) => void
|
||||||
|
@ -3,7 +3,7 @@ import type { FC, ReactNode } from 'react'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
export type IFeaturePanelProps = {
|
export interface IFeaturePanelProps {
|
||||||
className?: string
|
className?: string
|
||||||
headerIcon?: ReactNode
|
headerIcon?: ReactNode
|
||||||
title: ReactNode
|
title: ReactNode
|
||||||
|
@ -9,7 +9,7 @@ import { MessageClockCircle } from '@/app/components/base/icons/src/vender/solid
|
|||||||
import I18n from '@/context/i18n'
|
import I18n from '@/context/i18n'
|
||||||
import { LanguagesSupported } from '@/i18n/language'
|
import { LanguagesSupported } from '@/i18n/language'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
showWarning: boolean
|
showWarning: boolean
|
||||||
onShowEditModal: () => void
|
onShowEditModal: () => void
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import ConfirmAddVar from './confirm-add-var'
|
|||||||
import s from './style.module.css'
|
import s from './style.module.css'
|
||||||
import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap'
|
import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { type PromptVariable } from '@/models/debug'
|
import type { PromptVariable } from '@/models/debug'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import type { CompletionParams } from '@/types/app'
|
import type { CompletionParams } from '@/types/app'
|
||||||
import { AppType } from '@/types/app'
|
import { AppType } from '@/types/app'
|
||||||
|
@ -3,7 +3,7 @@ import type { FC } from 'react'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
title: string
|
title: string
|
||||||
children: JSX.Element
|
children: JSX.Element
|
||||||
|
@ -23,7 +23,7 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config'
|
|||||||
|
|
||||||
const TEXT_MAX_LENGTH = 256
|
const TEXT_MAX_LENGTH = 256
|
||||||
|
|
||||||
export type IConfigModalProps = {
|
export interface IConfigModalProps {
|
||||||
isCreate?: boolean
|
isCreate?: boolean
|
||||||
payload?: InputVar
|
payload?: InputVar
|
||||||
isShow: boolean
|
isShow: boolean
|
||||||
|
@ -3,7 +3,7 @@ import type { FC } from 'react'
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
|
|
||||||
export type IConfigStringProps = {
|
export interface IConfigStringProps {
|
||||||
value: number | undefined
|
value: number | undefined
|
||||||
maxLength: number
|
maxLength: number
|
||||||
modelId: string
|
modelId: string
|
||||||
@ -28,7 +28,7 @@ const ConfigString: FC<IConfigStringProps> = ({
|
|||||||
min={1}
|
min={1}
|
||||||
value={value || ''}
|
value={value || ''}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
let value = parseInt(e.target.value, 10)
|
let value = Number.parseInt(e.target.value, 10)
|
||||||
if (value > maxLength)
|
if (value > maxLength)
|
||||||
value = maxLength
|
value = maxLength
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ import type { FC } from 'react'
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useBoolean } from 'ahooks'
|
import { useBoolean } from 'ahooks'
|
||||||
import type { Timeout } from 'ahooks/lib/useRequest/src/types'
|
|
||||||
import { useContext } from 'use-context-selector'
|
import { useContext } from 'use-context-selector'
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import {
|
import {
|
||||||
@ -34,7 +33,7 @@ import { InputVarType } from '@/app/components/workflow/types'
|
|||||||
|
|
||||||
export const ADD_EXTERNAL_DATA_TOOL = 'ADD_EXTERNAL_DATA_TOOL'
|
export const ADD_EXTERNAL_DATA_TOOL = 'ADD_EXTERNAL_DATA_TOOL'
|
||||||
|
|
||||||
type ExternalDataToolParams = {
|
interface ExternalDataToolParams {
|
||||||
key: string
|
key: string
|
||||||
type: string
|
type: string
|
||||||
index: number
|
index: number
|
||||||
@ -44,13 +43,13 @@ type ExternalDataToolParams = {
|
|||||||
icon_background?: string
|
icon_background?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IConfigVarProps = {
|
export interface IConfigVarProps {
|
||||||
promptVariables: PromptVariable[]
|
promptVariables: PromptVariable[]
|
||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
onPromptVariablesChange?: (promptVariables: PromptVariable[]) => void
|
onPromptVariablesChange?: (promptVariables: PromptVariable[]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
let conflictTimer: Timeout
|
let conflictTimer: number
|
||||||
|
|
||||||
const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVariablesChange }) => {
|
const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVariablesChange }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -107,7 +106,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
|||||||
onPromptVariablesChange?.(newPromptVariables)
|
onPromptVariablesChange?.(newPromptVariables)
|
||||||
}
|
}
|
||||||
const updatePromptKey = (index: number, newKey: string) => {
|
const updatePromptKey = (index: number, newKey: string) => {
|
||||||
clearTimeout(conflictTimer)
|
window.clearTimeout(conflictTimer)
|
||||||
const { isValid, errorKey, errorMessageKey } = checkKeys([newKey], true)
|
const { isValid, errorKey, errorMessageKey } = checkKeys([newKey], true)
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
@ -127,7 +126,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
|||||||
return item
|
return item
|
||||||
})
|
})
|
||||||
|
|
||||||
conflictTimer = setTimeout(() => {
|
conflictTimer = window.setTimeout(() => {
|
||||||
const isKeyExists = promptVariables.some(item => item.key?.trim() === newKey.trim())
|
const isKeyExists = promptVariables.some(item => item.key?.trim() === newKey.trim())
|
||||||
if (isKeyExists) {
|
if (isKeyExists) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
|
@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import type { InputVarType } from '@/app/components/workflow/types'
|
import type { InputVarType } from '@/app/components/workflow/types'
|
||||||
import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
|
import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
|
||||||
export type ISelectTypeItemProps = {
|
export interface ISelectTypeItemProps {
|
||||||
type: InputVarType
|
type: InputVarType
|
||||||
selected: boolean
|
selected: boolean
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
|
@ -106,23 +106,22 @@ const SettingBuiltInTool: FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{infoSchemas.length > 0 && (
|
{infoSchemas.length > 0 && (
|
||||||
<div className='mt-6'>
|
<div className='my-2'>
|
||||||
<div className='flex items-center mb-4 leading-[18px] text-xs font-semibold text-gray-500 uppercase'>
|
<div className='pt-3 text-text-secondary system-sm-semibold-uppercase'>
|
||||||
<div className='mr-3'>{t('tools.setBuiltInTools.parameters')}</div>
|
{t('tools.setBuiltInTools.parameters')}
|
||||||
<div className='grow w-0 h-px bg-[#f3f4f6]'></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className='space-y-4'>
|
<div className='py-2 space-y-3'>
|
||||||
{infoSchemas.map((item: any, index) => (
|
{infoSchemas.map((item: any, index) => (
|
||||||
<div key={index}>
|
<div key={index} className='py-1'>
|
||||||
<div className='flex items-center space-x-2 leading-[18px]'>
|
<div className='flex items-center gap-2'>
|
||||||
<div className='text-[13px] font-semibold text-gray-900'>{item.label[language]}</div>
|
<div className='text-text-secondary code-sm-semibold'>{item.label[language]}</div>
|
||||||
<div className='text-xs font-medium text-gray-500'>{item.type === 'number-input' ? t('tools.setBuiltInTools.number') : t('tools.setBuiltInTools.string')}</div>
|
<div className='text-text-tertiary system-xs-regular'>{item.type === 'number-input' ? t('tools.setBuiltInTools.number') : t('tools.setBuiltInTools.string')}</div>
|
||||||
{item.required && (
|
{item.required && (
|
||||||
<div className='text-xs font-medium text-[#EC4A0A]'>{t('tools.setBuiltInTools.required')}</div>
|
<div className='text-text-warning-secondary system-xs-medium'>{t('tools.setBuiltInTools.required')}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{item.human_description && (
|
{item.human_description && (
|
||||||
<div className='mt-1 leading-[18px] text-xs font-normal text-gray-600'>
|
<div className='mt-0.5 text-text-tertiary system-xs-regular'>
|
||||||
{item.human_description?.[language]}
|
{item.human_description?.[language]}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -192,9 +191,9 @@ const SettingBuiltInTool: FC<Props> = ({
|
|||||||
</>)}
|
</>)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
panelClassName='mt-[65px] !w-[405px]'
|
panelClassName='mt-[64px] mb-2 !w-[420px]'
|
||||||
maxWidthClassName='!max-w-[405px]'
|
maxWidthClassName='!max-w-[420px]'
|
||||||
height='calc(100vh - 65px)'
|
height='calc(100vh - 64px)'
|
||||||
headerClassName='!border-b-black/5'
|
headerClassName='!border-b-black/5'
|
||||||
body={
|
body={
|
||||||
<div className='h-full pt-3'>
|
<div className='h-full pt-3'>
|
||||||
@ -203,7 +202,7 @@ const SettingBuiltInTool: FC<Props> = ({
|
|||||||
<Loading type='app' />
|
<Loading type='app' />
|
||||||
</div>
|
</div>
|
||||||
: (<div className='flex flex-col h-full'>
|
: (<div className='flex flex-col h-full'>
|
||||||
<div className='grow h-0 overflow-y-auto px-6'>
|
<div className='grow h-0 overflow-y-auto px-4'>
|
||||||
{isInfoActive ? infoUI : settingUI}
|
{isInfoActive ? infoUI : settingUI}
|
||||||
</div>
|
</div>
|
||||||
{!readonly && !isInfoActive && (
|
{!readonly && !isInfoActive && (
|
||||||
|
@ -34,7 +34,7 @@ import { LoveMessage } from '@/app/components/base/icons/src/vender/features'
|
|||||||
import type { AutomaticRes } from '@/service/debug'
|
import type { AutomaticRes } from '@/service/debug'
|
||||||
import { Generator } from '@/app/components/base/icons/src/vender/other'
|
import { Generator } from '@/app/components/base/icons/src/vender/other'
|
||||||
|
|
||||||
export type IGetAutomaticResProps = {
|
export interface IGetAutomaticResProps {
|
||||||
mode: AppType
|
mode: AppType
|
||||||
model: Model
|
model: Model
|
||||||
isShow: boolean
|
isShow: boolean
|
||||||
|
@ -11,7 +11,7 @@ import AgentTools from './agent/agent-tools'
|
|||||||
import ConfigContext from '@/context/debug-configuration'
|
import ConfigContext from '@/context/debug-configuration'
|
||||||
import ConfigPrompt from '@/app/components/app/configuration/config-prompt'
|
import ConfigPrompt from '@/app/components/app/configuration/config-prompt'
|
||||||
import ConfigVar from '@/app/components/app/configuration/config-var'
|
import ConfigVar from '@/app/components/app/configuration/config-var'
|
||||||
import { type ModelConfig, type PromptVariable } from '@/models/debug'
|
import type { ModelConfig, PromptVariable } from '@/models/debug'
|
||||||
import type { AppType } from '@/types/app'
|
import type { AppType } from '@/types/app'
|
||||||
import { ModelModeType } from '@/types/app'
|
import { ModelModeType } from '@/types/app'
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import { useSelectedDatasetsMode } from '@/app/components/workflow/nodes/knowled
|
|||||||
import Switch from '@/app/components/base/switch'
|
import Switch from '@/app/components/base/switch'
|
||||||
import Toast from '@/app/components/base/toast'
|
import Toast from '@/app/components/base/toast'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
datasetConfigs: DatasetConfigs
|
datasetConfigs: DatasetConfigs
|
||||||
onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void
|
onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void
|
||||||
isInWorkflow?: boolean
|
isInWorkflow?: boolean
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
getMultipleRetrievalConfig,
|
getMultipleRetrievalConfig,
|
||||||
} from '@/app/components/workflow/nodes/knowledge-retrieval/utils'
|
} from '@/app/components/workflow/nodes/knowledge-retrieval/utils'
|
||||||
|
|
||||||
type ParamsConfigProps = {
|
interface ParamsConfigProps {
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
selectedDatasets: DataSet[]
|
selectedDatasets: DataSet[]
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ import { ModelTypeEnum } from '@/app/components/header/account-setting/model-pro
|
|||||||
import { fetchMembers } from '@/service/common'
|
import { fetchMembers } from '@/service/common'
|
||||||
import type { Member } from '@/models/common'
|
import type { Member } from '@/models/common'
|
||||||
|
|
||||||
type SettingsModalProps = {
|
interface SettingsModalProps {
|
||||||
currentDataset: DataSet
|
currentDataset: DataSet
|
||||||
onCancel: () => void
|
onCancel: () => void
|
||||||
onSave: (newDataset: DataSet) => void
|
onSave: (newDataset: DataSet) => void
|
||||||
|
@ -30,7 +30,7 @@ import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-
|
|||||||
import { useFeatures } from '@/app/components/base/features/hooks'
|
import { useFeatures } from '@/app/components/base/features/hooks'
|
||||||
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
||||||
|
|
||||||
type ChatItemProps = {
|
interface ChatItemProps {
|
||||||
modelAndParameter: ModelAndParameter
|
modelAndParameter: ModelAndParameter
|
||||||
}
|
}
|
||||||
const ChatItem: FC<ChatItemProps> = ({
|
const ChatItem: FC<ChatItemProps> = ({
|
||||||
|
@ -15,7 +15,7 @@ import { useEventEmitterContextContext } from '@/context/event-emitter'
|
|||||||
import { useProviderContext } from '@/context/provider-context'
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
import { useFeatures } from '@/app/components/base/features/hooks'
|
import { useFeatures } from '@/app/components/base/features/hooks'
|
||||||
|
|
||||||
type TextGenerationItemProps = {
|
interface TextGenerationItemProps {
|
||||||
modelAndParameter: ModelAndParameter
|
modelAndParameter: ModelAndParameter
|
||||||
}
|
}
|
||||||
const TextGenerationItem: FC<TextGenerationItemProps> = ({
|
const TextGenerationItem: FC<TextGenerationItemProps> = ({
|
||||||
|
@ -27,10 +27,10 @@ import { useFeatures } from '@/app/components/base/features/hooks'
|
|||||||
import { getLastAnswer } from '@/app/components/base/chat/utils'
|
import { getLastAnswer } from '@/app/components/base/chat/utils'
|
||||||
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
||||||
|
|
||||||
type DebugWithSingleModelProps = {
|
interface DebugWithSingleModelProps {
|
||||||
checkCanSend?: () => boolean
|
checkCanSend?: () => boolean
|
||||||
}
|
}
|
||||||
export type DebugWithSingleModelRefType = {
|
export interface DebugWithSingleModelRefType {
|
||||||
handleRestart: () => void
|
handleRestart: () => void
|
||||||
}
|
}
|
||||||
const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSingleModelProps>(({
|
const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSingleModelProps>(({
|
||||||
|
@ -48,7 +48,7 @@ import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
|||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||||
|
|
||||||
type IDebug = {
|
interface IDebug {
|
||||||
isAPIKeySet: boolean
|
isAPIKeySet: boolean
|
||||||
onSetting: () => void
|
onSetting: () => void
|
||||||
inputs: Inputs
|
inputs: Inputs
|
||||||
|
@ -59,7 +59,7 @@ import {
|
|||||||
useTextGenerationCurrentProviderAndModelAndModelList,
|
useTextGenerationCurrentProviderAndModelAndModelList,
|
||||||
} from '@/app/components/header/account-setting/model-provider-page/hooks'
|
} from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||||
import { fetchCollectionList } from '@/service/tools'
|
import { fetchCollectionList } from '@/service/tools'
|
||||||
import { type Collection } from '@/app/components/tools/types'
|
import type { Collection } from '@/app/components/tools/types'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import {
|
import {
|
||||||
getMultipleRetrievalConfig,
|
getMultipleRetrievalConfig,
|
||||||
@ -72,7 +72,7 @@ import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
|||||||
import NewFeaturePanel from '@/app/components/base/features/new-feature-panel'
|
import NewFeaturePanel from '@/app/components/base/features/new-feature-panel'
|
||||||
import { fetchFileUploadConfig } from '@/service/common'
|
import { fetchFileUploadConfig } from '@/service/common'
|
||||||
|
|
||||||
type PublishConfig = {
|
interface PublishConfig {
|
||||||
modelConfig: ModelConfig
|
modelConfig: ModelConfig
|
||||||
completionParams: FormValue
|
completionParams: FormValue
|
||||||
}
|
}
|
||||||
@ -156,7 +156,6 @@ const Configuration: FC = () => {
|
|||||||
const setCompletionParams = (value: FormValue) => {
|
const setCompletionParams = (value: FormValue) => {
|
||||||
const params = { ...value }
|
const params = { ...value }
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
||||||
if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) {
|
if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) {
|
||||||
params.stop = getTempStop()
|
params.stop = getTempStop()
|
||||||
setTempStop([])
|
setTempStop([])
|
||||||
@ -351,7 +350,6 @@ const Configuration: FC = () => {
|
|||||||
const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true)
|
const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true)
|
||||||
const setPromptMode = async (mode: PromptMode) => {
|
const setPromptMode = async (mode: PromptMode) => {
|
||||||
if (mode === PromptMode.advanced) {
|
if (mode === PromptMode.advanced) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
||||||
await migrateToDefaultPrompt()
|
await migrateToDefaultPrompt()
|
||||||
setCanReturnToSimpleMode(true)
|
setCanReturnToSimpleMode(true)
|
||||||
}
|
}
|
||||||
@ -589,7 +587,6 @@ const Configuration: FC = () => {
|
|||||||
annotation_reply: modelConfig.annotation_reply,
|
annotation_reply: modelConfig.annotation_reply,
|
||||||
external_data_tools: modelConfig.external_data_tools,
|
external_data_tools: modelConfig.external_data_tools,
|
||||||
dataSets: datasets || [],
|
dataSets: datasets || [],
|
||||||
// eslint-disable-next-line multiline-ternary
|
|
||||||
agentConfig: res.mode === 'agent-chat' ? {
|
agentConfig: res.mode === 'agent-chat' ? {
|
||||||
max_iteration: DEFAULT_AGENT_SETTING.max_iteration,
|
max_iteration: DEFAULT_AGENT_SETTING.max_iteration,
|
||||||
...modelConfig.agent_mode,
|
...modelConfig.agent_mode,
|
||||||
|
@ -23,7 +23,7 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config'
|
|||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
export type IPromptValuePanelProps = {
|
export interface IPromptValuePanelProps {
|
||||||
appType: AppType
|
appType: AppType
|
||||||
onSend?: () => void
|
onSend?: () => void
|
||||||
inputs: Inputs
|
inputs: Inputs
|
||||||
|
@ -21,13 +21,13 @@ import { useToastContext } from '@/app/components/base/toast'
|
|||||||
import AppIcon from '@/app/components/base/app-icon'
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
|
|
||||||
const systemTypes = ['api']
|
const systemTypes = ['api']
|
||||||
type ExternalDataToolModalProps = {
|
interface ExternalDataToolModalProps {
|
||||||
data: ExternalDataTool
|
data: ExternalDataTool
|
||||||
onCancel: () => void
|
onCancel: () => void
|
||||||
onSave: (externalDataTool: ExternalDataTool) => void
|
onSave: (externalDataTool: ExternalDataTool) => void
|
||||||
onValidateBeforeSave?: (externalDataTool: ExternalDataTool) => boolean
|
onValidateBeforeSave?: (externalDataTool: ExternalDataTool) => boolean
|
||||||
}
|
}
|
||||||
type Provider = {
|
interface Provider {
|
||||||
key: string
|
key: string
|
||||||
name: string
|
name: string
|
||||||
form_schema?: CodeBasedExtensionItem['form_schema']
|
form_schema?: CodeBasedExtensionItem['form_schema']
|
||||||
|
@ -29,7 +29,7 @@ import Tooltip from '@/app/components/base/tooltip'
|
|||||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||||
import { getRedirection } from '@/utils/app-redirection'
|
import { getRedirection } from '@/utils/app-redirection'
|
||||||
|
|
||||||
type CreateAppDialogProps = {
|
interface CreateAppDialogProps {
|
||||||
show: boolean
|
show: boolean
|
||||||
onSuccess: () => void
|
onSuccess: () => void
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
|
@ -22,7 +22,7 @@ import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
|||||||
import { getRedirection } from '@/utils/app-redirection'
|
import { getRedirection } from '@/utils/app-redirection'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
type CreateFromDSLModalProps = {
|
interface CreateFromDSLModalProps {
|
||||||
show: boolean
|
show: boolean
|
||||||
onSuccess?: () => void
|
onSuccess?: () => void
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
|
@ -13,7 +13,7 @@ import { useProviderContext } from '@/context/provider-context'
|
|||||||
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
||||||
import type { AppIconType } from '@/types/app'
|
import type { AppIconType } from '@/types/app'
|
||||||
|
|
||||||
export type DuplicateAppModalProps = {
|
export interface DuplicateAppModalProps {
|
||||||
appName: string
|
appName: string
|
||||||
icon_type: AppIconType | null
|
icon_type: AppIconType | null
|
||||||
icon: string
|
icon: string
|
||||||
|
@ -12,7 +12,7 @@ import { PageType } from '@/app/components/base/features/new-feature-panel/annot
|
|||||||
import TabSlider from '@/app/components/base/tab-slider-plain'
|
import TabSlider from '@/app/components/base/tab-slider-plain'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
pageType: PageType
|
pageType: PageType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ export const TIME_PERIOD_LIST = [
|
|||||||
{ value: 'all', name: 'allTime' },
|
{ value: 'all', name: 'allTime' },
|
||||||
]
|
]
|
||||||
|
|
||||||
type IFilterProps = {
|
interface IFilterProps {
|
||||||
isChatMode?: boolean
|
isChatMode?: boolean
|
||||||
appId: string
|
appId: string
|
||||||
queryParams: QueryParam
|
queryParams: QueryParam
|
||||||
|
@ -17,11 +17,11 @@ import Loading from '@/app/components/base/loading'
|
|||||||
import { fetchChatConversations, fetchCompletionConversations } from '@/service/log'
|
import { fetchChatConversations, fetchCompletionConversations } from '@/service/log'
|
||||||
import { APP_PAGE_LIMIT } from '@/config'
|
import { APP_PAGE_LIMIT } from '@/config'
|
||||||
import type { App, AppMode } from '@/types/app'
|
import type { App, AppMode } from '@/types/app'
|
||||||
export type ILogsProps = {
|
export interface ILogsProps {
|
||||||
appDetail: App
|
appDetail: App
|
||||||
}
|
}
|
||||||
|
|
||||||
export type QueryParam = {
|
export interface QueryParam {
|
||||||
period?: number | string
|
period?: number | string
|
||||||
annotation_status?: string
|
annotation_status?: string
|
||||||
keyword?: string
|
keyword?: string
|
||||||
|
@ -47,7 +47,7 @@ import { getProcessedFilesFromResponse } from '@/app/components/base/file-upload
|
|||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
|
|
||||||
type IConversationList = {
|
interface IConversationList {
|
||||||
logs?: ChatConversationsResponse | CompletionConversationsResponse
|
logs?: ChatConversationsResponse | CompletionConversationsResponse
|
||||||
appDetail: App
|
appDetail: App
|
||||||
onRefresh: () => void
|
onRefresh: () => void
|
||||||
@ -55,7 +55,7 @@ type IConversationList = {
|
|||||||
|
|
||||||
const defaultValue = 'N/A'
|
const defaultValue = 'N/A'
|
||||||
|
|
||||||
type IDrawerContext = {
|
interface IDrawerContext {
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
appDetail?: App
|
appDetail?: App
|
||||||
}
|
}
|
||||||
@ -158,7 +158,7 @@ const getFormattedChatList = (messages: ChatMessage[], conversationId: string, t
|
|||||||
// const displayedParams = CompletionParams.slice(0, -2)
|
// const displayedParams = CompletionParams.slice(0, -2)
|
||||||
const validatedParams = ['temperature', 'top_p', 'presence_penalty', 'frequency_penalty']
|
const validatedParams = ['temperature', 'top_p', 'presence_penalty', 'frequency_penalty']
|
||||||
|
|
||||||
type IDetailPanel = {
|
interface IDetailPanel {
|
||||||
detail: any
|
detail: any
|
||||||
onFeedback: FeedbackFunc
|
onFeedback: FeedbackFunc
|
||||||
onSubmitAnnotation: SubmitAnnotationFunc
|
onSubmitAnnotation: SubmitAnnotationFunc
|
||||||
|
@ -20,7 +20,7 @@ const Progress: FC<IProgressProps> = ({
|
|||||||
className={cn(s.bar, exhausted && s['bar-error'], 'absolute top-0 left-0 right-0 bottom-0')}
|
className={cn(s.bar, exhausted && s['bar-error'], 'absolute top-0 left-0 right-0 bottom-0')}
|
||||||
style={{ width: `${value}%` }}
|
style={{ width: `${value}%` }}
|
||||||
/>
|
/>
|
||||||
{Array(10).fill(0).map((i, k) => (
|
{Array.from({ length: 10 }).fill(0).map((i, k) => (
|
||||||
<div key={k} className={s['bar-item']} />
|
<div key={k} className={s['bar-item']} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -243,7 +243,7 @@ const Chart: React.FC<IChartProps> = ({
|
|||||||
? ''
|
? ''
|
||||||
: <span>{t('appOverview.analysis.tokenUsage.consumed')} Tokens<span className='text-sm'>
|
: <span>{t('appOverview.analysis.tokenUsage.consumed')} Tokens<span className='text-sm'>
|
||||||
<span className='ml-1 text-gray-500'>(</span>
|
<span className='ml-1 text-gray-500'>(</span>
|
||||||
<span className='text-orange-400'>~{sum(statistics.map(item => parseFloat(get(item, 'total_price', '0')))).toLocaleString('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 4 })}</span>
|
<span className='text-orange-400'>~{sum(statistics.map(item => Number.parseFloat(get(item, 'total_price', '0')))).toLocaleString('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 4 })}</span>
|
||||||
<span className='text-gray-500'>)</span>
|
<span className='text-gray-500'>)</span>
|
||||||
</span></span>}
|
</span></span>}
|
||||||
textStyle={{ main: `!text-3xl !font-normal ${sumData === 0 ? '!text-gray-300' : ''}` }} />
|
textStyle={{ main: `!text-3xl !font-normal ${sumData === 0 ? '!text-gray-300' : ''}` }} />
|
||||||
|
@ -22,7 +22,7 @@ import AppContext, { useAppContext } from '@/context/app-context'
|
|||||||
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
||||||
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
||||||
|
|
||||||
export type ISettingsModalProps = {
|
export interface ISettingsModalProps {
|
||||||
isChat: boolean
|
isChat: boolean
|
||||||
appInfo: AppDetailResponse & Partial<AppSSO>
|
appInfo: AppDetailResponse & Partial<AppSSO>
|
||||||
isShow: boolean
|
isShow: boolean
|
||||||
@ -31,7 +31,7 @@ export type ISettingsModalProps = {
|
|||||||
onSave?: (params: ConfigParams) => Promise<void>
|
onSave?: (params: ConfigParams) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ConfigParams = {
|
export interface ConfigParams {
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
default_language: string
|
default_language: string
|
||||||
|
@ -2,7 +2,7 @@ import { create } from 'zustand'
|
|||||||
import type { App, AppSSO } from '@/types/app'
|
import type { App, AppSSO } from '@/types/app'
|
||||||
import type { IChatItem } from '@/app/components/base/chat/chat/type'
|
import type { IChatItem } from '@/app/components/base/chat/chat/type'
|
||||||
|
|
||||||
type State = {
|
interface State {
|
||||||
appDetail?: App & Partial<AppSSO>
|
appDetail?: App & Partial<AppSSO>
|
||||||
appSidebarExpand: string
|
appSidebarExpand: string
|
||||||
currentLogItem?: IChatItem
|
currentLogItem?: IChatItem
|
||||||
@ -13,7 +13,7 @@ type State = {
|
|||||||
showAppConfigureFeaturesModal: boolean
|
showAppConfigureFeaturesModal: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type Action = {
|
interface Action {
|
||||||
setAppDetail: (appDetail?: App & Partial<AppSSO>) => void
|
setAppDetail: (appDetail?: App & Partial<AppSSO>) => void
|
||||||
setAppSiderbarExpand: (state: string) => void
|
setAppSiderbarExpand: (state: string) => void
|
||||||
setCurrentLogItem: (item?: IChatItem) => void
|
setCurrentLogItem: (item?: IChatItem) => void
|
||||||
|
@ -25,7 +25,7 @@ import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/aler
|
|||||||
import AppIcon from '@/app/components/base/app-icon'
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
|
||||||
type SwitchAppModalProps = {
|
interface SwitchAppModalProps {
|
||||||
show: boolean
|
show: boolean
|
||||||
appDetail: App
|
appDetail: App
|
||||||
onSuccess?: () => void
|
onSuccess?: () => void
|
||||||
|
@ -33,7 +33,7 @@ import { useChatContext } from '@/app/components/base/chat/chat/context'
|
|||||||
|
|
||||||
const MAX_DEPTH = 3
|
const MAX_DEPTH = 3
|
||||||
|
|
||||||
export type IGenerationItemProps = {
|
export interface IGenerationItemProps {
|
||||||
isWorkflow?: boolean
|
isWorkflow?: boolean
|
||||||
workflowProcessData?: WorkflowProcess
|
workflowProcessData?: WorkflowProcess
|
||||||
className?: string
|
className?: string
|
||||||
|
@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { RiCloseLine } from '@remixicon/react'
|
import { RiCloseLine } from '@remixicon/react'
|
||||||
import Run from '@/app/components/workflow/run'
|
import Run from '@/app/components/workflow/run'
|
||||||
|
|
||||||
type ILogDetail = {
|
interface ILogDetail {
|
||||||
runID: string
|
runID: string
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import type { QueryParam } from './index'
|
|||||||
import Chip from '@/app/components/base/chip'
|
import Chip from '@/app/components/base/chip'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
|
|
||||||
type IFilterProps = {
|
interface IFilterProps {
|
||||||
queryParams: QueryParam
|
queryParams: QueryParam
|
||||||
setQueryParams: (v: QueryParam) => void
|
setQueryParams: (v: QueryParam) => void
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,11 @@ import { fetchWorkflowLogs } from '@/service/log'
|
|||||||
import { APP_PAGE_LIMIT } from '@/config'
|
import { APP_PAGE_LIMIT } from '@/config'
|
||||||
import type { App, AppMode } from '@/types/app'
|
import type { App, AppMode } from '@/types/app'
|
||||||
|
|
||||||
export type ILogsProps = {
|
export interface ILogsProps {
|
||||||
appDetail: App
|
appDetail: App
|
||||||
}
|
}
|
||||||
|
|
||||||
export type QueryParam = {
|
export interface QueryParam {
|
||||||
status?: string
|
status?: string
|
||||||
keyword?: string
|
keyword?: string
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import Indicator from '@/app/components/header/indicator'
|
|||||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||||
import useTimestamp from '@/hooks/use-timestamp'
|
import useTimestamp from '@/hooks/use-timestamp'
|
||||||
|
|
||||||
type ILogs = {
|
interface ILogs {
|
||||||
logs?: WorkflowLogsResponse
|
logs?: WorkflowLogsResponse
|
||||||
appDetail?: App
|
appDetail?: App
|
||||||
onRefresh: () => void
|
onRefresh: () => void
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
.action-btn {
|
.action-btn {
|
||||||
@apply inline-flex justify-center items-center cursor-pointer text-text-tertiary
|
@apply inline-flex justify-center items-center cursor-pointer text-text-tertiary hover:text-text-secondary hover:bg-state-base-hover
|
||||||
hover:text-text-secondary
|
|
||||||
hover:bg-state-base-hover
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn-disabled {
|
.action-btn-disabled {
|
||||||
@ -29,21 +27,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action-btn.action-btn-active {
|
.action-btn.action-btn-active {
|
||||||
@apply
|
@apply text-text-accent bg-state-accent-active hover:bg-state-accent-active-alt
|
||||||
text-text-accent
|
|
||||||
bg-state-accent-active
|
|
||||||
hover:bg-state-accent-active-alt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn.action-btn-disabled {
|
.action-btn.action-btn-disabled {
|
||||||
@apply
|
@apply text-text-disabled
|
||||||
text-text-disabled
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn.action-btn-destructive {
|
.action-btn.action-btn-destructive {
|
||||||
@apply
|
@apply text-text-destructive bg-state-destructive-hover
|
||||||
text-text-destructive
|
|
||||||
bg-state-destructive-hover
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -28,7 +28,7 @@ const actionButtonVariants = cva(
|
|||||||
)
|
)
|
||||||
|
|
||||||
export type ActionButtonProps = {
|
export type ActionButtonProps = {
|
||||||
size?: 'xs' | 'm' | 'l' | 'xl'
|
size?: 'xs' | 's' | 'm' | 'l' | 'xl'
|
||||||
state?: ActionButtonState
|
state?: ActionButtonState
|
||||||
styleCss?: CSSProperties
|
styleCss?: CSSProperties
|
||||||
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof actionButtonVariants>
|
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof actionButtonVariants>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import AudioPlayer from '@/app/components/base/audio-btn/audio'
|
import AudioPlayer from '@/app/components/base/audio-btn/audio'
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
// eslint-disable-next-line ts/consistent-type-definitions
|
||||||
interface AudioPlayerManager {
|
interface AudioPlayerManager {
|
||||||
instance: AudioPlayerManager
|
instance: AudioPlayerManager
|
||||||
}
|
}
|
||||||
@ -12,6 +12,7 @@ export class AudioPlayerManager {
|
|||||||
private audioPlayers: AudioPlayer | null = null
|
private audioPlayers: AudioPlayer | null = null
|
||||||
private msgId: string | undefined
|
private msgId: string | undefined
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
private constructor() {
|
private constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import Toast from '@/app/components/base/toast'
|
|||||||
import { textToAudioStream } from '@/service/share'
|
import { textToAudioStream } from '@/service/share'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
// eslint-disable-next-line ts/consistent-type-definitions
|
||||||
interface Window {
|
interface Window {
|
||||||
ManagedMediaSource: any
|
ManagedMediaSource: any
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import Tooltip from '@/app/components/base/tooltip'
|
|||||||
import Loading from '@/app/components/base/loading'
|
import Loading from '@/app/components/base/loading'
|
||||||
import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
|
import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
|
||||||
|
|
||||||
type AudioBtnProps = {
|
interface AudioBtnProps {
|
||||||
id?: string
|
id?: string
|
||||||
voice?: string
|
voice?: string
|
||||||
value?: string
|
value?: string
|
||||||
|
@ -55,7 +55,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
|
|||||||
audio.load()
|
audio.load()
|
||||||
|
|
||||||
// Delayed generation of waveform data
|
// Delayed generation of waveform data
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
// eslint-disable-next-line ts/no-use-before-define
|
||||||
const timer = setTimeout(() => generateWaveformData(src), 1000)
|
const timer = setTimeout(() => generateWaveformData(src), 1000)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -49,4 +49,6 @@ const AutoHeightTextarea = forwardRef<HTMLTextAreaElement, AutoHeightTextareaPro
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AutoHeightTextarea.displayName = 'AutoHeightTextarea'
|
||||||
|
|
||||||
export default AutoHeightTextarea
|
export default AutoHeightTextarea
|
||||||
|
@ -5,22 +5,28 @@ type BadgeProps = {
|
|||||||
className?: string
|
className?: string
|
||||||
text: string
|
text: string
|
||||||
uppercase?: boolean
|
uppercase?: boolean
|
||||||
|
hasRedCornerMark?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const Badge = ({
|
const Badge = ({
|
||||||
className,
|
className,
|
||||||
text,
|
text,
|
||||||
uppercase = true,
|
uppercase = true,
|
||||||
|
hasRedCornerMark,
|
||||||
}: BadgeProps) => {
|
}: BadgeProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center px-[5px] h-5 rounded-[5px] border border-divider-deep leading-3 text-text-tertiary',
|
'relative inline-flex items-center px-[5px] h-5 rounded-[5px] border border-divider-deep leading-3 text-text-tertiary',
|
||||||
uppercase ? 'system-2xs-medium-uppercase' : 'system-xs-medium',
|
uppercase ? 'system-2xs-medium-uppercase' : 'system-xs-medium',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{text}
|
{text}
|
||||||
|
{hasRedCornerMark && (
|
||||||
|
<div className='absolute top-[-2px] right-[-2px] w-1.5 h-1.5 border border-components-badge-status-light-error-border-inner bg-components-badge-status-light-error-bg rounded-[2px] shadow-sm'>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
28
web/app/components/base/badge/index.css
Normal file
28
web/app/components/base/badge/index.css
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
@tailwind components;
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.badge {
|
||||||
|
@apply inline-flex justify-center items-center text-text-tertiary border border-divider-deep
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-l {
|
||||||
|
@apply rounded-md gap-1 min-w-6
|
||||||
|
}
|
||||||
|
|
||||||
|
/* m is for the regular button */
|
||||||
|
.badge-m {
|
||||||
|
@apply rounded-md gap-[3px] min-w-5
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-s {
|
||||||
|
@apply rounded-[5px] gap-0.5 min-w-[18px]
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.badge-warning {
|
||||||
|
@apply text-text-warning border border-text-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.badge-accent {
|
||||||
|
@apply text-text-accent-secondary border border-text-accent-secondary
|
||||||
|
}
|
||||||
|
}
|
81
web/app/components/base/badge/index.tsx
Normal file
81
web/app/components/base/badge/index.tsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import type { CSSProperties, ReactNode } from 'react'
|
||||||
|
import React from 'react'
|
||||||
|
import { type VariantProps, cva } from 'class-variance-authority'
|
||||||
|
import classNames from '@/utils/classnames'
|
||||||
|
import './index.css'
|
||||||
|
|
||||||
|
enum BadgeState {
|
||||||
|
Warning = 'warning',
|
||||||
|
Accent = 'accent',
|
||||||
|
Default = '',
|
||||||
|
}
|
||||||
|
|
||||||
|
const BadgeVariants = cva(
|
||||||
|
'badge',
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
size: {
|
||||||
|
s: 'badge-s',
|
||||||
|
m: 'badge-m',
|
||||||
|
l: 'badge-l',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
size: 'm',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
type BadgeProps = {
|
||||||
|
size?: 's' | 'm' | 'l'
|
||||||
|
iconOnly?: boolean
|
||||||
|
uppercase?: boolean
|
||||||
|
state?: BadgeState
|
||||||
|
styleCss?: CSSProperties
|
||||||
|
children?: ReactNode
|
||||||
|
} & React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof BadgeVariants>
|
||||||
|
|
||||||
|
function getBadgeState(state: BadgeState) {
|
||||||
|
switch (state) {
|
||||||
|
case BadgeState.Warning:
|
||||||
|
return 'badge-warning'
|
||||||
|
case BadgeState.Accent:
|
||||||
|
return 'badge-accent'
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Badge: React.FC<BadgeProps> = ({
|
||||||
|
className,
|
||||||
|
size,
|
||||||
|
state = BadgeState.Default,
|
||||||
|
iconOnly = false,
|
||||||
|
uppercase = false,
|
||||||
|
styleCss,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
BadgeVariants({ size, className }),
|
||||||
|
getBadgeState(state),
|
||||||
|
size === 's'
|
||||||
|
? (iconOnly ? 'p-[3px]' : 'px-[5px] py-[3px]')
|
||||||
|
: size === 'l'
|
||||||
|
? (iconOnly ? 'p-1.5' : 'px-2 py-1')
|
||||||
|
: (iconOnly ? 'p-1' : 'px-[5px] py-[2px]'),
|
||||||
|
uppercase ? 'system-2xs-medium-uppercase' : 'system-2xs-medium',
|
||||||
|
)}
|
||||||
|
style={styleCss}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Badge.displayName = 'Badge'
|
||||||
|
|
||||||
|
export default Badge
|
||||||
|
export { Badge, BadgeState, BadgeVariants }
|
@ -4,7 +4,7 @@ import React from 'react'
|
|||||||
import { RiAddLine } from '@remixicon/react'
|
import { RiAddLine } from '@remixicon/react'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import Textarea from '@/app/components/base/textarea'
|
import Textarea from '@/app/components/base/textarea'
|
||||||
|
|
||||||
type InputProps = {
|
interface InputProps {
|
||||||
form: any
|
form: any
|
||||||
value: string
|
value: string
|
||||||
onChange: (variable: string, value: string) => void
|
onChange: (variable: string, value: string) => void
|
||||||
|
@ -16,7 +16,7 @@ import type {
|
|||||||
ConversationItem,
|
ConversationItem,
|
||||||
} from '@/models/share'
|
} from '@/models/share'
|
||||||
|
|
||||||
export type ChatWithHistoryContextValue = {
|
export interface ChatWithHistoryContextValue {
|
||||||
appInfoError?: any
|
appInfoError?: any
|
||||||
appInfoLoading?: boolean
|
appInfoLoading?: boolean
|
||||||
appMeta?: AppMeta
|
appMeta?: AppMeta
|
||||||
|
@ -20,7 +20,7 @@ import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
|||||||
import { checkOrSetAccessToken } from '@/app/components/share/utils'
|
import { checkOrSetAccessToken } from '@/app/components/share/utils'
|
||||||
import AppUnavailable from '@/app/components/base/app-unavailable'
|
import AppUnavailable from '@/app/components/base/app-unavailable'
|
||||||
|
|
||||||
type ChatWithHistoryProps = {
|
interface ChatWithHistoryProps {
|
||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
||||||
@ -99,7 +99,7 @@ const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ChatWithHistoryWrapProps = {
|
export interface ChatWithHistoryWrapProps {
|
||||||
installedAppInfo?: InstalledApp
|
installedAppInfo?: InstalledApp
|
||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import Thought from '@/app/components/base/chat/chat/thought'
|
|||||||
import { FileList } from '@/app/components/base/file-uploader'
|
import { FileList } from '@/app/components/base/file-uploader'
|
||||||
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
|
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
|
||||||
|
|
||||||
type AgentContentProps = {
|
interface AgentContentProps {
|
||||||
item: ChatItem
|
item: ChatItem
|
||||||
responding?: boolean
|
responding?: boolean
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import type { ChatItem } from '../../types'
|
|||||||
import { Markdown } from '@/app/components/base/markdown'
|
import { Markdown } from '@/app/components/base/markdown'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
type BasicContentProps = {
|
interface BasicContentProps {
|
||||||
item: ChatItem
|
item: ChatItem
|
||||||
}
|
}
|
||||||
const BasicContent: FC<BasicContentProps> = ({
|
const BasicContent: FC<BasicContentProps> = ({
|
||||||
|
@ -23,7 +23,7 @@ import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { FileList } from '@/app/components/base/file-uploader'
|
import { FileList } from '@/app/components/base/file-uploader'
|
||||||
|
|
||||||
type AnswerProps = {
|
interface AnswerProps {
|
||||||
item: ChatItem
|
item: ChatItem
|
||||||
question: string
|
question: string
|
||||||
index: number
|
index: number
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import Log from '@/app/components/base/chat/chat/log'
|
import Log from '@/app/components/base/chat/chat/log'
|
||||||
|
|
||||||
type OperationProps = {
|
interface OperationProps {
|
||||||
item: ChatItem
|
item: ChatItem
|
||||||
question: string
|
question: string
|
||||||
index: number
|
index: number
|
||||||
|
@ -17,7 +17,7 @@ import { CheckCircle } from '@/app/components/base/icons/src/vender/solid/genera
|
|||||||
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
|
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
|
||||||
type WorkflowProcessProps = {
|
interface WorkflowProcessProps {
|
||||||
data: WorkflowProcess
|
data: WorkflowProcess
|
||||||
item?: ChatItem
|
item?: ChatItem
|
||||||
expand?: boolean
|
expand?: boolean
|
||||||
|
@ -33,7 +33,7 @@ import {
|
|||||||
} from '@/app/components/base/file-uploader/utils'
|
} from '@/app/components/base/file-uploader/utils'
|
||||||
|
|
||||||
type GetAbortController = (abortController: AbortController) => void
|
type GetAbortController = (abortController: AbortController) => void
|
||||||
type SendCallback = {
|
interface SendCallback {
|
||||||
onGetConversationMessages?: (conversationId: string, getAbortController: GetAbortController) => Promise<any>
|
onGetConversationMessages?: (conversationId: string, getAbortController: GetAbortController) => Promise<any>
|
||||||
onGetSuggestedQuestions?: (responseItemId: string, getAbortController: GetAbortController) => Promise<any>
|
onGetSuggestedQuestions?: (responseItemId: string, getAbortController: GetAbortController) => Promise<any>
|
||||||
onConversationComplete?: (conversationId: string) => void
|
onConversationComplete?: (conversationId: string) => void
|
||||||
|
@ -35,7 +35,7 @@ import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
|||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import type { AppData } from '@/models/share'
|
import type { AppData } from '@/models/share'
|
||||||
|
|
||||||
export type ChatProps = {
|
export interface ChatProps {
|
||||||
appData?: AppData
|
appData?: AppData
|
||||||
chatList: ChatItem[]
|
chatList: ChatItem[]
|
||||||
config?: ChatConfig
|
config?: ChatConfig
|
||||||
|
@ -12,7 +12,7 @@ import { User } from '@/app/components/base/icons/src/public/avatar'
|
|||||||
import { Markdown } from '@/app/components/base/markdown'
|
import { Markdown } from '@/app/components/base/markdown'
|
||||||
import { FileList } from '@/app/components/base/file-uploader'
|
import { FileList } from '@/app/components/base/file-uploader'
|
||||||
|
|
||||||
type QuestionProps = {
|
interface QuestionProps {
|
||||||
item: ChatItem
|
item: ChatItem
|
||||||
questionIcon?: ReactNode
|
questionIcon?: ReactNode
|
||||||
theme: Theme | null | undefined
|
theme: Theme | null | undefined
|
||||||
|
@ -4,7 +4,7 @@ import React from 'react'
|
|||||||
import type { ThoughtItem, ToolInfoInThought } from '../type'
|
import type { ThoughtItem, ToolInfoInThought } from '../type'
|
||||||
import ToolDetail from '@/app/components/base/chat/chat/answer/tool-detail'
|
import ToolDetail from '@/app/components/base/chat/chat/answer/tool-detail'
|
||||||
|
|
||||||
export type IThoughtProps = {
|
export interface IThoughtProps {
|
||||||
thought: ThoughtItem
|
thought: ThoughtItem
|
||||||
isFinished: boolean
|
isFinished: boolean
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@ import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
|||||||
import type { InputVarType } from '@/app/components/workflow/types'
|
import type { InputVarType } from '@/app/components/workflow/types'
|
||||||
import type { FileResponse } from '@/types/workflow'
|
import type { FileResponse } from '@/types/workflow'
|
||||||
|
|
||||||
export type MessageMore = {
|
export interface MessageMore {
|
||||||
time: string
|
time: string
|
||||||
tokens: number
|
tokens: number
|
||||||
latency: number | string
|
latency: number | string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FeedbackType = {
|
export interface FeedbackType {
|
||||||
rating: MessageRating
|
rating: MessageRating
|
||||||
content?: string | null
|
content?: string | null
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ export type SubmitAnnotationFunc = (
|
|||||||
|
|
||||||
export type DisplayScene = 'web' | 'console'
|
export type DisplayScene = 'web' | 'console'
|
||||||
|
|
||||||
export type ToolInfoInThought = {
|
export interface ToolInfoInThought {
|
||||||
name: string
|
name: string
|
||||||
label: string
|
label: string
|
||||||
input: string
|
input: string
|
||||||
@ -34,7 +34,7 @@ export type ToolInfoInThought = {
|
|||||||
isFinished: boolean
|
isFinished: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ThoughtItem = {
|
export interface ThoughtItem {
|
||||||
id: string
|
id: string
|
||||||
tool: string // plugin or dataset. May has multi.
|
tool: string // plugin or dataset. May has multi.
|
||||||
thought: string
|
thought: string
|
||||||
@ -47,7 +47,7 @@ export type ThoughtItem = {
|
|||||||
message_files?: FileEntity[]
|
message_files?: FileEntity[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CitationItem = {
|
export interface CitationItem {
|
||||||
content: string
|
content: string
|
||||||
data_source_type: string
|
data_source_type: string
|
||||||
dataset_name: string
|
dataset_name: string
|
||||||
@ -62,7 +62,7 @@ export type CitationItem = {
|
|||||||
word_count: number
|
word_count: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IChatItem = {
|
export interface IChatItem {
|
||||||
id: string
|
id: string
|
||||||
content: string
|
content: string
|
||||||
citation?: CitationItem[]
|
citation?: CitationItem[]
|
||||||
@ -104,7 +104,7 @@ export type IChatItem = {
|
|||||||
nextSibling?: string
|
nextSibling?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Metadata = {
|
export interface Metadata {
|
||||||
retriever_resources?: CitationItem[]
|
retriever_resources?: CitationItem[]
|
||||||
annotation_reply: {
|
annotation_reply: {
|
||||||
id: string
|
id: string
|
||||||
@ -115,20 +115,20 @@ export type Metadata = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MessageEnd = {
|
export interface MessageEnd {
|
||||||
id: string
|
id: string
|
||||||
metadata: Metadata
|
metadata: Metadata
|
||||||
files?: FileResponse[]
|
files?: FileResponse[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MessageReplace = {
|
export interface MessageReplace {
|
||||||
id: string
|
id: string
|
||||||
task_id: string
|
task_id: string
|
||||||
answer: string
|
answer: string
|
||||||
conversation_id: string
|
conversation_id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AnnotationReply = {
|
export interface AnnotationReply {
|
||||||
id: string
|
id: string
|
||||||
task_id: string
|
task_id: string
|
||||||
answer: string
|
answer: string
|
||||||
@ -137,7 +137,7 @@ export type AnnotationReply = {
|
|||||||
annotation_author_name: string
|
annotation_author_name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type InputForm = {
|
export interface InputForm {
|
||||||
type: InputVarType
|
type: InputVarType
|
||||||
label: string
|
label: string
|
||||||
variable: any
|
variable: any
|
||||||
|
@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import Textarea from '@/app/components/base/textarea'
|
import Textarea from '@/app/components/base/textarea'
|
||||||
|
|
||||||
type InputProps = {
|
interface InputProps {
|
||||||
form: any
|
form: any
|
||||||
value: string
|
value: string
|
||||||
onChange: (variable: string, value: string) => void
|
onChange: (variable: string, value: string) => void
|
||||||
|
@ -15,7 +15,7 @@ import type {
|
|||||||
ConversationItem,
|
ConversationItem,
|
||||||
} from '@/models/share'
|
} from '@/models/share'
|
||||||
|
|
||||||
export type EmbeddedChatbotContextValue = {
|
export interface EmbeddedChatbotContextValue {
|
||||||
appInfoError?: any
|
appInfoError?: any
|
||||||
appInfoLoading?: boolean
|
appInfoLoading?: boolean
|
||||||
appMeta?: AppMeta
|
appMeta?: AppMeta
|
||||||
|
@ -14,32 +14,32 @@ export type {
|
|||||||
PromptVariable,
|
PromptVariable,
|
||||||
} from '@/models/debug'
|
} from '@/models/debug'
|
||||||
|
|
||||||
export type UserInputForm = {
|
export interface UserInputForm {
|
||||||
default: string
|
default: string
|
||||||
label: string
|
label: string
|
||||||
required: boolean
|
required: boolean
|
||||||
variable: string
|
variable: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserInputFormTextInput = {
|
export interface UserInputFormTextInput {
|
||||||
'text-input': UserInputForm & {
|
'text-input': UserInputForm & {
|
||||||
max_length: number
|
max_length: number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserInputFormSelect = {
|
export interface UserInputFormSelect {
|
||||||
'select': UserInputForm & {
|
select: UserInputForm & {
|
||||||
options: string[]
|
options: string[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserInputFormParagraph = {
|
export interface UserInputFormParagraph {
|
||||||
'paragraph': UserInputForm
|
paragraph: UserInputForm
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VisionConfig = VisionSettings
|
export type VisionConfig = VisionSettings
|
||||||
|
|
||||||
export type EnableType = {
|
export interface EnableType {
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ export type ChatConfig = Omit<ModelConfig, 'model'> & {
|
|||||||
supportCitationHitInfo?: boolean
|
supportCitationHitInfo?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WorkflowProcess = {
|
export interface WorkflowProcess {
|
||||||
status: WorkflowRunningStatus
|
status: WorkflowRunningStatus
|
||||||
tracing: NodeTracing[]
|
tracing: NodeTracing[]
|
||||||
expand?: boolean // for UI
|
expand?: boolean // for UI
|
||||||
@ -73,10 +73,10 @@ export type OnSend = (message: string, files?: FileEntity[], last_answer?: ChatI
|
|||||||
|
|
||||||
export type OnRegenerate = (chatItem: ChatItem) => void
|
export type OnRegenerate = (chatItem: ChatItem) => void
|
||||||
|
|
||||||
export type Callback = {
|
export interface Callback {
|
||||||
onSuccess: () => void
|
onSuccess: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Feedback = {
|
export interface Feedback {
|
||||||
rating: 'like' | 'dislike' | null
|
rating: 'like' | 'dislike' | null
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { t } from 'i18next'
|
import { t } from 'i18next'
|
||||||
|
import { debounce } from 'lodash-es'
|
||||||
import copy from 'copy-to-clipboard'
|
import copy from 'copy-to-clipboard'
|
||||||
import s from './style.module.css'
|
import s from './style.module.css'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
@ -18,22 +19,29 @@ const CopyBtn = ({
|
|||||||
}: ICopyBtnProps) => {
|
}: ICopyBtnProps) => {
|
||||||
const [isCopied, setIsCopied] = useState(false)
|
const [isCopied, setIsCopied] = useState(false)
|
||||||
|
|
||||||
|
const onClickCopy = debounce(() => {
|
||||||
|
copy(value)
|
||||||
|
setIsCopied(true)
|
||||||
|
}, 100)
|
||||||
|
|
||||||
|
const onMouseLeave = debounce(() => {
|
||||||
|
setIsCopied(false)
|
||||||
|
}, 100)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${className}`}>
|
<div className={`${className}`}>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={(isCopied ? t('appApi.copied') : t('appApi.copy'))}
|
popupContent={(isCopied ? t('appApi.copied') : t('appApi.copy'))}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
onMouseLeave={onMouseLeave}
|
||||||
className={'box-border p-0.5 flex items-center justify-center rounded-md bg-white cursor-pointer'}
|
className={'box-border p-0.5 flex items-center justify-center rounded-md bg-white cursor-pointer'}
|
||||||
style={!isPlain
|
style={!isPlain
|
||||||
? {
|
? {
|
||||||
boxShadow: '0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06)',
|
boxShadow: '0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06)',
|
||||||
}
|
}
|
||||||
: {}}
|
: {}}
|
||||||
onClick={() => {
|
onClick={onClickCopy}
|
||||||
copy(value)
|
|
||||||
setIsCopied(true)
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className={`w-6 h-6 rounded-md hover:bg-gray-50 ${s.copyIcon} ${isCopied ? s.copied : ''}`}></div>
|
<div className={`w-6 h-6 rounded-md hover:bg-gray-50 ${s.copyIcon} ${isCopied ? s.copied : ''}`}></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,8 +12,9 @@ import Divider from '@/app/components/base/divider'
|
|||||||
import { searchEmoji } from '@/utils/emoji'
|
import { searchEmoji } from '@/utils/emoji'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
// eslint-disable-next-line ts/no-namespace
|
||||||
namespace JSX {
|
namespace JSX {
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
// eslint-disable-next-line ts/consistent-type-definitions
|
||||||
interface IntrinsicElements {
|
interface IntrinsicElements {
|
||||||
'em-emoji': React.DetailedHTMLProps< React.HTMLAttributes<HTMLElement>, HTMLElement >
|
'em-emoji': React.DetailedHTMLProps< React.HTMLAttributes<HTMLElement>, HTMLElement >
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,327 @@
|
|||||||
|
'use client'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
|
import produce from 'immer'
|
||||||
|
import {
|
||||||
|
RiAddLine,
|
||||||
|
RiDeleteBinLine,
|
||||||
|
} from '@remixicon/react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useBoolean } from 'ahooks'
|
||||||
|
import { ReactSortable } from 'react-sortablejs'
|
||||||
|
import {
|
||||||
|
useFeatures,
|
||||||
|
useFeaturesStore,
|
||||||
|
} from '../../hooks'
|
||||||
|
import type { OnFeaturesChange } from '../../types'
|
||||||
|
import cn from '@/utils/classnames'
|
||||||
|
import Panel from '@/app/components/app/configuration/base/feature-panel'
|
||||||
|
import Button from '@/app/components/base/button'
|
||||||
|
import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
|
||||||
|
import { getInputKeys } from '@/app/components/base/block-input'
|
||||||
|
import ConfirmAddVar from '@/app/components/app/configuration/config-prompt/confirm-add-var'
|
||||||
|
import { getNewVar } from '@/utils/var'
|
||||||
|
import { varHighlightHTML } from '@/app/components/app/configuration/base/var-highlight'
|
||||||
|
import type { PromptVariable } from '@/models/debug'
|
||||||
|
import type { InputVar } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
|
const MAX_QUESTION_NUM = 5
|
||||||
|
|
||||||
|
export type OpeningStatementProps = {
|
||||||
|
onChange?: OnFeaturesChange
|
||||||
|
readonly?: boolean
|
||||||
|
promptVariables?: PromptVariable[]
|
||||||
|
onAutoAddPromptVariable: (variable: PromptVariable[]) => void
|
||||||
|
workflowVariables?: InputVar[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// regex to match the {{}} and replace it with a span
|
||||||
|
const regex = /\{\{([^}]+)\}\}/g
|
||||||
|
|
||||||
|
const OpeningStatement: FC<OpeningStatementProps> = ({
|
||||||
|
onChange,
|
||||||
|
readonly,
|
||||||
|
promptVariables = [],
|
||||||
|
onAutoAddPromptVariable,
|
||||||
|
workflowVariables = [],
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const featureStore = useFeaturesStore()
|
||||||
|
const openingStatement = useFeatures(s => s.features.opening)
|
||||||
|
const value = openingStatement?.opening_statement || ''
|
||||||
|
const suggestedQuestions = openingStatement?.suggested_questions || []
|
||||||
|
const [notIncludeKeys, setNotIncludeKeys] = useState<string[]>([])
|
||||||
|
|
||||||
|
const hasValue = !!(value || '').trim()
|
||||||
|
const inputRef = useRef<HTMLTextAreaElement>(null)
|
||||||
|
|
||||||
|
const [isFocus, { setTrue: didSetFocus, setFalse: setBlur }] = useBoolean(false)
|
||||||
|
|
||||||
|
const setFocus = () => {
|
||||||
|
didSetFocus()
|
||||||
|
setTimeout(() => {
|
||||||
|
const input = inputRef.current
|
||||||
|
if (input) {
|
||||||
|
input.focus()
|
||||||
|
input.setSelectionRange(input.value.length, input.value.length)
|
||||||
|
}
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const [tempValue, setTempValue] = useState(value)
|
||||||
|
useEffect(() => {
|
||||||
|
setTempValue(value || '')
|
||||||
|
}, [value])
|
||||||
|
|
||||||
|
const [tempSuggestedQuestions, setTempSuggestedQuestions] = useState(suggestedQuestions || [])
|
||||||
|
const notEmptyQuestions = tempSuggestedQuestions.filter(question => !!question && question.trim())
|
||||||
|
const coloredContent = (tempValue || '')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(regex, varHighlightHTML({ name: '$1' })) // `<span class="${highLightClassName}">{{$1}}</span>`
|
||||||
|
.replace(/\n/g, '<br />')
|
||||||
|
|
||||||
|
const handleEdit = () => {
|
||||||
|
if (readonly)
|
||||||
|
return
|
||||||
|
setFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
const [isShowConfirmAddVar, { setTrue: showConfirmAddVar, setFalse: hideConfirmAddVar }] = useBoolean(false)
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
setBlur()
|
||||||
|
setTempValue(value)
|
||||||
|
setTempSuggestedQuestions(suggestedQuestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleConfirm = () => {
|
||||||
|
const keys = getInputKeys(tempValue)
|
||||||
|
const promptKeys = promptVariables.map(item => item.key)
|
||||||
|
const workflowVariableKeys = workflowVariables.map(item => item.variable)
|
||||||
|
let notIncludeKeys: string[] = []
|
||||||
|
|
||||||
|
if (promptKeys.length === 0 && workflowVariables.length === 0) {
|
||||||
|
if (keys.length > 0)
|
||||||
|
notIncludeKeys = keys
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (workflowVariables.length > 0)
|
||||||
|
notIncludeKeys = keys.filter(key => !workflowVariableKeys.includes(key))
|
||||||
|
|
||||||
|
else notIncludeKeys = keys.filter(key => !promptKeys.includes(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notIncludeKeys.length > 0) {
|
||||||
|
setNotIncludeKeys(notIncludeKeys)
|
||||||
|
showConfirmAddVar()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setBlur()
|
||||||
|
const { getState } = featureStore!
|
||||||
|
const {
|
||||||
|
features,
|
||||||
|
setFeatures,
|
||||||
|
} = getState()
|
||||||
|
|
||||||
|
const newFeatures = produce(features, (draft) => {
|
||||||
|
if (draft.opening) {
|
||||||
|
draft.opening.opening_statement = tempValue
|
||||||
|
draft.opening.suggested_questions = tempSuggestedQuestions
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setFeatures(newFeatures)
|
||||||
|
|
||||||
|
if (onChange)
|
||||||
|
onChange(newFeatures)
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancelAutoAddVar = () => {
|
||||||
|
const { getState } = featureStore!
|
||||||
|
const {
|
||||||
|
features,
|
||||||
|
setFeatures,
|
||||||
|
} = getState()
|
||||||
|
|
||||||
|
const newFeatures = produce(features, (draft) => {
|
||||||
|
if (draft.opening)
|
||||||
|
draft.opening.opening_statement = tempValue
|
||||||
|
})
|
||||||
|
setFeatures(newFeatures)
|
||||||
|
|
||||||
|
if (onChange)
|
||||||
|
onChange(newFeatures)
|
||||||
|
hideConfirmAddVar()
|
||||||
|
setBlur()
|
||||||
|
}
|
||||||
|
|
||||||
|
const autoAddVar = () => {
|
||||||
|
const { getState } = featureStore!
|
||||||
|
const {
|
||||||
|
features,
|
||||||
|
setFeatures,
|
||||||
|
} = getState()
|
||||||
|
|
||||||
|
const newFeatures = produce(features, (draft) => {
|
||||||
|
if (draft.opening)
|
||||||
|
draft.opening.opening_statement = tempValue
|
||||||
|
})
|
||||||
|
setFeatures(newFeatures)
|
||||||
|
if (onChange)
|
||||||
|
onChange(newFeatures)
|
||||||
|
onAutoAddPromptVariable([...notIncludeKeys.map(key => getNewVar(key, 'string'))])
|
||||||
|
hideConfirmAddVar()
|
||||||
|
setBlur()
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerRight = !readonly ? (
|
||||||
|
isFocus ? (
|
||||||
|
<div className='flex items-center space-x-1'>
|
||||||
|
<Button
|
||||||
|
variant='ghost'
|
||||||
|
size='small'
|
||||||
|
onClick={handleCancel}
|
||||||
|
>
|
||||||
|
{t('common.operation.cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button size='small' onClick={handleConfirm} variant="primary">{t('common.operation.save')}</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<OperationBtn type='edit' actionName={hasValue ? '' : t('appDebug.openingStatement.writeOpener') as string} onClick={handleEdit} />
|
||||||
|
)
|
||||||
|
) : null
|
||||||
|
|
||||||
|
const renderQuestions = () => {
|
||||||
|
return isFocus ? (
|
||||||
|
<div>
|
||||||
|
<div className='flex items-center py-2'>
|
||||||
|
<div className='shrink-0 flex space-x-0.5 leading-[18px] text-xs font-medium text-gray-500'>
|
||||||
|
<div className='uppercase'>{t('appDebug.openingStatement.openingQuestion')}</div>
|
||||||
|
<div>·</div>
|
||||||
|
<div>{tempSuggestedQuestions.length}/{MAX_QUESTION_NUM}</div>
|
||||||
|
</div>
|
||||||
|
<div className='ml-3 grow w-0 h-px bg-[#243, 244, 246]'></div>
|
||||||
|
</div>
|
||||||
|
<ReactSortable
|
||||||
|
className="space-y-1"
|
||||||
|
list={tempSuggestedQuestions.map((name, index) => {
|
||||||
|
return {
|
||||||
|
id: index,
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
setList={list => setTempSuggestedQuestions(list.map(item => item.name))}
|
||||||
|
handle='.handle'
|
||||||
|
ghostClass="opacity-50"
|
||||||
|
animation={150}
|
||||||
|
>
|
||||||
|
{tempSuggestedQuestions.map((question, index) => {
|
||||||
|
return (
|
||||||
|
<div className='group relative rounded-lg border border-gray-200 flex items-center pl-2.5 hover:border-gray-300 hover:bg-white' key={index}>
|
||||||
|
<div className='handle flex items-center justify-center w-4 h-4 cursor-grab'>
|
||||||
|
<svg width="6" height="10" viewBox="0 0 6 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fillRule="evenodd" clipRule="evenodd" d="M1 2C1.55228 2 2 1.55228 2 1C2 0.447715 1.55228 0 1 0C0.447715 0 0 0.447715 0 1C0 1.55228 0.447715 2 1 2ZM1 6C1.55228 6 2 5.55228 2 5C2 4.44772 1.55228 4 1 4C0.447715 4 0 4.44772 0 5C0 5.55228 0.447715 6 1 6ZM6 1C6 1.55228 5.55228 2 5 2C4.44772 2 4 1.55228 4 1C4 0.447715 4.44772 0 5 0C5.55228 0 6 0.447715 6 1ZM5 6C5.55228 6 6 5.55228 6 5C6 4.44772 5.55228 4 5 4C4.44772 4 4 4.44772 4 5C4 5.55228 4.44772 6 5 6ZM2 9C2 9.55229 1.55228 10 1 10C0.447715 10 0 9.55229 0 9C0 8.44771 0.447715 8 1 8C1.55228 8 2 8.44771 2 9ZM5 10C5.55228 10 6 9.55229 6 9C6 8.44771 5.55228 8 5 8C4.44772 8 4 8.44771 4 9C4 9.55229 4.44772 10 5 10Z" fill="#98A2B3" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="input"
|
||||||
|
value={question || ''}
|
||||||
|
onChange={(e) => {
|
||||||
|
const value = e.target.value
|
||||||
|
setTempSuggestedQuestions(tempSuggestedQuestions.map((item, i) => {
|
||||||
|
if (index === i)
|
||||||
|
return value
|
||||||
|
|
||||||
|
return item
|
||||||
|
}))
|
||||||
|
}}
|
||||||
|
className={'w-full overflow-x-auto pl-1.5 pr-8 text-sm leading-9 text-gray-900 border-0 grow h-9 bg-transparent focus:outline-none cursor-pointer rounded-lg'}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className='block absolute top-1/2 translate-y-[-50%] right-1.5 p-1 rounded-md cursor-pointer hover:bg-[#FEE4E2] hover:text-[#D92D20]'
|
||||||
|
onClick={() => {
|
||||||
|
setTempSuggestedQuestions(tempSuggestedQuestions.filter((_, i) => index !== i))
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RiDeleteBinLine className='w-3.5 h-3.5' />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}</ReactSortable>
|
||||||
|
{tempSuggestedQuestions.length < MAX_QUESTION_NUM && (
|
||||||
|
<div
|
||||||
|
onClick={() => { setTempSuggestedQuestions([...tempSuggestedQuestions, '']) }}
|
||||||
|
className='mt-1 flex items-center h-9 px-3 gap-2 rounded-lg cursor-pointer text-gray-400 bg-gray-100 hover:bg-gray-200'>
|
||||||
|
<RiAddLine className='w-4 h-4' />
|
||||||
|
<div className='text-gray-500 text-[13px]'>{t('appDebug.variableConfig.addOption')}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className='mt-1.5 flex flex-wrap'>
|
||||||
|
{notEmptyQuestions.map((question, index) => {
|
||||||
|
return (
|
||||||
|
<div key={index} className='mt-1 mr-1 max-w-full truncate last:mr-0 shrink-0 leading-8 items-center px-2.5 rounded-lg border border-gray-200 shadow-xs bg-white text-[13px] font-normal text-gray-900 cursor-pointer'>
|
||||||
|
{question}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Panel
|
||||||
|
className={cn(isShowConfirmAddVar && 'h-[220px]', 'relative !bg-gray-25')}
|
||||||
|
title={t('appDebug.openingStatement.title')}
|
||||||
|
headerIcon={
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fillRule="evenodd" clipRule="evenodd" d="M8.33353 1.33301C4.83572 1.33301 2.00019 4.16854 2.00019 7.66634C2.00019 8.37301 2.11619 9.05395 2.3307 9.69036C2.36843 9.80229 2.39063 9.86853 2.40507 9.91738L2.40979 9.93383L2.40729 9.93903C2.39015 9.97437 2.36469 10.0218 2.31705 10.11L1.2158 12.1484C1.14755 12.2746 1.07633 12.4064 1.02735 12.5209C0.978668 12.6348 0.899813 12.8437 0.938613 13.0914C0.984094 13.3817 1.15495 13.6373 1.40581 13.7903C1.61981 13.9208 1.843 13.9279 1.96683 13.9264C2.09141 13.925 2.24036 13.9095 2.38314 13.8947L5.81978 13.5395C5.87482 13.5338 5.9036 13.5309 5.92468 13.5292L5.92739 13.529L5.93564 13.532C5.96154 13.5413 5.99666 13.5548 6.0573 13.5781C6.76459 13.8506 7.53244 13.9997 8.33353 13.9997C11.8313 13.9997 14.6669 11.1641 14.6669 7.66634C14.6669 4.16854 11.8313 1.33301 8.33353 1.33301ZM5.9799 5.72116C6.73142 5.08698 7.73164 5.27327 8.33144 5.96584C8.93125 5.27327 9.91854 5.09365 10.683 5.72116C11.4474 6.34867 11.5403 7.41567 10.9501 8.16572C10.5845 8.6304 9.6668 9.47911 9.02142 10.0576C8.78435 10.2702 8.66582 10.3764 8.52357 10.4192C8.40154 10.456 8.26134 10.456 8.13931 10.4192C7.99706 10.3764 7.87853 10.2702 7.64147 10.0576C6.99609 9.47911 6.07839 8.6304 5.71276 8.16572C5.12259 7.41567 5.22839 6.35534 5.9799 5.72116Z" fill="#E74694" />
|
||||||
|
</svg>
|
||||||
|
}
|
||||||
|
headerRight={headerRight}
|
||||||
|
hasHeaderBottomBorder={!hasValue}
|
||||||
|
isFocus={isFocus}
|
||||||
|
>
|
||||||
|
<div className='text-gray-700 text-sm'>
|
||||||
|
{(hasValue || (!hasValue && isFocus)) ? (
|
||||||
|
<>
|
||||||
|
{isFocus
|
||||||
|
? (
|
||||||
|
<div>
|
||||||
|
<textarea
|
||||||
|
ref={inputRef}
|
||||||
|
value={tempValue}
|
||||||
|
rows={3}
|
||||||
|
onChange={e => setTempValue(e.target.value)}
|
||||||
|
className="w-full px-0 text-sm border-0 bg-transparent focus:outline-none "
|
||||||
|
placeholder={t('appDebug.openingStatement.placeholder') as string}
|
||||||
|
>
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<div dangerouslySetInnerHTML={{
|
||||||
|
__html: coloredContent,
|
||||||
|
}}></div>
|
||||||
|
)}
|
||||||
|
{renderQuestions()}
|
||||||
|
</>) : (
|
||||||
|
<div className='pt-2 pb-1 text-xs text-gray-500'>{t('appDebug.openingStatement.noDataPlaceHolder')}</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isShowConfirmAddVar && (
|
||||||
|
<ConfirmAddVar
|
||||||
|
varNameArr={notIncludeKeys}
|
||||||
|
onConfirm={autoAddVar}
|
||||||
|
onCancel={cancelAutoAddVar}
|
||||||
|
onHide={hideConfirmAddVar}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</Panel>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default React.memo(OpeningStatement)
|
@ -2,16 +2,16 @@ import { createStore } from 'zustand'
|
|||||||
import type { Features } from './types'
|
import type { Features } from './types'
|
||||||
import { Resolution, TransferMethod } from '@/types/app'
|
import { Resolution, TransferMethod } from '@/types/app'
|
||||||
|
|
||||||
export type FeaturesModal = {
|
export interface FeaturesModal {
|
||||||
showFeaturesModal: boolean
|
showFeaturesModal: boolean
|
||||||
setShowFeaturesModal: (showFeaturesModal: boolean) => void
|
setShowFeaturesModal: (showFeaturesModal: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FeaturesState = {
|
export interface FeaturesState {
|
||||||
features: Features
|
features: Features
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FeaturesAction = {
|
export interface FeaturesAction {
|
||||||
setFeatures: (features: Features) => void
|
setFeatures: (features: Features) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { Resolution, TransferMethod, TtsAutoPlay } from '@/types/app'
|
import type { Resolution, TransferMethod, TtsAutoPlay } from '@/types/app'
|
||||||
import type { FileUploadConfigResponse } from '@/models/common'
|
import type { FileUploadConfigResponse } from '@/models/common'
|
||||||
|
|
||||||
export type EnabledOrDisabled = {
|
export interface EnabledOrDisabled {
|
||||||
enabled?: boolean
|
enabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ export type FileUpload = {
|
|||||||
fileUploadConfig?: FileUploadConfigResponse
|
fileUploadConfig?: FileUploadConfigResponse
|
||||||
} & EnabledOrDisabled
|
} & EnabledOrDisabled
|
||||||
|
|
||||||
export type AnnotationReplyConfig = {
|
export interface AnnotationReplyConfig {
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
id?: string
|
id?: string
|
||||||
score_threshold?: number
|
score_threshold?: number
|
||||||
@ -64,7 +64,7 @@ export enum FeatureEnum {
|
|||||||
annotationReply = 'annotationReply',
|
annotationReply = 'annotationReply',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Features = {
|
export interface Features {
|
||||||
[FeatureEnum.moreLikeThis]?: MoreLikeThis
|
[FeatureEnum.moreLikeThis]?: MoreLikeThis
|
||||||
[FeatureEnum.opening]?: OpeningStatement
|
[FeatureEnum.opening]?: OpeningStatement
|
||||||
[FeatureEnum.suggested]?: SuggestedQuestionsAfterAnswer
|
[FeatureEnum.suggested]?: SuggestedQuestionsAfterAnswer
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user