Browse Source

Feat: Add VariablePickerMenuPlugin to select variables in the prompt text box by menu #4764 (#4765)

### What problem does this PR solve?

Feat: Add VariablePickerMenuPlugin to select variables in the prompt
text box by menu #4764

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
tags/v0.17.0
balibabu 8 months ago
parent
commit
bfcc2abe47
No account linked to committer's email address

+ 4
- 1
web/.umirc.ts View File

import path from 'path'; import path from 'path';
import TerserPlugin from 'terser-webpack-plugin';
import { defineConfig } from 'umi'; import { defineConfig } from 'umi';
import { appName } from './src/conf.json'; import { appName } from './src/conf.json';
import routes from './src/routes'; import routes from './src/routes';
'@react-dev-inspector/umi4-plugin', '@react-dev-inspector/umi4-plugin',
'@umijs/plugins/dist/tailwindcss', '@umijs/plugins/dist/tailwindcss',
], ],
jsMinifier: 'terser',
jsMinifier: 'none', // Fixed the issue that the page displayed an error after packaging lexical with terser
lessLoader: { lessLoader: {
modifyVars: { modifyVars: {
hack: `true; @import "~@/less/index.less";`, hack: `true; @import "~@/less/index.less";`,
chainWebpack(memo, args) { chainWebpack(memo, args) {
memo.module.rule('markdown').test(/\.md$/).type('asset/source'); memo.module.rule('markdown').test(/\.md$/).type('asset/source');


memo.optimization.minimizer('terser').use(TerserPlugin); // Fixed the issue that the page displayed an error after packaging lexical with terser

return memo; return memo;
}, },
tailwindcss: {}, tailwindcss: {},

+ 434
- 19
web/package-lock.json View File

"@antv/g6": "^5.0.10", "@antv/g6": "^5.0.10",
"@hookform/resolvers": "^3.9.1", "@hookform/resolvers": "^3.9.1",
"@js-preview/excel": "^1.7.8", "@js-preview/excel": "^1.7.8",
"@lexical/react": "^0.23.1",
"@monaco-editor/react": "^4.6.0", "@monaco-editor/react": "^4.6.0",
"@radix-ui/react-alert-dialog": "^1.1.4", "@radix-ui/react-alert-dialog": "^1.1.4",
"@radix-ui/react-aspect-ratio": "^1.1.0", "@radix-ui/react-aspect-ratio": "^1.1.0",
"input-otp": "^1.4.1", "input-otp": "^1.4.1",
"js-base64": "^3.7.5", "js-base64": "^3.7.5",
"jsencrypt": "^3.3.2", "jsencrypt": "^3.3.2",
"lexical": "^0.23.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lucide-react": "^0.454.0", "lucide-react": "^0.454.0",
"mammoth": "^1.7.2", "mammoth": "^1.7.2",
"react-dev-inspector": "^2.0.1", "react-dev-inspector": "^2.0.1",
"remark-loader": "^6.0.0", "remark-loader": "^6.0.0",
"tailwindcss": "^3", "tailwindcss": "^3",
"terser-webpack-plugin": "^5.3.11",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.0.3", "typescript": "^5.0.3",
"umi-plugin-icons": "^0.1.1" "umi-plugin-icons": "^0.1.1"
"resolved": "https://registry.npmmirror.com/@js-preview/excel/-/excel-1.7.8.tgz", "resolved": "https://registry.npmmirror.com/@js-preview/excel/-/excel-1.7.8.tgz",
"integrity": "sha512-pLJTDIhbzqaiH3kUPnbeWLsBFeCAHjnBwloMvoREdW4YUYTcsHDQ5h41QTyRJWSYRJBCcsy6Kt7KeDHOHDbVEw==" "integrity": "sha512-pLJTDIhbzqaiH3kUPnbeWLsBFeCAHjnBwloMvoREdW4YUYTcsHDQ5h41QTyRJWSYRJBCcsy6Kt7KeDHOHDbVEw=="
}, },
"node_modules/@lexical/clipboard": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/clipboard/-/clipboard-0.23.1.tgz",
"integrity": "sha512-MT8IXl1rhTe8VcwnkhgFtWra6sRYNsl/I7nE9aw6QxwvPReKmRDmyBmEIeXwnKSGHRe19OJhu4/A9ciKPyVdMA==",
"dependencies": {
"@lexical/html": "0.23.1",
"@lexical/list": "0.23.1",
"@lexical/selection": "0.23.1",
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/code": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/code/-/code-0.23.1.tgz",
"integrity": "sha512-TOxaFAwoewrX3rHp4Po+u1LJT8oteP/6Kn2z6j9DaynBW62gIqTuSAFcMPysVx/Puq5hhJHPRD/be9RWDteDZw==",
"dependencies": {
"@lexical/utils": "0.23.1",
"lexical": "0.23.1",
"prismjs": "^1.27.0"
}
},
"node_modules/@lexical/devtools-core": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/devtools-core/-/devtools-core-0.23.1.tgz",
"integrity": "sha512-QsgcrECy11ZHhWAfyNW/ougXFF1o0EuQnhFybgTdqQmw0rJ2ZgPLpPjD5lws3CE8mP8g5knBV4/cyxvv42fzzg==",
"dependencies": {
"@lexical/html": "0.23.1",
"@lexical/link": "0.23.1",
"@lexical/mark": "0.23.1",
"@lexical/table": "0.23.1",
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
},
"peerDependencies": {
"react": ">=17.x",
"react-dom": ">=17.x"
}
},
"node_modules/@lexical/dragon": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/dragon/-/dragon-0.23.1.tgz",
"integrity": "sha512-ZoY9VJDrTpO69sinRhIs3RlPAWviy4mwnC7lqtM77/pVK0Kaknv7z2iDqv+414PKQCgUhyoXp7PfYXu/3yb6LQ==",
"dependencies": {
"lexical": "0.23.1"
}
},
"node_modules/@lexical/hashtag": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/hashtag/-/hashtag-0.23.1.tgz",
"integrity": "sha512-EkRCHV/IQwKlggy3VQDF9b4Krc9DKNZEjXe84CkEVrRpQSOwXi0qORzuaAipARyN632WKLSXOZJmNzkUNocJ6A==",
"dependencies": {
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/history": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/history/-/history-0.23.1.tgz",
"integrity": "sha512-5Vro4bIePw37MwffpvPm56WlwPdlY/u+fVkvXsxdhK9bqiFesmLZhBirokDPvJEMP35V59kzmN5mmWXSYfuRpg==",
"dependencies": {
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/html": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/html/-/html-0.23.1.tgz",
"integrity": "sha512-kNkDUaDe/Awypaw8JZn65BzT1gwNj2bNkaGFcmIkXUrTtiqlvgYvKvJeOKLkoAb/i2xq990ZAbHOsJrJm1jMbw==",
"dependencies": {
"@lexical/selection": "0.23.1",
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/link": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/link/-/link-0.23.1.tgz",
"integrity": "sha512-HRaOp7prtcbHjbgq8AjJ4O02jYb8pTeS8RrGcgIRhCOq3/EcsSb1dXMwuraqmh9oxbuFyEu/JE31EFksiOW6qA==",
"dependencies": {
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/list": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/list/-/list-0.23.1.tgz",
"integrity": "sha512-TI3WyWk3avv9uaJwaq8V+m9zxLRgnzXDYNS0rREafnW09rDpaFkpVmDuX+PZVR3NqPlwVt+slWVSBuyfguAFbA==",
"dependencies": {
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/mark": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/mark/-/mark-0.23.1.tgz",
"integrity": "sha512-E7cMOBVMrNGMw0LsyWKNFQZ5Io3bUIHCC3aCUdH24z1XWnuTmDFKMqNrphywPniO7pzSgVyGpkQBZIAIN76+YA==",
"dependencies": {
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/markdown": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/markdown/-/markdown-0.23.1.tgz",
"integrity": "sha512-TQx8oXenaiVYffBPxD85m4CydbDAuYOonATiABAFG6CHkA6vi898M1TCTgVDS6/iISjtjQpqHo0SW7YjLt14jw==",
"dependencies": {
"@lexical/code": "0.23.1",
"@lexical/link": "0.23.1",
"@lexical/list": "0.23.1",
"@lexical/rich-text": "0.23.1",
"@lexical/text": "0.23.1",
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/offset": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/offset/-/offset-0.23.1.tgz",
"integrity": "sha512-ylw5egME/lldacVXDoRsdGDXPuk9lGmYgcqx/aITGrSymav+RDjQoAapHbz1HQqGmm/m18+VLaWTdjtkbrIN6g==",
"dependencies": {
"lexical": "0.23.1"
}
},
"node_modules/@lexical/overflow": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/overflow/-/overflow-0.23.1.tgz",
"integrity": "sha512-WubTqozpxOeyTm/tKIHXinsjuRcgPESacOvu93dS+sC7q3n+xeBIu5FL7lM6bbsk3zNtNJQ9sG0svZngmWRjCw==",
"dependencies": {
"lexical": "0.23.1"
}
},
"node_modules/@lexical/plain-text": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/plain-text/-/plain-text-0.23.1.tgz",
"integrity": "sha512-tM4DJw+HyT9XV4BKGVECDnejcC//jsFggjFmJgwIMTCxJPiGXEEZLZTXmGqf8QdFZ6cH1I5bhreZPQUWu6dRvg==",
"dependencies": {
"@lexical/clipboard": "0.23.1",
"@lexical/selection": "0.23.1",
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/react": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/react/-/react-0.23.1.tgz",
"integrity": "sha512-g5CQMOiK+Djqp75UaSFUceHZEUQVIXBzWBuVR69pCiptCgNqN3CNAoIxy0hTTaVrLq6S0SCjUOduBDtioN0bLA==",
"dependencies": {
"@lexical/clipboard": "0.23.1",
"@lexical/code": "0.23.1",
"@lexical/devtools-core": "0.23.1",
"@lexical/dragon": "0.23.1",
"@lexical/hashtag": "0.23.1",
"@lexical/history": "0.23.1",
"@lexical/link": "0.23.1",
"@lexical/list": "0.23.1",
"@lexical/mark": "0.23.1",
"@lexical/markdown": "0.23.1",
"@lexical/overflow": "0.23.1",
"@lexical/plain-text": "0.23.1",
"@lexical/rich-text": "0.23.1",
"@lexical/selection": "0.23.1",
"@lexical/table": "0.23.1",
"@lexical/text": "0.23.1",
"@lexical/utils": "0.23.1",
"@lexical/yjs": "0.23.1",
"lexical": "0.23.1",
"react-error-boundary": "^3.1.4"
},
"peerDependencies": {
"react": ">=17.x",
"react-dom": ">=17.x"
}
},
"node_modules/@lexical/react/node_modules/react-error-boundary": {
"version": "3.1.4",
"resolved": "https://registry.npmmirror.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz",
"integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==",
"dependencies": {
"@babel/runtime": "^7.12.5"
},
"engines": {
"node": ">=10",
"npm": ">=6"
},
"peerDependencies": {
"react": ">=16.13.1"
}
},
"node_modules/@lexical/rich-text": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/rich-text/-/rich-text-0.23.1.tgz",
"integrity": "sha512-Y77HGxdF5aemjw/H44BXETD5KNeaNdwMRu9P7IrlK7cC1dvvimzL2D6ezbub5i7F1Ef5T0quOXjwK056vrqaKQ==",
"dependencies": {
"@lexical/clipboard": "0.23.1",
"@lexical/selection": "0.23.1",
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/selection": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/selection/-/selection-0.23.1.tgz",
"integrity": "sha512-xoehAURMZJZYf046GHUXiv8FSv5zTobhwDD2dML4fmNHPp9NxugkWHlNUinTK/b+jGgjSYVsqpEKPBmue4ZHdQ==",
"dependencies": {
"lexical": "0.23.1"
}
},
"node_modules/@lexical/table": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/table/-/table-0.23.1.tgz",
"integrity": "sha512-Qs+iuwSVkV4OGTt+JdL9hvyl/QO3X9waH70L5Fxu9JmQk/jLl02tIGXbE38ocJkByfpyk4PrphoXt6l7CugJZA==",
"dependencies": {
"@lexical/clipboard": "0.23.1",
"@lexical/utils": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/text": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/text/-/text-0.23.1.tgz",
"integrity": "sha512-aOuuAhmc+l2iSK99uP0x/Zg9LSQswQdNG3IxzGa0rTx844mWUHuEbAUaOqqlgDA1/zZ0WjObyhPfZJL775y63g==",
"dependencies": {
"lexical": "0.23.1"
}
},
"node_modules/@lexical/utils": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/utils/-/utils-0.23.1.tgz",
"integrity": "sha512-yXEkF6fj32+mJblCoP0ZT/vA0S05FA0nRUkVrvGX6sbZ9y+cIzuIbBoHi4z1ytutcWHQrwCK4TsN9hPYBIlb2w==",
"dependencies": {
"@lexical/list": "0.23.1",
"@lexical/selection": "0.23.1",
"@lexical/table": "0.23.1",
"lexical": "0.23.1"
}
},
"node_modules/@lexical/yjs": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/@lexical/yjs/-/yjs-0.23.1.tgz",
"integrity": "sha512-ygodSxmC65srNicMIhqBRIXI2LHhmnHcR1EO9fLO7flZWGCR1HIoeGmwhHo9FLgJoc5LHanV+dE0z1onFo1qqQ==",
"dependencies": {
"@lexical/offset": "0.23.1",
"@lexical/selection": "0.23.1",
"lexical": "0.23.1"
},
"peerDependencies": {
"yjs": ">=13.5.22"
}
},
"node_modules/@ljharb/resumer": { "node_modules/@ljharb/resumer": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmmirror.com/@ljharb/resumer/-/resumer-0.0.1.tgz", "resolved": "https://registry.npmmirror.com/@ljharb/resumer/-/resumer-0.0.1.tgz",
"uri-js": "^4.2.2" "uri-js": "^4.2.2"
} }
}, },
"node_modules/ajv-formats": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"license": "MIT",
"dependencies": {
"ajv": "^8.0.0"
},
"peerDependencies": {
"ajv": "^8.0.0"
},
"peerDependenciesMeta": {
"ajv": {
"optional": true
}
}
},
"node_modules/ajv-formats/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/ajv-keywords": { "node_modules/ajv-keywords": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/fast-uri": {
"version": "3.0.6",
"resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.0.6.tgz",
"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause"
},
"node_modules/fastest-levenshtein": { "node_modules/fastest-levenshtein": {
"version": "1.0.16", "version": "1.0.16",
"resolved": "https://registry.npmmirror.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "resolved": "https://registry.npmmirror.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
"unfetch": "^5.0.0" "unfetch": "^5.0.0"
} }
}, },
"node_modules/isomorphic.js": {
"version": "0.2.5",
"resolved": "https://registry.npmmirror.com/isomorphic.js/-/isomorphic.js-0.2.5.tgz",
"integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==",
"peer": true,
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
}
},
"node_modules/istanbul-lib-coverage": { "node_modules/istanbul-lib-coverage": {
"version": "3.2.2", "version": "3.2.2",
"resolved": "https://registry.npmmirror.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "resolved": "https://registry.npmmirror.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/lexical": {
"version": "0.23.1",
"resolved": "https://registry.npmmirror.com/lexical/-/lexical-0.23.1.tgz",
"integrity": "sha512-iuS72HcAYUemsCRQCm4XZzkGhZb8a9KagW+ee2TFfkkf9f3ZpUYSrobMpjYVZRkgMOx7Zk5VCPMxm1nouJTfnQ=="
},
"node_modules/lib0": {
"version": "0.2.99",
"resolved": "https://registry.npmmirror.com/lib0/-/lib0-0.2.99.tgz",
"integrity": "sha512-vwztYuUf1uf/1zQxfzRfO5yzfNKhTtgOByCruuiQQxWQXnPb8Itaube5ylofcV0oM0aKal9Mv+S1s1Ky0UYP1w==",
"peer": true,
"dependencies": {
"isomorphic.js": "^0.2.4"
},
"bin": {
"0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js",
"0gentesthtml": "bin/gentesthtml.js",
"0serve": "bin/0serve.js"
},
"engines": {
"node": ">=16"
},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
}
},
"node_modules/lie": { "node_modules/lie": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz", "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz",
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}, },
"node_modules/serialize-javascript": { "node_modules/serialize-javascript": {
"version": "6.0.1",
"resolved": "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
"integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
"peer": true,
"version": "6.0.2",
"resolved": "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"randombytes": "^2.1.0" "randombytes": "^2.1.0"
} }
} }
}, },
"node_modules/terser": { "node_modules/terser": {
"version": "5.26.0",
"resolved": "https://registry.npmmirror.com/terser/-/terser-5.26.0.tgz",
"integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==",
"version": "5.38.1",
"resolved": "https://registry.npmmirror.com/terser/-/terser-5.38.1.tgz",
"integrity": "sha512-GWANVlPM/ZfYzuPHjq0nxT+EbOEDDN3Jwhwdg1D8TU8oSkktp8w64Uq4auuGLxFSoNTRDncTq2hQHX1Ld9KHkA==",
"license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.3", "@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2", "acorn": "^8.8.2",
} }
}, },
"node_modules/terser-webpack-plugin": { "node_modules/terser-webpack-plugin": {
"version": "5.3.10",
"resolved": "https://registry.npmmirror.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
"integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
"peer": true,
"version": "5.3.11",
"resolved": "https://registry.npmmirror.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz",
"integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@jridgewell/trace-mapping": "^0.3.20",
"@jridgewell/trace-mapping": "^0.3.25",
"jest-worker": "^27.4.5", "jest-worker": "^27.4.5",
"schema-utils": "^3.1.1",
"serialize-javascript": "^6.0.1",
"terser": "^5.26.0"
"schema-utils": "^4.3.0",
"serialize-javascript": "^6.0.2",
"terser": "^5.31.1"
}, },
"engines": { "engines": {
"node": ">= 10.13.0" "node": ">= 10.13.0"
}, },
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": { "peerDependencies": {
"webpack": "^5.1.0" "webpack": "^5.1.0"
}, },
} }
} }
}, },
"node_modules/terser-webpack-plugin/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/terser-webpack-plugin/node_modules/ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3"
},
"peerDependencies": {
"ajv": "^8.8.2"
}
},
"node_modules/terser-webpack-plugin/node_modules/has-flag": { "node_modules/terser-webpack-plugin/node_modules/has-flag": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"peer": true,
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
"version": "27.5.1", "version": "27.5.1",
"resolved": "https://registry.npmmirror.com/jest-worker/-/jest-worker-27.5.1.tgz", "resolved": "https://registry.npmmirror.com/jest-worker/-/jest-worker-27.5.1.tgz",
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
"peer": true,
"dependencies": { "dependencies": {
"@types/node": "*", "@types/node": "*",
"merge-stream": "^2.0.0", "merge-stream": "^2.0.0",
"node": ">= 10.13.0" "node": ">= 10.13.0"
} }
}, },
"node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/terser-webpack-plugin/node_modules/schema-utils": {
"version": "4.3.0",
"resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.3.0.tgz",
"integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.1.0"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/terser-webpack-plugin/node_modules/supports-color": { "node_modules/terser-webpack-plugin/node_modules/supports-color": {
"version": "8.1.1", "version": "8.1.1",
"resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"peer": true,
"dependencies": { "dependencies": {
"has-flag": "^4.0.0" "has-flag": "^4.0.0"
}, },
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/yjs": {
"version": "13.6.23",
"resolved": "https://registry.npmmirror.com/yjs/-/yjs-13.6.23.tgz",
"integrity": "sha512-ExtnT5WIOVpkL56bhLeisG/N5c4fmzKn4k0ROVfJa5TY2QHbH7F0Wu2T5ZhR7ErsFWQEFafyrnSI8TPKVF9Few==",
"peer": true,
"dependencies": {
"lib0": "^0.2.99"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
}
},
"node_modules/yn": { "node_modules/yn": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz", "resolved": "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz",

+ 3
- 0
web/package.json View File

"@antv/g6": "^5.0.10", "@antv/g6": "^5.0.10",
"@hookform/resolvers": "^3.9.1", "@hookform/resolvers": "^3.9.1",
"@js-preview/excel": "^1.7.8", "@js-preview/excel": "^1.7.8",
"@lexical/react": "^0.23.1",
"@monaco-editor/react": "^4.6.0", "@monaco-editor/react": "^4.6.0",
"@radix-ui/react-alert-dialog": "^1.1.4", "@radix-ui/react-alert-dialog": "^1.1.4",
"@radix-ui/react-aspect-ratio": "^1.1.0", "@radix-ui/react-aspect-ratio": "^1.1.0",
"input-otp": "^1.4.1", "input-otp": "^1.4.1",
"js-base64": "^3.7.5", "js-base64": "^3.7.5",
"jsencrypt": "^3.3.2", "jsencrypt": "^3.3.2",
"lexical": "^0.23.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lucide-react": "^0.454.0", "lucide-react": "^0.454.0",
"mammoth": "^1.7.2", "mammoth": "^1.7.2",
"react-dev-inspector": "^2.0.1", "react-dev-inspector": "^2.0.1",
"remark-loader": "^6.0.0", "remark-loader": "^6.0.0",
"tailwindcss": "^3", "tailwindcss": "^3",
"terser-webpack-plugin": "^5.3.11",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.0.3", "typescript": "^5.0.3",
"umi-plugin-icons": "^0.1.1" "umi-plugin-icons": "^0.1.1"

+ 76
- 0
web/src/components/prompt-editor/index.css View File

.typeahead-popover {
background: #fff;
box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.3);
border-radius: 8px;
position: fixed;
z-index: 1000;
}

.typeahead-popover ul {
list-style: none;
margin: 0;
max-height: 200px;
overflow-y: scroll;
}

.typeahead-popover ul::-webkit-scrollbar {
display: none;
}

.typeahead-popover ul {
-ms-overflow-style: none;
scrollbar-width: none;
}

.typeahead-popover ul li {
margin: 0;
min-width: 180px;
font-size: 14px;
outline: none;
cursor: pointer;
border-radius: 8px;
}

.typeahead-popover ul li.selected {
background: #eee;
}

.typeahead-popover li {
margin: 0 8px 0 8px;
color: #050505;
cursor: pointer;
line-height: 16px;
font-size: 15px;
display: flex;
align-content: center;
flex-direction: row;
flex-shrink: 0;
background-color: #fff;
border: 0;
}

.typeahead-popover li.active {
display: flex;
width: 20px;
height: 20px;
background-size: contain;
}

.typeahead-popover li .text {
display: flex;
line-height: 20px;
flex-grow: 1;
min-width: 150px;
}

.typeahead-popover li .icon {
display: flex;
width: 20px;
height: 20px;
user-select: none;
margin-right: 8px;
line-height: 16px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}

+ 83
- 0
web/src/components/prompt-editor/index.tsx View File

import { CodeHighlightNode, CodeNode } from '@lexical/code';
import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin';
import {
InitialConfigType,
LexicalComposer,
} from '@lexical/react/LexicalComposer';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
import { HeadingNode, QuoteNode } from '@lexical/rich-text';
import {
$getRoot,
$nodesOfType,
EditorState,
Klass,
LexicalNode,
} from 'lexical';

import { useTranslation } from 'react-i18next';
import theme from './theme';
import { VariableNode } from './variable-node';
import VariablePickerMenuPlugin from './variable-picker-plugin';

// Catch any errors that occur during Lexical updates and log them
// or throw them as needed. If you don't throw them, Lexical will
// try to recover gracefully without losing user data.
function onError(error: Error) {
console.error(error);
}

const Nodes: Array<Klass<LexicalNode>> = [
HeadingNode,
QuoteNode,
CodeHighlightNode,
CodeNode,
VariableNode,
];

type IProps = {
value?: string;
onChange?: (value?: string) => void;
};

export function PromptEditor({ value, onChange }: IProps) {
const { t } = useTranslation();
const initialConfig: InitialConfigType = {
namespace: 'PromptEditor',
theme,
onError,
nodes: Nodes,
};

function onValueChange(editorState: EditorState) {
editorState?.read(() => {
const listNodes = $nodesOfType(VariableNode); // to be removed
// const allNodes = $dfs();
console.log('🚀 ~ onChange ~ allNodes:', listNodes);

const text = $getRoot().getTextContent();
onChange?.(text);
});
}

return (
<LexicalComposer initialConfig={initialConfig}>
<RichTextPlugin
contentEditable={
<ContentEditable className="min-h-40 relative px-2 py-1 border" />
}
placeholder={
<div className="absolute top-2 left-2">{t('common.pleaseInput')}</div>
}
ErrorBoundary={LexicalErrorBoundary}
/>
<HistoryPlugin />
<AutoFocusPlugin />
<VariablePickerMenuPlugin value={value}></VariablePickerMenuPlugin>
<OnChangePlugin onChange={onValueChange}></OnChangePlugin>
</LexicalComposer>
);
}

+ 43
- 0
web/src/components/prompt-editor/theme.ts View File

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

export default {
code: 'editor-code',
heading: {
h1: 'editor-heading-h1',
h2: 'editor-heading-h2',
h3: 'editor-heading-h3',
h4: 'editor-heading-h4',
h5: 'editor-heading-h5',
},
image: 'editor-image',
link: 'editor-link',
list: {
listitem: 'editor-listitem',
nested: {
listitem: 'editor-nested-listitem',
},
ol: 'editor-list-ol',
ul: 'editor-list-ul',
},
ltr: 'ltr',
paragraph: 'editor-paragraph',
placeholder: 'editor-placeholder',
quote: 'editor-quote',
rtl: 'rtl',
text: {
bold: 'editor-text-bold',
code: 'editor-text-code',
hashtag: 'editor-text-hashtag',
italic: 'editor-text-italic',
overflowed: 'editor-text-overflowed',
strikethrough: 'editor-text-strikethrough',
underline: 'editor-text-underline',
underlineStrikethrough: 'editor-text-underlineStrikethrough',
},
};

+ 70
- 0
web/src/components/prompt-editor/variable-node.tsx View File

import i18n from '@/locales/config';
import { BeginId } from '@/pages/flow/constant';
import { DecoratorNode, LexicalNode, NodeKey } from 'lexical';
import { ReactNode } from 'react';
const prefix = BeginId + '@';

export class VariableNode extends DecoratorNode<ReactNode> {
__value: string;
__label: string;

static getType(): string {
return 'variable';
}

static clone(node: VariableNode): VariableNode {
return new VariableNode(node.__value, node.__label, node.__key);
}

constructor(value: string, label: string, key?: NodeKey) {
super(key);
this.__value = value;
this.__label = label;
}

createDOM(): HTMLElement {
const dom = document.createElement('span');
dom.className = 'mr-1';

return dom;
}

updateDOM(): false {
return false;
}

decorate(): ReactNode {
let content: ReactNode = (
<span className="text-blue-600">{this.__label}</span>
);
if (this.__value.startsWith(prefix)) {
content = (
<div>
<span>{i18n.t(`flow.begin`)}</span> / {content}
</div>
);
}
return (
<div className="bg-gray-200 dark:bg-gray-400 text-primary inline-flex items-center rounded-md px-2 py-0">
{content}
</div>
);
}

getTextContent(): string {
return `{${this.__value}}`;
}
}

export function $createVariableNode(
value: string,
label: string,
): VariableNode {
return new VariableNode(value, label);
}

export function $isVariableNode(
node: LexicalNode | null | undefined,
): node is VariableNode {
return node instanceof VariableNode;
}

+ 251
- 0
web/src/components/prompt-editor/variable-picker-plugin.tsx View File

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import {
LexicalTypeaheadMenuPlugin,
MenuOption,
useBasicTypeaheadTriggerMatch,
} from '@lexical/react/LexicalTypeaheadMenuPlugin';
import {
$createParagraphNode,
$createTextNode,
$getRoot,
$getSelection,
$isRangeSelection,
TextNode,
} from 'lexical';
import {
ReactElement,
useCallback,
useContext,
useEffect,
useRef,
} from 'react';
import * as ReactDOM from 'react-dom';

import { FlowFormContext } from '@/pages/flow/context';
import { useBuildComponentIdSelectOptions } from '@/pages/flow/hooks/use-get-begin-query';
import { $createVariableNode } from './variable-node';

import './index.css';
class VariableInnerOption extends MenuOption {
label: string;
value: string;

constructor(label: string, value: string) {
super(value);
this.label = label;
this.value = value;
}
}

class VariableOption extends MenuOption {
label: ReactElement | string;
title: string;
options: VariableInnerOption[];

constructor(
label: ReactElement | string,
title: string,
options: VariableInnerOption[],
) {
super(title);
this.label = label;
this.title = title;
this.options = options;
}
}

function VariablePickerMenuItem({
index,
option,
selectOptionAndCleanUp,
}: {
index: number;
option: VariableOption;
selectOptionAndCleanUp: (
option: VariableOption | VariableInnerOption,
) => void;
}) {
return (
<li
key={option.key}
tabIndex={-1}
ref={option.setRefElement}
role="option"
id={'typeahead-item-' + index}
>
<div>
<span className="text text-slate-500">{option.title}</span>
<ul className="pl-2 py-1">
{option.options.map((x) => (
<li
key={x.value}
onClick={() => selectOptionAndCleanUp(x)}
className="hover:bg-slate-300 p-1"
>
{x.label}
</li>
))}
</ul>
</div>
</li>
);
}

export default function VariablePickerMenuPlugin({
value,
}: {
value?: string;
}): JSX.Element {
const [editor] = useLexicalComposerContext();
const isFirstRender = useRef(true);

const node = useContext(FlowFormContext);

const checkForTriggerMatch = useBasicTypeaheadTriggerMatch('/', {
minLength: 0,
});

const setQueryString = useCallback(() => {}, []);

const options = useBuildComponentIdSelectOptions(node?.id, node?.parentId);

const nextOptions: VariableOption[] = options.map(
(x) =>
new VariableOption(
x.label,
x.title,
x.options.map((y) => new VariableInnerOption(y.label, y.value)),
),
);

const findLabelByValue = useCallback(
(value: string) => {
const children = options.reduce<Array<{ label: string; value: string }>>(
(pre, cur) => {
return pre.concat(cur.options);
},
[],
);

return children.find((x) => x.value === value)?.label;
},
[options],
);

const onSelectOption = useCallback(
(
selectedOption: VariableOption | VariableInnerOption,
nodeToRemove: TextNode | null,
closeMenu: () => void,
) => {
editor.update(() => {
const selection = $getSelection();

if (!$isRangeSelection(selection) || selectedOption === null) {
return;
}

if (nodeToRemove) {
nodeToRemove.remove();
}

selection.insertNodes([
$createVariableNode(
(selectedOption as VariableInnerOption).value,
selectedOption.label as string,
),
]);

closeMenu();
});
},
[editor],
);

const parseTextToVariableNodes = useCallback(
(text: string) => {
const paragraph = $createParagraphNode();

// Regular expression to match content within {}
const regex = /{([^}]*)}/g;
let match;
let lastIndex = 0;

while ((match = regex.exec(text)) !== null) {
const { 1: content, index, 0: template } = match;

// Add the previous text part (if any)
if (index > lastIndex) {
const textNode = $createTextNode(text.slice(lastIndex, index));

paragraph.append(textNode);
}

// Add variable node or text node
const label = findLabelByValue(content);
if (label) {
paragraph.append($createVariableNode(content, label));
} else {
paragraph.append($createTextNode(template));
}

// Update index
lastIndex = regex.lastIndex;
}

// Add the last part of text (if any)
if (lastIndex < text.length) {
const textNode = $createTextNode(text.slice(lastIndex));
paragraph.append(textNode);
}

$getRoot().clear().append(paragraph);
},
[findLabelByValue],
);

useEffect(() => {
if (editor && value && isFirstRender.current) {
isFirstRender.current = false;
editor.update(() => {
parseTextToVariableNodes(value);
});
}
}, [parseTextToVariableNodes, editor, value]);

return (
<LexicalTypeaheadMenuPlugin<VariableOption | VariableInnerOption>
onQueryChange={setQueryString}
onSelectOption={onSelectOption}
triggerFn={checkForTriggerMatch}
options={nextOptions}
menuRenderFn={(anchorElementRef, { selectOptionAndCleanUp }) =>
anchorElementRef.current && options.length
? ReactDOM.createPortal(
<div className="typeahead-popover w-[200px] p-2">
<ul>
{nextOptions.map((option, i: number) => (
<VariablePickerMenuItem
index={i}
key={option.key}
option={option}
selectOptionAndCleanUp={selectOptionAndCleanUp}
/>
))}
</ul>
</div>,
anchorElementRef.current,
)
: null
}
/>
);
}

+ 19
- 19
web/src/pages/dataset/testing/index.tsx View File

content: `Lorem ipsum odor amet, consectetuer adipiscing elit. Ullamcorper vulputate id laoreet malesuada commodo molestie. Lectus convallis class euismod; consequat in curabitur. Ablandit praesent inceptos nibh placerat lectus fringilla finibus. Hac vivamus id scelerisque et gravida nec ligula et non. Consectetur eu himenaeos eget felis quis habitant tellus. Tellus commodo inceptos litora habitant per himenaeos faucibus pretium. Gravida velit pretium amet purus rhoncus taciti. `, content: `Lorem ipsum odor amet, consectetuer adipiscing elit. Ullamcorper vulputate id laoreet malesuada commodo molestie. Lectus convallis class euismod; consequat in curabitur. Ablandit praesent inceptos nibh placerat lectus fringilla finibus. Hac vivamus id scelerisque et gravida nec ligula et non. Consectetur eu himenaeos eget felis quis habitant tellus. Tellus commodo inceptos litora habitant per himenaeos faucibus pretium. Gravida velit pretium amet purus rhoncus taciti. `,
}); });


const SimilarityList = [
{ label: '混合相似度', value: 45.88 },
{ label: '关键词似度', value: 45.88 },
{ label: '向量相似度', value: 45.88 },
];

export default function RetrievalTesting() { export default function RetrievalTesting() {
return ( return (
<section className="flex divide-x h-full"> <section className="flex divide-x h-full">
<TestingForm></TestingForm> <TestingForm></TestingForm>
</div> </div>
<div className="p-4 flex-1 "> <div className="p-4 flex-1 ">
<h2 className="text-3xl font-bold mb-8 px-[10%]">
<h2 className="text-4xl font-bold mb-8 px-[10%]">
15 Results from 3 files 15 Results from 3 files
</h2> </h2>
<section className="flex flex-col gap-4 overflow-auto h-[83vh] px-[10%]"> <section className="flex flex-col gap-4 overflow-auto h-[83vh] px-[10%]">
<CardHeader> <CardHeader>
<CardTitle> <CardTitle>
<div className="flex gap-2 flex-wrap"> <div className="flex gap-2 flex-wrap">
<Badge
variant="outline"
className="bg-colors-background-inverse-strong p-2 rounded-xl text-base"
>
混合相似度 45.88
</Badge>
<Badge
variant="outline"
className="bg-colors-background-inverse-strong p-2 rounded-xl text-base"
>
关键词似度 45.88
</Badge>
<Badge
variant="outline"
className="bg-colors-background-inverse-strong p-2 rounded-xl text-base"
>
向量相似度 45.88
</Badge>
{SimilarityList.map((x, idx) => (
<Badge
key={idx}
variant="outline"
className="bg-colors-background-inverse-strong p-1.5 rounded-xl text-colors-text-inverse-weak text-base"
>
{x.label}
<span className="text-colors-text-inverse-strong ml-1 text-lg leading-none">
{x.value}
</span>
</Badge>
))}
</div> </div>
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>

+ 0
- 20
web/src/pages/flow/canvas/node/generate-node.tsx View File

import { useTheme } from '@/components/theme-provider'; import { useTheme } from '@/components/theme-provider';
import { IGenerateNode } from '@/interfaces/database/flow'; import { IGenerateNode } from '@/interfaces/database/flow';
import { Handle, NodeProps, Position } from '@xyflow/react'; import { Handle, NodeProps, Position } from '@xyflow/react';
import { Flex } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { get } from 'lodash'; import { get } from 'lodash';
import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query';
import { IGenerateParameter } from '../../interface';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';
isConnectable = true, isConnectable = true,
selected, selected,
}: NodeProps<IGenerateNode>) { }: NodeProps<IGenerateNode>) {
const parameters: IGenerateParameter[] = get(data, 'form.parameters', []);
const getLabel = useGetComponentLabelByValue(id);
const { theme } = useTheme(); const { theme } = useTheme();
return ( return (
<section <section
<div className={styles.nodeText}> <div className={styles.nodeText}>
<LLMLabel value={get(data, 'form.llm_id')}></LLMLabel> <LLMLabel value={get(data, 'form.llm_id')}></LLMLabel>
</div> </div>
<Flex gap={8} vertical className={styles.generateParameters}>
{parameters.map((x) => (
<Flex
key={x.id}
align="center"
gap={6}
className={styles.conditionBlock}
>
<label htmlFor="">{x.key}</label>
<span className={styles.parameterValue}>
{getLabel(x.component_id)}
</span>
</Flex>
))}
</Flex>
</section> </section>
); );
} }

+ 0
- 1
web/src/pages/flow/constant.tsx View File

Operator.Message, Operator.Message,
Operator.Generate, Operator.Generate,
Operator.RewriteQuestion, Operator.RewriteQuestion,
Operator.Categorize,
Operator.Relevant, Operator.Relevant,
], ],
[Operator.KeywordExtract]: [ [Operator.KeywordExtract]: [

+ 6
- 0
web/src/pages/flow/context.ts View File

import { RAGFlowNodeType } from '@/interfaces/database/flow';
import { createContext } from 'react';

export const FlowFormContext = createContext<RAGFlowNodeType | undefined>(
undefined,
);

+ 27
- 9
web/src/pages/flow/flow-drawer/index.tsx View File

import { IModalProps } from '@/interfaces/common'; import { IModalProps } from '@/interfaces/common';
import { CloseOutlined } from '@ant-design/icons'; import { CloseOutlined } from '@ant-design/icons';
import { Drawer, Flex, Form, Input } from 'antd'; import { Drawer, Flex, Form, Input } from 'antd';
import { lowerFirst } from 'lodash';
import { get, isPlainObject, lowerFirst } from 'lodash';
import { Play } from 'lucide-react'; import { Play } from 'lucide-react';
import { useEffect, useRef } from 'react'; import { useEffect, useRef } from 'react';
import { BeginId, Operator, operatorMap } from '../constant'; import { BeginId, Operator, operatorMap } from '../constant';
import YahooFinanceForm from '../form/yahoo-finance-form'; import YahooFinanceForm from '../form/yahoo-finance-form';
import { useHandleFormValuesChange, useHandleNodeNameChange } from '../hooks'; import { useHandleFormValuesChange, useHandleNodeNameChange } from '../hooks';
import OperatorIcon from '../operator-icon'; import OperatorIcon from '../operator-icon';
import { getDrawerWidth, needsSingleStepDebugging } from '../utils';
import {
buildCategorizeListFromObject,
getDrawerWidth,
needsSingleStepDebugging,
} from '../utils';
import SingleDebugDrawer from './single-debug-drawer'; import SingleDebugDrawer from './single-debug-drawer';


import { RAGFlowNodeType } from '@/interfaces/database/flow'; import { RAGFlowNodeType } from '@/interfaces/database/flow';
import { FlowFormContext } from '../context';
import { RunTooltip } from '../flow-tooltip'; import { RunTooltip } from '../flow-tooltip';
import IterationForm from '../form/iteration-from'; import IterationForm from '../form/iteration-from';
import styles from './index.less'; import styles from './index.less';
if (node?.id !== previousId.current) { if (node?.id !== previousId.current) {
form.resetFields(); form.resetFields();
} }
form.setFieldsValue(node?.data?.form);

if (operatorName === Operator.Categorize) {
const items = buildCategorizeListFromObject(
get(node, 'data.form.category_description', {}),
);
const formData = node?.data?.form;
if (isPlainObject(formData)) {
form.setFieldsValue({ ...formData, items });
}
} else {
form.setFieldsValue(node?.data?.form);
}
previousId.current = node?.id; previousId.current = node?.id;
} }
}, [visible, form, node?.data?.form, node?.id]);
}, [visible, form, node?.data?.form, node?.id, node, operatorName]);


return ( return (
<Drawer <Drawer
> >
<section className={styles.formWrapper}> <section className={styles.formWrapper}>
{visible && ( {visible && (
<OperatorForm
onValuesChange={handleValuesChange}
form={form}
node={node}
></OperatorForm>
<FlowFormContext.Provider value={node}>
<OperatorForm
onValuesChange={handleValuesChange}
form={form}
node={node}
></OperatorForm>
</FlowFormContext.Provider>
)} )}
</section> </section>
{singleDebugDrawerVisible && ( {singleDebugDrawerVisible && (

+ 4
- 46
web/src/pages/flow/form/categorize-form/hooks.ts View File

import get from 'lodash/get';
import omit from 'lodash/omit';
import { useCallback, useEffect } from 'react';
import { import {
ICategorizeItem, ICategorizeItem,
ICategorizeItemResult, ICategorizeItemResult,
IOperatorForm,
} from '../../interface';
import useGraphStore from '../../store';

/**
* convert the following object into a list
*
* {
"product_related": {
"description": "The question is about product usage, appearance and how it works.",
"examples": "Why it always beaming?\nHow to install it onto the wall?\nIt leaks, what to do?",
"to": "generate:0"
}
}
*/
const buildCategorizeListFromObject = (
categorizeItem: ICategorizeItemResult,
) => {
// Categorize's to field has two data sources, with edges as the data source.
// Changes in the edge or to field need to be synchronized to the form field.
return Object.keys(categorizeItem)
.reduce<Array<ICategorizeItem>>((pre, cur) => {
// synchronize edge data to the to field

pre.push({ name: cur, ...categorizeItem[cur] });
return pre;
}, [])
.sort((a, b) => a.index - b.index);
};
} from '@/interfaces/database/flow';
import omit from 'lodash/omit';
import { useCallback } from 'react';
import { IOperatorForm } from '../../interface';


/** /**
* Convert the list in the following form into an object * Convert the list in the following form into an object


export const useHandleFormValuesChange = ({ export const useHandleFormValuesChange = ({
onValuesChange, onValuesChange,
form,
nodeId,
}: IOperatorForm) => { }: IOperatorForm) => {
const getNode = useGraphStore((state) => state.getNode);
const node = getNode(nodeId);

const handleValuesChange = useCallback( const handleValuesChange = useCallback(
(changedValues: any, values: any) => { (changedValues: any, values: any) => {
onValuesChange?.(changedValues, { onValuesChange?.(changedValues, {
[onValuesChange], [onValuesChange],
); );


useEffect(() => {
const items = buildCategorizeListFromObject(
get(node, 'data.form.category_description', {}),
);
form?.setFieldsValue({
items,
});
}, [form, node]);

return { handleValuesChange }; return { handleValuesChange };
}; };

+ 4
- 5
web/src/pages/flow/form/generate-form/index.tsx View File

import LLMSelect from '@/components/llm-select'; import LLMSelect from '@/components/llm-select';
import MessageHistoryWindowSizeItem from '@/components/message-history-window-size-item'; import MessageHistoryWindowSizeItem from '@/components/message-history-window-size-item';
import { PromptEditor } from '@/components/prompt-editor';
import { useTranslate } from '@/hooks/common-hooks'; import { useTranslate } from '@/hooks/common-hooks';
import { Form, Input, Switch } from 'antd';
import { Form, Switch } from 'antd';
import { IOperatorForm } from '../../interface'; import { IOperatorForm } from '../../interface';
import DynamicParameters from './dynamic-parameters';


const GenerateForm = ({ onValuesChange, form, node }: IOperatorForm) => {
const GenerateForm = ({ onValuesChange, form }: IOperatorForm) => {
const { t } = useTranslate('flow'); const { t } = useTranslate('flow');


return ( return (
}, },
]} ]}
> >
<Input.TextArea rows={8} />
<PromptEditor></PromptEditor>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name={['cite']} name={['cite']}
<MessageHistoryWindowSizeItem <MessageHistoryWindowSizeItem
initialValue={12} initialValue={12}
></MessageHistoryWindowSizeItem> ></MessageHistoryWindowSizeItem>
<DynamicParameters node={node}></DynamicParameters>
</Form> </Form>
); );
}; };

+ 4
- 6
web/src/pages/flow/form/template-form/index.tsx View File

import { Form, Input } from 'antd';
import { PromptEditor } from '@/components/prompt-editor';
import { Form } from 'antd';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { IOperatorForm } from '../../interface'; import { IOperatorForm } from '../../interface';
import DynamicParameters from '../generate-form/dynamic-parameters';


const TemplateForm = ({ onValuesChange, form, node }: IOperatorForm) => {
const TemplateForm = ({ onValuesChange, form }: IOperatorForm) => {
const { t } = useTranslation(); const { t } = useTranslation();


return ( return (
layout={'vertical'} layout={'vertical'}
> >
<Form.Item name={['content']} label={t('flow.content')}> <Form.Item name={['content']} label={t('flow.content')}>
<Input.TextArea rows={8} placeholder={t('flow.blank')} />
<PromptEditor></PromptEditor>
</Form.Item> </Form.Item>

<DynamicParameters node={node}></DynamicParameters>
</Form> </Form>
); );
}; };

+ 27
- 0
web/src/pages/flow/utils.ts View File

import { import {
DSLComponents, DSLComponents,
ICategorizeItem,
ICategorizeItemResult, ICategorizeItemResult,
RAGFlowNodeType, RAGFlowNodeType,
} from '@/interfaces/database/flow'; } from '@/interfaces/database/flow';
dragHandle: getNodeDragHandle(label), dragHandle: getNodeDragHandle(label),
}; };
}; };

/**
* convert the following object into a list
*
* {
"product_related": {
"description": "The question is about product usage, appearance and how it works.",
"examples": "Why it always beaming?\nHow to install it onto the wall?\nIt leaks, what to do?",
"to": "generate:0"
}
}
*/
export const buildCategorizeListFromObject = (
categorizeItem: ICategorizeItemResult,
) => {
// Categorize's to field has two data sources, with edges as the data source.
// Changes in the edge or to field need to be synchronized to the form field.
return Object.keys(categorizeItem)
.reduce<Array<ICategorizeItem>>((pre, cur) => {
// synchronize edge data to the to field

pre.push({ name: cur, ...categorizeItem[cur] });
return pre;
}, [])
.sort((a, b) => a.index - b.index);
};

+ 1
- 0
web/tailwind.config.js View File

'colors-text-functional-danger': 'var(--colors-text-functional-danger)', 'colors-text-functional-danger': 'var(--colors-text-functional-danger)',
'colors-text-inverse-strong': 'var(--colors-text-inverse-strong)', 'colors-text-inverse-strong': 'var(--colors-text-inverse-strong)',
'colors-text-persist-light': 'var(--colors-text-persist-light)', 'colors-text-persist-light': 'var(--colors-text-persist-light)',
'colors-text-inverse-weak': 'var(--colors-text-inverse-weak)',


primary: { primary: {
DEFAULT: 'hsl(var(--primary))', DEFAULT: 'hsl(var(--primary))',

+ 2
- 0
web/tailwind.css View File

--colors-text-functional-danger: rgba(255, 81, 81, 1); --colors-text-functional-danger: rgba(255, 81, 81, 1);
--colors-text-inverse-strong: rgba(255, 255, 255, 1); --colors-text-inverse-strong: rgba(255, 255, 255, 1);
--colors-text-persist-light: rgba(255, 255, 255, 1); --colors-text-persist-light: rgba(255, 255, 255, 1);
--colors-text-inverse-weak: rgba(184, 181, 203, 1);
} }


.dark { .dark {
--colors-text-functional-danger: rgba(255, 81, 81, 1); --colors-text-functional-danger: rgba(255, 81, 81, 1);
--colors-text-inverse-strong: rgba(17, 16, 23, 1); --colors-text-inverse-strong: rgba(17, 16, 23, 1);
--colors-text-persist-light: rgba(255, 255, 255, 1); --colors-text-persist-light: rgba(255, 255, 255, 1);
--colors-text-inverse-weak: rgba(84, 80, 106, 1);
} }
} }



Loading…
Cancel
Save