### What problem does this PR solve? feat: render stats charts feat: create api token feat: delete api token feat: add ChatApiKeyModal feat: add RagLineChart Issue link: #345 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.2.0
| "antd": "^5.12.7", | "antd": "^5.12.7", | ||||
| "axios": "^1.6.3", | "axios": "^1.6.3", | ||||
| "classnames": "^2.5.1", | "classnames": "^2.5.1", | ||||
| "dayjs": "^1.11.10", | |||||
| "i18next": "^23.7.16", | "i18next": "^23.7.16", | ||||
| "js-base64": "^3.7.5", | "js-base64": "^3.7.5", | ||||
| "jsencrypt": "^3.3.2", | "jsencrypt": "^3.3.2", | ||||
| "lodash": "^4.17.21", | "lodash": "^4.17.21", | ||||
| "moment": "^2.30.1", | |||||
| "rc-tween-one": "^3.0.6", | "rc-tween-one": "^3.0.6", | ||||
| "react-chat-elements": "^12.0.13", | "react-chat-elements": "^12.0.13", | ||||
| "react-copy-to-clipboard": "^5.1.0", | |||||
| "react-i18next": "^14.0.0", | "react-i18next": "^14.0.0", | ||||
| "react-infinite-scroll-component": "^6.1.0", | "react-infinite-scroll-component": "^6.1.0", | ||||
| "react-markdown": "^9.0.1", | "react-markdown": "^9.0.1", | ||||
| "react-pdf-highlighter": "^6.1.0", | "react-pdf-highlighter": "^6.1.0", | ||||
| "react-string-replace": "^1.1.1", | "react-string-replace": "^1.1.1", | ||||
| "react-syntax-highlighter": "^15.5.0", | "react-syntax-highlighter": "^15.5.0", | ||||
| "recharts": "^2.12.4", | |||||
| "remark-gfm": "^4.0.0", | "remark-gfm": "^4.0.0", | ||||
| "umi": "^4.0.90", | "umi": "^4.0.90", | ||||
| "umi-request": "^1.4.0", | "umi-request": "^1.4.0", | ||||
| "@react-dev-inspector/umi4-plugin": "^2.0.1", | "@react-dev-inspector/umi4-plugin": "^2.0.1", | ||||
| "@types/lodash": "^4.14.202", | "@types/lodash": "^4.14.202", | ||||
| "@types/react": "^18.0.33", | "@types/react": "^18.0.33", | ||||
| "@types/react-copy-to-clipboard": "^5.0.7", | |||||
| "@types/react-dom": "^18.0.11", | "@types/react-dom": "^18.0.11", | ||||
| "@types/react-syntax-highlighter": "^15.5.11", | "@types/react-syntax-highlighter": "^15.5.11", | ||||
| "@types/uuid": "^9.0.8", | "@types/uuid": "^9.0.8", | ||||
| "@babel/types": "^7.20.7" | "@babel/types": "^7.20.7" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/@types/d3-array": { | |||||
| "version": "3.2.1", | |||||
| "resolved": "https://registry.npmmirror.com/@types/d3-array/-/d3-array-3.2.1.tgz", | |||||
| "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" | |||||
| }, | |||||
| "node_modules/@types/d3-color": { | |||||
| "version": "3.1.3", | |||||
| "resolved": "https://registry.npmmirror.com/@types/d3-color/-/d3-color-3.1.3.tgz", | |||||
| "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" | |||||
| }, | |||||
| "node_modules/@types/d3-ease": { | |||||
| "version": "3.0.2", | |||||
| "resolved": "https://registry.npmmirror.com/@types/d3-ease/-/d3-ease-3.0.2.tgz", | |||||
| "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" | |||||
| }, | |||||
| "node_modules/@types/d3-interpolate": { | |||||
| "version": "3.0.4", | |||||
| "resolved": "https://registry.npmmirror.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", | |||||
| "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", | |||||
| "dependencies": { | |||||
| "@types/d3-color": "*" | |||||
| } | |||||
| }, | |||||
| "node_modules/@types/d3-path": { | |||||
| "version": "3.1.0", | |||||
| "resolved": "https://registry.npmmirror.com/@types/d3-path/-/d3-path-3.1.0.tgz", | |||||
| "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" | |||||
| }, | |||||
| "node_modules/@types/d3-scale": { | |||||
| "version": "4.0.8", | |||||
| "resolved": "https://registry.npmmirror.com/@types/d3-scale/-/d3-scale-4.0.8.tgz", | |||||
| "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", | |||||
| "dependencies": { | |||||
| "@types/d3-time": "*" | |||||
| } | |||||
| }, | |||||
| "node_modules/@types/d3-shape": { | |||||
| "version": "3.1.6", | |||||
| "resolved": "https://registry.npmmirror.com/@types/d3-shape/-/d3-shape-3.1.6.tgz", | |||||
| "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", | |||||
| "dependencies": { | |||||
| "@types/d3-path": "*" | |||||
| } | |||||
| }, | |||||
| "node_modules/@types/d3-time": { | |||||
| "version": "3.0.3", | |||||
| "resolved": "https://registry.npmmirror.com/@types/d3-time/-/d3-time-3.0.3.tgz", | |||||
| "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" | |||||
| }, | |||||
| "node_modules/@types/d3-timer": { | |||||
| "version": "3.0.2", | |||||
| "resolved": "https://registry.npmmirror.com/@types/d3-timer/-/d3-timer-3.0.2.tgz", | |||||
| "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" | |||||
| }, | |||||
| "node_modules/@types/debug": { | "node_modules/@types/debug": { | ||||
| "version": "4.1.12", | "version": "4.1.12", | ||||
| "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.12.tgz", | "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.12.tgz", | ||||
| "csstype": "^3.0.2" | "csstype": "^3.0.2" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/@types/react-copy-to-clipboard": { | |||||
| "version": "5.0.7", | |||||
| "resolved": "https://registry.npmmirror.com/@types/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.7.tgz", | |||||
| "integrity": "sha512-Gft19D+as4M+9Whq1oglhmK49vqPhcLzk8WfvfLvaYMIPYanyfLy0+CwFucMJfdKoSFyySPmkkWn8/E6voQXjQ==", | |||||
| "dev": true, | |||||
| "dependencies": { | |||||
| "@types/react": "*" | |||||
| } | |||||
| }, | |||||
| "node_modules/@types/react-dom": { | "node_modules/@types/react-dom": { | ||||
| "version": "18.2.18", | "version": "18.2.18", | ||||
| "resolved": "https://registry.npmmirror.com/@types/react-dom/-/react-dom-18.2.18.tgz", | "resolved": "https://registry.npmmirror.com/@types/react-dom/-/react-dom-18.2.18.tgz", | ||||
| "node": ">=12" | "node": ">=12" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/clsx": { | |||||
| "version": "2.1.0", | |||||
| "resolved": "https://registry.npmmirror.com/clsx/-/clsx-2.1.0.tgz", | |||||
| "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", | |||||
| "engines": { | |||||
| "node": ">=6" | |||||
| } | |||||
| }, | |||||
| "node_modules/coa": { | "node_modules/coa": { | ||||
| "version": "2.0.2", | "version": "2.0.2", | ||||
| "resolved": "https://registry.npmmirror.com/coa/-/coa-2.0.2.tgz", | "resolved": "https://registry.npmmirror.com/coa/-/coa-2.0.2.tgz", | ||||
| "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-1.2.4.tgz", | "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-1.2.4.tgz", | ||||
| "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" | "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" | ||||
| }, | }, | ||||
| "node_modules/d3-color": { | |||||
| "version": "3.1.0", | |||||
| "resolved": "https://registry.npmmirror.com/d3-color/-/d3-color-3.1.0.tgz", | |||||
| "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/d3-ease": { | |||||
| "version": "3.0.1", | |||||
| "resolved": "https://registry.npmmirror.com/d3-ease/-/d3-ease-3.0.1.tgz", | |||||
| "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/d3-format": { | |||||
| "version": "3.1.0", | |||||
| "resolved": "https://registry.npmmirror.com/d3-format/-/d3-format-3.1.0.tgz", | |||||
| "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/d3-interpolate": { | |||||
| "version": "3.0.1", | |||||
| "resolved": "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz", | |||||
| "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", | |||||
| "dependencies": { | |||||
| "d3-color": "1 - 3" | |||||
| }, | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/d3-path": { | |||||
| "version": "3.1.0", | |||||
| "resolved": "https://registry.npmmirror.com/d3-path/-/d3-path-3.1.0.tgz", | |||||
| "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/d3-polygon": { | "node_modules/d3-polygon": { | ||||
| "version": "1.0.6", | "version": "1.0.6", | ||||
| "resolved": "https://registry.npmmirror.com/d3-polygon/-/d3-polygon-1.0.6.tgz", | "resolved": "https://registry.npmmirror.com/d3-polygon/-/d3-polygon-1.0.6.tgz", | ||||
| "integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==" | "integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==" | ||||
| }, | }, | ||||
| "node_modules/d3-scale": { | |||||
| "version": "4.0.2", | |||||
| "resolved": "https://registry.npmmirror.com/d3-scale/-/d3-scale-4.0.2.tgz", | |||||
| "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", | |||||
| "dependencies": { | |||||
| "d3-array": "2.10.0 - 3", | |||||
| "d3-format": "1 - 3", | |||||
| "d3-interpolate": "1.2.0 - 3", | |||||
| "d3-time": "2.1.1 - 3", | |||||
| "d3-time-format": "2 - 4" | |||||
| }, | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/d3-scale/node_modules/d3-array": { | |||||
| "version": "3.2.4", | |||||
| "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-3.2.4.tgz", | |||||
| "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", | |||||
| "dependencies": { | |||||
| "internmap": "1 - 2" | |||||
| }, | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/d3-shape": { | |||||
| "version": "3.2.0", | |||||
| "resolved": "https://registry.npmmirror.com/d3-shape/-/d3-shape-3.2.0.tgz", | |||||
| "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", | |||||
| "dependencies": { | |||||
| "d3-path": "^3.1.0" | |||||
| }, | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/d3-time": { | |||||
| "version": "3.1.0", | |||||
| "resolved": "https://registry.npmmirror.com/d3-time/-/d3-time-3.1.0.tgz", | |||||
| "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", | |||||
| "dependencies": { | |||||
| "d3-array": "2 - 3" | |||||
| }, | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/d3-time-format": { | |||||
| "version": "4.1.0", | |||||
| "resolved": "https://registry.npmmirror.com/d3-time-format/-/d3-time-format-4.1.0.tgz", | |||||
| "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", | |||||
| "dependencies": { | |||||
| "d3-time": "1 - 3" | |||||
| }, | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/d3-time/node_modules/d3-array": { | |||||
| "version": "3.2.4", | |||||
| "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-3.2.4.tgz", | |||||
| "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", | |||||
| "dependencies": { | |||||
| "internmap": "1 - 2" | |||||
| }, | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/d3-timer": { | |||||
| "version": "3.0.1", | |||||
| "resolved": "https://registry.npmmirror.com/d3-timer/-/d3-timer-3.0.1.tgz", | |||||
| "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/data-uri-to-buffer": { | "node_modules/data-uri-to-buffer": { | ||||
| "version": "4.0.1", | "version": "4.0.1", | ||||
| "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", | "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", | ||||
| "node": ">=0.10.0" | "node": ">=0.10.0" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/decimal.js-light": { | |||||
| "version": "2.5.1", | |||||
| "resolved": "https://registry.npmmirror.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz", | |||||
| "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" | |||||
| }, | |||||
| "node_modules/decode-named-character-reference": { | "node_modules/decode-named-character-reference": { | ||||
| "version": "1.0.2", | "version": "1.0.2", | ||||
| "resolved": "https://registry.npmmirror.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", | "resolved": "https://registry.npmmirror.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", | ||||
| "utila": "~0.4" | "utila": "~0.4" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/dom-helpers": { | |||||
| "version": "5.2.1", | |||||
| "resolved": "https://registry.npmmirror.com/dom-helpers/-/dom-helpers-5.2.1.tgz", | |||||
| "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", | |||||
| "dependencies": { | |||||
| "@babel/runtime": "^7.8.7", | |||||
| "csstype": "^3.0.2" | |||||
| } | |||||
| }, | |||||
| "node_modules/dom-serializer": { | "node_modules/dom-serializer": { | ||||
| "version": "1.4.1", | "version": "1.4.1", | ||||
| "resolved": "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-1.4.1.tgz", | "resolved": "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-1.4.1.tgz", | ||||
| "es5-ext": "~0.10.14" | "es5-ext": "~0.10.14" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/eventemitter3": { | |||||
| "version": "4.0.7", | |||||
| "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz", | |||||
| "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" | |||||
| }, | |||||
| "node_modules/events": { | "node_modules/events": { | ||||
| "version": "3.3.0", | "version": "3.3.0", | ||||
| "resolved": "https://registry.npmmirror.com/events/-/events-3.3.0.tgz", | "resolved": "https://registry.npmmirror.com/events/-/events-3.3.0.tgz", | ||||
| "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", | "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", | ||||
| "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" | ||||
| }, | }, | ||||
| "node_modules/fast-equals": { | |||||
| "version": "5.0.1", | |||||
| "resolved": "https://registry.npmmirror.com/fast-equals/-/fast-equals-5.0.1.tgz", | |||||
| "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", | |||||
| "engines": { | |||||
| "node": ">=6.0.0" | |||||
| } | |||||
| }, | |||||
| "node_modules/fast-glob": { | "node_modules/fast-glob": { | ||||
| "version": "3.2.12", | "version": "3.2.12", | ||||
| "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.2.12.tgz", | "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.2.12.tgz", | ||||
| "node": ">= 0.4" | "node": ">= 0.4" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/internmap": { | |||||
| "version": "2.0.3", | |||||
| "resolved": "https://registry.npmmirror.com/internmap/-/internmap-2.0.3.tgz", | |||||
| "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/intersection-observer": { | "node_modules/intersection-observer": { | ||||
| "version": "0.12.2", | "version": "0.12.2", | ||||
| "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz", | "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz", | ||||
| "version": "2.30.1", | "version": "2.30.1", | ||||
| "resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz", | "resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz", | ||||
| "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", | "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", | ||||
| "devOptional": true, | |||||
| "engines": { | "engines": { | ||||
| "node": "*" | "node": "*" | ||||
| } | } | ||||
| "react-dom": "18.2.0" | "react-dom": "18.2.0" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/react-copy-to-clipboard": { | |||||
| "version": "5.1.0", | |||||
| "resolved": "https://registry.npmmirror.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", | |||||
| "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==", | |||||
| "dependencies": { | |||||
| "copy-to-clipboard": "^3.3.1", | |||||
| "prop-types": "^15.8.1" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "react": "^15.3.0 || 16 || 17 || 18" | |||||
| } | |||||
| }, | |||||
| "node_modules/react-dev-inspector": { | "node_modules/react-dev-inspector": { | ||||
| "version": "2.0.1", | "version": "2.0.1", | ||||
| "resolved": "https://registry.npmmirror.com/react-dev-inspector/-/react-dev-inspector-2.0.1.tgz", | "resolved": "https://registry.npmmirror.com/react-dev-inspector/-/react-dev-inspector-2.0.1.tgz", | ||||
| "react": ">=15" | "react": ">=15" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/react-smooth": { | |||||
| "version": "4.0.1", | |||||
| "resolved": "https://registry.npmmirror.com/react-smooth/-/react-smooth-4.0.1.tgz", | |||||
| "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", | |||||
| "dependencies": { | |||||
| "fast-equals": "^5.0.1", | |||||
| "prop-types": "^15.8.1", | |||||
| "react-transition-group": "^4.4.5" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "react": "^16.8.0 || ^17.0.0 || ^18.0.0", | |||||
| "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" | |||||
| } | |||||
| }, | |||||
| "node_modules/react-spinkit": { | "node_modules/react-spinkit": { | ||||
| "version": "3.0.0", | "version": "3.0.0", | ||||
| "resolved": "https://registry.npmmirror.com/react-spinkit/-/react-spinkit-3.0.0.tgz", | "resolved": "https://registry.npmmirror.com/react-spinkit/-/react-spinkit-3.0.0.tgz", | ||||
| "react": ">= 0.14.0" | "react": ">= 0.14.0" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/react-transition-group": { | |||||
| "version": "4.4.5", | |||||
| "resolved": "https://registry.npmmirror.com/react-transition-group/-/react-transition-group-4.4.5.tgz", | |||||
| "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", | |||||
| "dependencies": { | |||||
| "@babel/runtime": "^7.5.5", | |||||
| "dom-helpers": "^5.0.1", | |||||
| "loose-envify": "^1.4.0", | |||||
| "prop-types": "^15.6.2" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "react": ">=16.6.0", | |||||
| "react-dom": ">=16.6.0" | |||||
| } | |||||
| }, | |||||
| "node_modules/reactcss": { | "node_modules/reactcss": { | ||||
| "version": "1.2.3", | "version": "1.2.3", | ||||
| "resolved": "https://registry.npmmirror.com/reactcss/-/reactcss-1.2.3.tgz", | "resolved": "https://registry.npmmirror.com/reactcss/-/reactcss-1.2.3.tgz", | ||||
| "node": ">= 12.13.0" | "node": ">= 12.13.0" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/recharts": { | |||||
| "version": "2.12.4", | |||||
| "resolved": "https://registry.npmmirror.com/recharts/-/recharts-2.12.4.tgz", | |||||
| "integrity": "sha512-dM4skmk4fDKEDjL9MNunxv6zcTxePGVEzRnLDXALRpfJ85JoQ0P0APJ/CoJlmnQI0gPjBlOkjzrwrfQrRST3KA==", | |||||
| "dependencies": { | |||||
| "clsx": "^2.0.0", | |||||
| "eventemitter3": "^4.0.1", | |||||
| "lodash": "^4.17.21", | |||||
| "react-is": "^16.10.2", | |||||
| "react-smooth": "^4.0.0", | |||||
| "recharts-scale": "^0.4.4", | |||||
| "tiny-invariant": "^1.3.1", | |||||
| "victory-vendor": "^36.6.8" | |||||
| }, | |||||
| "engines": { | |||||
| "node": ">=14" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "react": "^16.0.0 || ^17.0.0 || ^18.0.0", | |||||
| "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" | |||||
| } | |||||
| }, | |||||
| "node_modules/recharts-scale": { | |||||
| "version": "0.4.5", | |||||
| "resolved": "https://registry.npmmirror.com/recharts-scale/-/recharts-scale-0.4.5.tgz", | |||||
| "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", | |||||
| "dependencies": { | |||||
| "decimal.js-light": "^2.4.1" | |||||
| } | |||||
| }, | |||||
| "node_modules/recharts/node_modules/react-is": { | |||||
| "version": "16.13.1", | |||||
| "resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz", | |||||
| "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" | |||||
| }, | |||||
| "node_modules/recursive-readdir": { | "node_modules/recursive-readdir": { | ||||
| "version": "2.2.3", | "version": "2.2.3", | ||||
| "resolved": "https://registry.npmmirror.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz", | "resolved": "https://registry.npmmirror.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz", | ||||
| "node_modules/tiny-invariant": { | "node_modules/tiny-invariant": { | ||||
| "version": "1.3.1", | "version": "1.3.1", | ||||
| "resolved": "https://registry.npmmirror.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz", | "resolved": "https://registry.npmmirror.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz", | ||||
| "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==", | |||||
| "dev": true, | |||||
| "peer": true | |||||
| "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" | |||||
| }, | }, | ||||
| "node_modules/tiny-warning": { | "node_modules/tiny-warning": { | ||||
| "version": "1.0.3", | "version": "1.0.3", | ||||
| "unist-util-stringify-position": "^4.0.0" | "unist-util-stringify-position": "^4.0.0" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/victory-vendor": { | |||||
| "version": "36.9.2", | |||||
| "resolved": "https://registry.npmmirror.com/victory-vendor/-/victory-vendor-36.9.2.tgz", | |||||
| "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", | |||||
| "dependencies": { | |||||
| "@types/d3-array": "^3.0.3", | |||||
| "@types/d3-ease": "^3.0.0", | |||||
| "@types/d3-interpolate": "^3.0.1", | |||||
| "@types/d3-scale": "^4.0.2", | |||||
| "@types/d3-shape": "^3.1.0", | |||||
| "@types/d3-time": "^3.0.0", | |||||
| "@types/d3-timer": "^3.0.0", | |||||
| "d3-array": "^3.1.6", | |||||
| "d3-ease": "^3.0.1", | |||||
| "d3-interpolate": "^3.0.1", | |||||
| "d3-scale": "^4.0.2", | |||||
| "d3-shape": "^3.1.0", | |||||
| "d3-time": "^3.0.0", | |||||
| "d3-timer": "^3.0.1" | |||||
| } | |||||
| }, | |||||
| "node_modules/victory-vendor/node_modules/d3-array": { | |||||
| "version": "3.2.4", | |||||
| "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-3.2.4.tgz", | |||||
| "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", | |||||
| "dependencies": { | |||||
| "internmap": "1 - 2" | |||||
| }, | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| } | |||||
| }, | |||||
| "node_modules/vite": { | "node_modules/vite": { | ||||
| "version": "4.3.1", | "version": "4.3.1", | ||||
| "resolved": "https://registry.npmmirror.com/vite/-/vite-4.3.1.tgz", | "resolved": "https://registry.npmmirror.com/vite/-/vite-4.3.1.tgz", |
| "antd": "^5.12.7", | "antd": "^5.12.7", | ||||
| "axios": "^1.6.3", | "axios": "^1.6.3", | ||||
| "classnames": "^2.5.1", | "classnames": "^2.5.1", | ||||
| "dayjs": "^1.11.10", | |||||
| "i18next": "^23.7.16", | "i18next": "^23.7.16", | ||||
| "js-base64": "^3.7.5", | "js-base64": "^3.7.5", | ||||
| "jsencrypt": "^3.3.2", | "jsencrypt": "^3.3.2", | ||||
| "lodash": "^4.17.21", | "lodash": "^4.17.21", | ||||
| "moment": "^2.30.1", | |||||
| "rc-tween-one": "^3.0.6", | "rc-tween-one": "^3.0.6", | ||||
| "react-chat-elements": "^12.0.13", | "react-chat-elements": "^12.0.13", | ||||
| "react-copy-to-clipboard": "^5.1.0", | |||||
| "react-i18next": "^14.0.0", | "react-i18next": "^14.0.0", | ||||
| "react-infinite-scroll-component": "^6.1.0", | "react-infinite-scroll-component": "^6.1.0", | ||||
| "react-markdown": "^9.0.1", | "react-markdown": "^9.0.1", | ||||
| "react-pdf-highlighter": "^6.1.0", | "react-pdf-highlighter": "^6.1.0", | ||||
| "react-string-replace": "^1.1.1", | "react-string-replace": "^1.1.1", | ||||
| "react-syntax-highlighter": "^15.5.0", | "react-syntax-highlighter": "^15.5.0", | ||||
| "recharts": "^2.12.4", | |||||
| "remark-gfm": "^4.0.0", | "remark-gfm": "^4.0.0", | ||||
| "umi": "^4.0.90", | "umi": "^4.0.90", | ||||
| "umi-request": "^1.4.0", | "umi-request": "^1.4.0", | ||||
| "@react-dev-inspector/umi4-plugin": "^2.0.1", | "@react-dev-inspector/umi4-plugin": "^2.0.1", | ||||
| "@types/lodash": "^4.14.202", | "@types/lodash": "^4.14.202", | ||||
| "@types/react": "^18.0.33", | "@types/react": "^18.0.33", | ||||
| "@types/react-copy-to-clipboard": "^5.0.7", | |||||
| "@types/react-dom": "^18.0.11", | "@types/react-dom": "^18.0.11", | ||||
| "@types/react-syntax-highlighter": "^15.5.11", | "@types/react-syntax-highlighter": "^15.5.11", | ||||
| "@types/uuid": "^9.0.8", | "@types/uuid": "^9.0.8", |
| import React, { ReactNode, useEffect, useState } from 'react'; | import React, { ReactNode, useEffect, useState } from 'react'; | ||||
| import storage from './utils/authorizationUtil'; | import storage from './utils/authorizationUtil'; | ||||
| import dayjs from 'dayjs'; | |||||
| import advancedFormat from 'dayjs/plugin/advancedFormat'; | |||||
| import customParseFormat from 'dayjs/plugin/customParseFormat'; | |||||
| import localeData from 'dayjs/plugin/localeData'; | |||||
| import weekday from 'dayjs/plugin/weekday'; | |||||
| import weekOfYear from 'dayjs/plugin/weekOfYear'; | |||||
| import weekYear from 'dayjs/plugin/weekYear'; | |||||
| dayjs.extend(customParseFormat); | |||||
| dayjs.extend(advancedFormat); | |||||
| dayjs.extend(weekday); | |||||
| dayjs.extend(localeData); | |||||
| dayjs.extend(weekOfYear); | |||||
| dayjs.extend(weekYear); | |||||
| const AntLanguageMap = { | const AntLanguageMap = { | ||||
| en: enUS, | en: enUS, | ||||
| zh: zhCN, | zh: zhCN, |
| import { useTranslate } from '@/hooks/commonHooks'; | |||||
| import { CheckOutlined, CopyOutlined } from '@ant-design/icons'; | |||||
| import { Tooltip } from 'antd'; | |||||
| import { useState } from 'react'; | |||||
| import { CopyToClipboard as Clipboard, Props } from 'react-copy-to-clipboard'; | |||||
| const CopyToClipboard = ({ text }: Props) => { | |||||
| const [copied, setCopied] = useState(false); | |||||
| const { t } = useTranslate('common'); | |||||
| const handleCopy = () => { | |||||
| setCopied(true); | |||||
| setTimeout(() => { | |||||
| setCopied(false); | |||||
| }, 2000); | |||||
| }; | |||||
| return ( | |||||
| <Tooltip title={copied ? t('copied') : t('copy')}> | |||||
| <Clipboard text={text} onCopy={handleCopy}> | |||||
| {copied ? <CheckOutlined /> : <CopyOutlined />} | |||||
| </Clipboard> | |||||
| </Tooltip> | |||||
| ); | |||||
| }; | |||||
| export default CopyToClipboard; |
| import { | |||||
| CartesianGrid, | |||||
| Legend, | |||||
| Line, | |||||
| LineChart, | |||||
| ResponsiveContainer, | |||||
| Tooltip, | |||||
| XAxis, | |||||
| YAxis, | |||||
| } from 'recharts'; | |||||
| import { CategoricalChartProps } from 'recharts/types/chart/generateCategoricalChart'; | |||||
| const data = [ | |||||
| { | |||||
| name: 'Page A', | |||||
| uv: 4000, | |||||
| pv: 2400, | |||||
| }, | |||||
| { | |||||
| name: 'Page B', | |||||
| uv: 3000, | |||||
| pv: 1398, | |||||
| }, | |||||
| { | |||||
| name: 'Page C', | |||||
| uv: 2000, | |||||
| pv: 9800, | |||||
| }, | |||||
| { | |||||
| name: 'Page D', | |||||
| uv: 2780, | |||||
| pv: 3908, | |||||
| }, | |||||
| { | |||||
| name: 'Page E', | |||||
| uv: 1890, | |||||
| pv: 4800, | |||||
| }, | |||||
| { | |||||
| name: 'Page F', | |||||
| uv: 2390, | |||||
| pv: 3800, | |||||
| }, | |||||
| { | |||||
| name: 'Page G', | |||||
| uv: 3490, | |||||
| pv: 4300, | |||||
| }, | |||||
| ]; | |||||
| interface IProps extends CategoricalChartProps { | |||||
| data?: Array<{ xAxis: string; yAxis: number }>; | |||||
| } | |||||
| const RagLineChart = ({ data }: IProps) => { | |||||
| return ( | |||||
| <ResponsiveContainer width="100%" height="100%"> | |||||
| <LineChart | |||||
| // width={500} | |||||
| // height={300} | |||||
| data={data} | |||||
| margin={ | |||||
| { | |||||
| // top: 5, | |||||
| // right: 30, | |||||
| // left: 20, | |||||
| // bottom: 10, | |||||
| } | |||||
| } | |||||
| > | |||||
| <CartesianGrid strokeDasharray="3 3" /> | |||||
| <XAxis dataKey="xAxis" /> | |||||
| <YAxis /> | |||||
| <Tooltip /> | |||||
| <Legend /> | |||||
| <Line | |||||
| type="monotone" | |||||
| dataKey="yAxis" | |||||
| stroke="#8884d8" | |||||
| activeDot={{ r: 8 }} | |||||
| /> | |||||
| {/* <Line type="monotone" dataKey="uv" stroke="#82ca9d" /> */} | |||||
| </LineChart> | |||||
| </ResponsiveContainer> | |||||
| ); | |||||
| }; | |||||
| export default RagLineChart; |
| import { IConversation, IDialog } from '@/interfaces/database/chat'; | |||||
| import { | |||||
| IConversation, | |||||
| IDialog, | |||||
| IStats, | |||||
| IToken, | |||||
| } from '@/interfaces/database/chat'; | |||||
| import { useCallback } from 'react'; | import { useCallback } from 'react'; | ||||
| import { useDispatch, useSelector } from 'umi'; | import { useDispatch, useSelector } from 'umi'; | ||||
| return completeConversation; | return completeConversation; | ||||
| }; | }; | ||||
| // #region API provided for external calls | |||||
| export const useCreateToken = (dialogId: string) => { | |||||
| const dispatch = useDispatch(); | |||||
| const createToken = useCallback(() => { | |||||
| return dispatch<any>({ | |||||
| type: 'chatModel/createToken', | |||||
| payload: { dialogId }, | |||||
| }); | |||||
| }, [dispatch, dialogId]); | |||||
| return createToken; | |||||
| }; | |||||
| export const useListToken = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const listToken = useCallback( | |||||
| (dialogId: string) => { | |||||
| return dispatch<any>({ | |||||
| type: 'chatModel/listToken', | |||||
| payload: { dialogId }, | |||||
| }); | |||||
| }, | |||||
| [dispatch], | |||||
| ); | |||||
| return listToken; | |||||
| }; | |||||
| export const useSelectTokenList = () => { | |||||
| const tokenList: IToken[] = useSelector( | |||||
| (state: any) => state.chatModel.tokenList, | |||||
| ); | |||||
| return tokenList; | |||||
| }; | |||||
| export const useRemoveToken = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const removeToken = useCallback( | |||||
| (payload: { tenantId: string; dialogId: string; tokens: string[] }) => { | |||||
| return dispatch<any>({ | |||||
| type: 'chatModel/removeToken', | |||||
| payload: payload, | |||||
| }); | |||||
| }, | |||||
| [dispatch], | |||||
| ); | |||||
| return removeToken; | |||||
| }; | |||||
| export const useFetchStats = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const fetchStats = useCallback( | |||||
| (payload: any) => { | |||||
| return dispatch<any>({ | |||||
| type: 'chatModel/getStats', | |||||
| payload, | |||||
| }); | |||||
| }, | |||||
| [dispatch], | |||||
| ); | |||||
| return fetchStats; | |||||
| }; | |||||
| export const useSelectStats = () => { | |||||
| const stats: IStats = useSelector((state: any) => state.chatModel.stats); | |||||
| return stats; | |||||
| }; | |||||
| //#endregion |
| // term_similarity: number; | // term_similarity: number; | ||||
| // vector_similarity: number; | // vector_similarity: number; | ||||
| // } | // } | ||||
| export interface IToken { | |||||
| create_date: string; | |||||
| create_time: number; | |||||
| tenant_id: string; | |||||
| token: string; | |||||
| update_date?: any; | |||||
| update_time?: any; | |||||
| } | |||||
| export interface IStats { | |||||
| pv: [string, number][]; | |||||
| uv: [string, number][]; | |||||
| speed: [string, number][]; | |||||
| tokens: [string, number][]; | |||||
| round: [string, number][]; | |||||
| thumb_up: [string, number][]; | |||||
| } |
| language: 'Language', | language: 'Language', | ||||
| languageMessage: 'Please input your language!', | languageMessage: 'Please input your language!', | ||||
| languagePlaceholder: 'select your language', | languagePlaceholder: 'select your language', | ||||
| copy: 'Copy', | |||||
| copied: 'Copied', | |||||
| }, | }, | ||||
| login: { | login: { | ||||
| login: 'Sign in', | login: 'Sign in', | ||||
| 'This sets the maximum length of the model’s output, measured in the number of tokens (words or pieces of words).', | 'This sets the maximum length of the model’s output, measured in the number of tokens (words or pieces of words).', | ||||
| quote: 'Show Quote', | quote: 'Show Quote', | ||||
| quoteTip: 'Should the source of the original text be displayed?', | quoteTip: 'Should the source of the original text be displayed?', | ||||
| overview: 'Overview', | |||||
| pv: 'Number of messages', | |||||
| uv: 'Active user number', | |||||
| speed: 'Token output speed', | |||||
| tokens: 'Consume the token number', | |||||
| round: 'Session Interaction Number', | |||||
| thumbUp: 'customer satisfaction', | |||||
| publicUrl: 'Public URL', | |||||
| preview: 'Preview', | |||||
| embedded: 'Embedded', | |||||
| serviceApiEndpoint: 'Service API Endpoint', | |||||
| apiKey: 'Api Key', | |||||
| apiReference: 'Api Reference', | |||||
| dateRange: 'Date Range:', | |||||
| backendServiceApi: 'Backend service API', | |||||
| createNewKey: 'Create new key', | |||||
| created: 'Created', | |||||
| action: 'Action', | |||||
| }, | }, | ||||
| setting: { | setting: { | ||||
| profile: 'Profile', | profile: 'Profile', |
| edit: '編輯', | edit: '編輯', | ||||
| upload: '上傳', | upload: '上傳', | ||||
| english: '英語', | english: '英語', | ||||
| chinese: '中文簡體', | |||||
| traditionalChinese: '中文繁體', | |||||
| chinese: '簡體中文', | |||||
| traditionalChinese: '繁體中文', | |||||
| language: '語言', | language: '語言', | ||||
| languageMessage: '請輸入語言', | languageMessage: '請輸入語言', | ||||
| languagePlaceholder: '請選擇語言', | languagePlaceholder: '請選擇語言', | ||||
| copy: '複製', | |||||
| copied: '複製成功', | |||||
| }, | }, | ||||
| login: { | login: { | ||||
| login: '登入', | login: '登入', | ||||
| systemMessage: '請輸入', | systemMessage: '請輸入', | ||||
| systemTip: | systemTip: | ||||
| '當LLM回答問題時,你需要LLM遵循的說明,比如角色設計、答案長度和答案語言等。', | '當LLM回答問題時,你需要LLM遵循的說明,比如角色設計、答案長度和答案語言等。', | ||||
| topN: 'top n', | |||||
| topN: 'Top N', | |||||
| topNTip: `並非所有相似度得分高於“相似度閾值”的塊都會被提供給法學碩士。LLM 只能看到這些“Top N”塊。`, | topNTip: `並非所有相似度得分高於“相似度閾值”的塊都會被提供給法學碩士。LLM 只能看到這些“Top N”塊。`, | ||||
| variable: '變量', | variable: '變量', | ||||
| variableTip: `如果您使用对话 API,变量可能会帮助您使用不同的策略与客户聊天。 | variableTip: `如果您使用对话 API,变量可能会帮助您使用不同的策略与客户聊天。 | ||||
| '這設置了模型輸出的最大長度,以標記(單詞或單詞片段)的數量來衡量。', | '這設置了模型輸出的最大長度,以標記(單詞或單詞片段)的數量來衡量。', | ||||
| quote: '顯示引文', | quote: '顯示引文', | ||||
| quoteTip: '是否應該顯示原文出處?', | quoteTip: '是否應該顯示原文出處?', | ||||
| overview: '概覽', | |||||
| pv: '消息數', | |||||
| uv: '活躍用戶數', | |||||
| speed: 'Token 輸出速度', | |||||
| tokens: '消耗Token數', | |||||
| round: '會話互動數', | |||||
| thumbUp: '用戶滿意度', | |||||
| publicUrl: '公共url', | |||||
| preview: '預覽', | |||||
| embedded: '嵌入', | |||||
| serviceApiEndpoint: '服務API端點', | |||||
| apiKey: 'API鍵', | |||||
| apiReference: 'API參考', | |||||
| dateRange: '日期範圍:', | |||||
| backendServiceApi: '後端服務API', | |||||
| createNewKey: '創建新密鑰', | |||||
| created: '創建於', | |||||
| action: '操作', | |||||
| }, | }, | ||||
| setting: { | setting: { | ||||
| profile: '概述', | profile: '概述', |
| edit: '编辑', | edit: '编辑', | ||||
| upload: '上传', | upload: '上传', | ||||
| english: '英文', | english: '英文', | ||||
| chinese: '中文简体', | |||||
| traditionalChinese: '中文繁体', | |||||
| chinese: '简体中文', | |||||
| traditionalChinese: '繁体中文', | |||||
| language: '语言', | language: '语言', | ||||
| languageMessage: '请输入语言', | languageMessage: '请输入语言', | ||||
| languagePlaceholder: '请选择语言', | languagePlaceholder: '请选择语言', | ||||
| copy: '复制', | |||||
| copied: '复制成功', | |||||
| }, | }, | ||||
| login: { | login: { | ||||
| login: '登录', | login: '登录', | ||||
| '这设置了模型输出的最大长度,以标记(单词或单词片段)的数量来衡量。', | '这设置了模型输出的最大长度,以标记(单词或单词片段)的数量来衡量。', | ||||
| quote: '显示引文', | quote: '显示引文', | ||||
| quoteTip: '是否应该显示原文出处?', | quoteTip: '是否应该显示原文出处?', | ||||
| overview: '概览', | |||||
| pv: '消息数', | |||||
| uv: '活跃用户数', | |||||
| speed: 'Token 输出速度', | |||||
| tokens: '消耗Token数', | |||||
| round: '会话互动数', | |||||
| thumbUp: '用户满意度', | |||||
| publicUrl: '公共Url', | |||||
| preview: '预览', | |||||
| embedded: '嵌入', | |||||
| serviceApiEndpoint: '服务API端点', | |||||
| apiKey: 'API键', | |||||
| apiReference: 'API参考', | |||||
| dateRange: '日期范围:', | |||||
| backendServiceApi: '后端服务API', | |||||
| createNewKey: '创建新密钥', | |||||
| created: '创建于', | |||||
| action: '操作', | |||||
| }, | }, | ||||
| setting: { | setting: { | ||||
| profile: '概要', | profile: '概要', |
| import ParsingStatusCell from './parsing-status-cell'; | import ParsingStatusCell from './parsing-status-cell'; | ||||
| import RenameModal from './rename-modal'; | import RenameModal from './rename-modal'; | ||||
| import { formatDate } from '@/utils/date'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| const KnowledgeFile = () => { | const KnowledgeFile = () => { | ||||
| title: t('uploadDate'), | title: t('uploadDate'), | ||||
| dataIndex: 'create_date', | dataIndex: 'create_date', | ||||
| key: 'create_date', | key: 'create_date', | ||||
| render(value) { | |||||
| return formatDate(value); | |||||
| }, | |||||
| }, | }, | ||||
| { | { | ||||
| title: t('chunkMethod'), | title: t('chunkMethod'), |
| import CopyToClipboard from '@/components/copy-to-clipboard'; | |||||
| import { useTranslate } from '@/hooks/commonHooks'; | |||||
| import { IModalProps } from '@/interfaces/common'; | |||||
| import { IToken } from '@/interfaces/database/chat'; | |||||
| import { formatDate } from '@/utils/date'; | |||||
| import { DeleteOutlined } from '@ant-design/icons'; | |||||
| import type { TableProps } from 'antd'; | |||||
| import { Button, Modal, Space, Table } from 'antd'; | |||||
| import { useOperateApiKey } from '../hooks'; | |||||
| const ChatApiKeyModal = ({ | |||||
| visible, | |||||
| dialogId, | |||||
| hideModal, | |||||
| }: IModalProps<any> & { dialogId: string }) => { | |||||
| const { createToken, removeToken, tokenList, listLoading, creatingLoading } = | |||||
| useOperateApiKey(visible, dialogId); | |||||
| const { t } = useTranslate('chat'); | |||||
| const columns: TableProps<IToken>['columns'] = [ | |||||
| { | |||||
| title: 'Token', | |||||
| dataIndex: 'token', | |||||
| key: 'token', | |||||
| render: (text) => <a>{text}</a>, | |||||
| }, | |||||
| { | |||||
| title: t('created'), | |||||
| dataIndex: 'create_date', | |||||
| key: 'create_date', | |||||
| render: (text) => formatDate(text), | |||||
| }, | |||||
| { | |||||
| title: t('action'), | |||||
| key: 'action', | |||||
| render: (_, record) => ( | |||||
| <Space size="middle"> | |||||
| <CopyToClipboard text={record.token}></CopyToClipboard> | |||||
| <DeleteOutlined | |||||
| onClick={() => removeToken(record.token, record.tenant_id)} | |||||
| /> | |||||
| </Space> | |||||
| ), | |||||
| }, | |||||
| ]; | |||||
| return ( | |||||
| <> | |||||
| <Modal | |||||
| title={t('apiKey')} | |||||
| open={visible} | |||||
| onCancel={hideModal} | |||||
| style={{ top: 300 }} | |||||
| width={'50vw'} | |||||
| > | |||||
| <Table | |||||
| columns={columns} | |||||
| dataSource={tokenList} | |||||
| rowKey={'token'} | |||||
| loading={listLoading} | |||||
| /> | |||||
| <Button onClick={createToken} loading={creatingLoading}> | |||||
| {t('createNewKey')} | |||||
| </Button> | |||||
| </Modal> | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| export default ChatApiKeyModal; |
| import { useFetchKnowledgeList } from '@/hooks/knowledgeHook'; | import { useFetchKnowledgeList } from '@/hooks/knowledgeHook'; | ||||
| import { PlusOutlined } from '@ant-design/icons'; | import { PlusOutlined } from '@ant-design/icons'; | ||||
| import { Form, Input, Select, Upload } from 'antd'; | |||||
| import { Form, Input, Select, Switch, Upload } from 'antd'; | |||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { ISegmentedContentProps } from '../interface'; | import { ISegmentedContentProps } from '../interface'; | ||||
| > | > | ||||
| <Input.TextArea autoSize={{ minRows: 5 }} /> | <Input.TextArea autoSize={{ minRows: 5 }} /> | ||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | |||||
| label={t('quote')} | |||||
| valuePropName="checked" | |||||
| name={['prompt_config', 'quote']} | |||||
| tooltip={t('quoteTip')} | |||||
| initialValue={true} | |||||
| > | |||||
| <Switch /> | |||||
| </Form.Item> | |||||
| <Form.Item | <Form.Item | ||||
| label={t('knowledgeBases')} | label={t('knowledgeBases')} | ||||
| name="kb_ids" | name="kb_ids" |
| > | > | ||||
| <Slider max={30} /> | <Slider max={30} /> | ||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | |||||
| label={t('quote')} | |||||
| valuePropName="checked" | |||||
| name={['prompt_config', 'quote']} | |||||
| tooltip={t('quoteTip')} | |||||
| initialValue={true} | |||||
| > | |||||
| <Switch /> | |||||
| </Form.Item> | |||||
| <section className={classNames(styles.variableContainer)}> | <section className={classNames(styles.variableContainer)}> | ||||
| <Row align={'middle'} justify="end"> | <Row align={'middle'} justify="end"> | ||||
| <Col span={7} className={styles.variableAlign}> | <Col span={7} className={styles.variableAlign}> |
| .chartWrapper { | |||||
| height: 40vh; | |||||
| overflow: auto; | |||||
| } | |||||
| .chartItem { | |||||
| height: 300px; | |||||
| padding: 10px 0 30px; | |||||
| } | |||||
| .chartLabel { | |||||
| display: inline-block; | |||||
| padding-left: 60px; | |||||
| padding-bottom: 20px; | |||||
| } | |||||
| .linkText { | |||||
| border-radius: 6px; | |||||
| padding: 6px 10px; | |||||
| background-color: #eff8ff; | |||||
| border: 1px; | |||||
| } |
| import LineChart from '@/components/line-chart'; | |||||
| import { useSetModalState, useTranslate } from '@/hooks/commonHooks'; | |||||
| import { IModalProps } from '@/interfaces/common'; | |||||
| import { IDialog, IStats } from '@/interfaces/database/chat'; | |||||
| import { Button, Card, DatePicker, Flex, Modal, Space, Typography } from 'antd'; | |||||
| import { RangePickerProps } from 'antd/es/date-picker'; | |||||
| import dayjs from 'dayjs'; | |||||
| import camelCase from 'lodash/camelCase'; | |||||
| import ChatApiKeyModal from '../chat-api-key-modal'; | |||||
| import { useFetchStatsOnMount, useSelectChartStatsList } from '../hooks'; | |||||
| import styles from './index.less'; | |||||
| const { Paragraph } = Typography; | |||||
| const { RangePicker } = DatePicker; | |||||
| const ChatOverviewModal = ({ | |||||
| visible, | |||||
| hideModal, | |||||
| dialog, | |||||
| }: IModalProps<any> & { dialog: IDialog }) => { | |||||
| const { t } = useTranslate('chat'); | |||||
| const chartList = useSelectChartStatsList(); | |||||
| const { | |||||
| visible: apiKeyVisible, | |||||
| hideModal: hideApiKeyModal, | |||||
| showModal: showApiKeyModal, | |||||
| } = useSetModalState(); | |||||
| const { pickerValue, setPickerValue } = useFetchStatsOnMount(visible); | |||||
| const disabledDate: RangePickerProps['disabledDate'] = (current) => { | |||||
| return current && current > dayjs().endOf('day'); | |||||
| }; | |||||
| return ( | |||||
| <> | |||||
| <Modal | |||||
| title={t('overview')} | |||||
| open={visible} | |||||
| onCancel={hideModal} | |||||
| width={'100vw'} | |||||
| > | |||||
| <Flex vertical gap={'middle'}> | |||||
| <Card title={dialog.name}> | |||||
| <Flex gap={8} vertical> | |||||
| {t('publicUrl')} | |||||
| <Paragraph copyable className={styles.linkText}> | |||||
| This is a copyable text. | |||||
| </Paragraph> | |||||
| </Flex> | |||||
| <Space size={'middle'}> | |||||
| <Button>{t('preview')}</Button> | |||||
| <Button>{t('embedded')}</Button> | |||||
| </Space> | |||||
| </Card> | |||||
| <Card title={t('backendServiceApi')}> | |||||
| <Flex gap={8} vertical> | |||||
| {t('serviceApiEndpoint')} | |||||
| <Paragraph copyable className={styles.linkText}> | |||||
| This is a copyable text. | |||||
| </Paragraph> | |||||
| </Flex> | |||||
| <Space size={'middle'}> | |||||
| <Button onClick={showApiKeyModal}>{t('apiKey')}</Button> | |||||
| <Button>{t('apiReference')}</Button> | |||||
| </Space> | |||||
| </Card> | |||||
| <Space> | |||||
| <b>{t('dateRange')}</b> | |||||
| <RangePicker | |||||
| disabledDate={disabledDate} | |||||
| value={pickerValue} | |||||
| onChange={setPickerValue} | |||||
| allowClear={false} | |||||
| /> | |||||
| </Space> | |||||
| <div className={styles.chartWrapper}> | |||||
| {Object.keys(chartList).map((x) => ( | |||||
| <div key={x} className={styles.chartItem}> | |||||
| <b className={styles.chartLabel}>{t(camelCase(x))}</b> | |||||
| <LineChart data={chartList[x as keyof IStats]}></LineChart> | |||||
| </div> | |||||
| ))} | |||||
| </div> | |||||
| </Flex> | |||||
| <ChatApiKeyModal | |||||
| visible={apiKeyVisible} | |||||
| hideModal={hideApiKeyModal} | |||||
| dialogId={dialog.id} | |||||
| ></ChatApiKeyModal> | |||||
| </Modal> | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| export default ChatOverviewModal; |
| import { fileIconMap } from '@/constants/common'; | import { fileIconMap } from '@/constants/common'; | ||||
| import { | import { | ||||
| useCompleteConversation, | useCompleteConversation, | ||||
| useCreateToken, | |||||
| useFetchConversation, | useFetchConversation, | ||||
| useFetchConversationList, | useFetchConversationList, | ||||
| useFetchDialog, | useFetchDialog, | ||||
| useFetchDialogList, | useFetchDialogList, | ||||
| useFetchStats, | |||||
| useListToken, | |||||
| useRemoveConversation, | useRemoveConversation, | ||||
| useRemoveDialog, | useRemoveDialog, | ||||
| useRemoveToken, | |||||
| useSelectConversationList, | useSelectConversationList, | ||||
| useSelectDialogList, | useSelectDialogList, | ||||
| useSelectTokenList, | |||||
| useSetDialog, | useSetDialog, | ||||
| useUpdateConversation, | useUpdateConversation, | ||||
| } from '@/hooks/chatHooks'; | } from '@/hooks/chatHooks'; | ||||
| import { useSetModalState, useShowDeleteConfirm } from '@/hooks/commonHooks'; | import { useSetModalState, useShowDeleteConfirm } from '@/hooks/commonHooks'; | ||||
| import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; | import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; | ||||
| import { IConversation, IDialog } from '@/interfaces/database/chat'; | |||||
| import { IConversation, IDialog, IStats } from '@/interfaces/database/chat'; | |||||
| import { IChunk } from '@/interfaces/database/knowledge'; | import { IChunk } from '@/interfaces/database/knowledge'; | ||||
| import { getFileExtension } from '@/utils'; | import { getFileExtension } from '@/utils'; | ||||
| import dayjs, { Dayjs } from 'dayjs'; | |||||
| import omit from 'lodash/omit'; | import omit from 'lodash/omit'; | ||||
| import { | import { | ||||
| ChangeEventHandler, | ChangeEventHandler, | ||||
| return dialogId === '' && conversationId === ''; | return dialogId === '' && conversationId === ''; | ||||
| }; | }; | ||||
| //#endregion | //#endregion | ||||
| //#region API provided for external calls | |||||
| type RangeValue = [Dayjs | null, Dayjs | null] | null; | |||||
| export const useFetchStatsOnMount = (visible: boolean) => { | |||||
| const fetchStats = useFetchStats(); | |||||
| const [pickerValue, setPickerValue] = useState<RangeValue>([ | |||||
| dayjs(), | |||||
| dayjs().subtract(7, 'day'), | |||||
| ]); | |||||
| useEffect(() => { | |||||
| if (visible && Array.isArray(pickerValue) && pickerValue[0]) { | |||||
| fetchStats({ fromDate: pickerValue[0], toDate: pickerValue[1] }); | |||||
| } | |||||
| }, [fetchStats, pickerValue, visible]); | |||||
| return { | |||||
| pickerValue, | |||||
| setPickerValue, | |||||
| }; | |||||
| }; | |||||
| export const useOperateApiKey = (visible: boolean, dialogId: string) => { | |||||
| const removeToken = useRemoveToken(); | |||||
| const createToken = useCreateToken(dialogId); | |||||
| const listToken = useListToken(); | |||||
| const tokenList = useSelectTokenList(); | |||||
| const creatingLoading = useOneNamespaceEffectsLoading('chatModel', [ | |||||
| 'createToken', | |||||
| ]); | |||||
| const listLoading = useOneNamespaceEffectsLoading('chatModel', ['list']); | |||||
| const showDeleteConfirm = useShowDeleteConfirm(); | |||||
| const onRemoveToken = (token: string, tenantId: string) => { | |||||
| showDeleteConfirm({ | |||||
| onOk: () => removeToken({ dialogId, tokens: [token], tenantId }), | |||||
| }); | |||||
| }; | |||||
| useEffect(() => { | |||||
| if (visible && dialogId) { | |||||
| listToken(dialogId); | |||||
| } | |||||
| }, [listToken, dialogId, visible]); | |||||
| return { | |||||
| removeToken: onRemoveToken, | |||||
| createToken, | |||||
| tokenList, | |||||
| creatingLoading, | |||||
| listLoading, | |||||
| }; | |||||
| }; | |||||
| type ChartStatsType = { | |||||
| [k in keyof IStats]: Array<{ xAxis: string; yAxis: number }>; | |||||
| }; | |||||
| export const useSelectChartStatsList = (): ChartStatsType => { | |||||
| // const stats: IStats = useSelectStats(); | |||||
| const stats = { | |||||
| pv: [ | |||||
| ['2024-06-01', 1], | |||||
| ['2024-07-24', 3], | |||||
| ['2024-09-01', 10], | |||||
| ], | |||||
| uv: [ | |||||
| ['2024-02-01', 0], | |||||
| ['2024-03-01', 99], | |||||
| ['2024-05-01', 3], | |||||
| ], | |||||
| speed: [ | |||||
| ['2024-09-01', 2], | |||||
| ['2024-09-01', 3], | |||||
| ], | |||||
| tokens: [ | |||||
| ['2024-09-01', 1], | |||||
| ['2024-09-01', 3], | |||||
| ], | |||||
| round: [ | |||||
| ['2024-09-01', 0], | |||||
| ['2024-09-01', 3], | |||||
| ], | |||||
| thumb_up: [ | |||||
| ['2024-09-01', 3], | |||||
| ['2024-09-01', 9], | |||||
| ], | |||||
| }; | |||||
| return Object.keys(stats).reduce((pre, cur) => { | |||||
| const item = stats[cur as keyof IStats]; | |||||
| if (item.length > 0) { | |||||
| pre[cur as keyof IStats] = item.map((x) => ({ | |||||
| xAxis: x[0] as string, | |||||
| yAxis: x[1] as number, | |||||
| })); | |||||
| } | |||||
| return pre; | |||||
| }, {} as ChartStatsType); | |||||
| }; | |||||
| //#endregion |
| useSelectFirstDialogOnMount, | useSelectFirstDialogOnMount, | ||||
| } from './hooks'; | } from './hooks'; | ||||
| import { useTranslate } from '@/hooks/commonHooks'; | |||||
| import { useSetModalState, useTranslate } from '@/hooks/commonHooks'; | |||||
| import { useSetSelectedRecord } from '@/hooks/logicHooks'; | |||||
| import { IDialog } from '@/interfaces/database/chat'; | |||||
| import ChatOverviewModal from './chat-overview-modal'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| const Chat = () => { | const Chat = () => { | ||||
| const dialogLoading = useSelectDialogListLoading(); | const dialogLoading = useSelectDialogListLoading(); | ||||
| const conversationLoading = useSelectConversationListLoading(); | const conversationLoading = useSelectConversationListLoading(); | ||||
| const { t } = useTranslate('chat'); | const { t } = useTranslate('chat'); | ||||
| const { | |||||
| visible: overviewVisible, | |||||
| hideModal: hideOverviewModal, | |||||
| showModal: showOverviewModal, | |||||
| } = useSetModalState(); | |||||
| const { currentRecord, setRecord } = useSetSelectedRecord<IDialog>(); | |||||
| useFetchDialogOnMount(dialogId, true); | useFetchDialogOnMount(dialogId, true); | ||||
| onRemoveDialog([dialogId]); | onRemoveDialog([dialogId]); | ||||
| }; | }; | ||||
| const handleShowOverviewModal = | |||||
| (dialog: IDialog): any => | |||||
| (info: any) => { | |||||
| info?.domEvent?.preventDefault(); | |||||
| info?.domEvent?.stopPropagation(); | |||||
| setRecord(dialog); | |||||
| showOverviewModal(); | |||||
| }; | |||||
| const handleRemoveConversation = | const handleRemoveConversation = | ||||
| (conversationId: string): MenuItemProps['onClick'] => | (conversationId: string): MenuItemProps['onClick'] => | ||||
| ({ domEvent }) => { | ({ domEvent }) => { | ||||
| }, | }, | ||||
| ]; | ]; | ||||
| const buildAppItems = (dialogId: string) => { | |||||
| const buildAppItems = (dialog: IDialog) => { | |||||
| const dialogId = dialog.id; | |||||
| const appItems: MenuProps['items'] = [ | const appItems: MenuProps['items'] = [ | ||||
| { | { | ||||
| key: '1', | key: '1', | ||||
| </Space> | </Space> | ||||
| ), | ), | ||||
| }, | }, | ||||
| { type: 'divider' }, | |||||
| // { | |||||
| // key: '3', | |||||
| // onClick: handleShowOverviewModal(dialog), | |||||
| // label: ( | |||||
| // <Space> | |||||
| // <ProfileOutlined /> | |||||
| // {t('overview')} | |||||
| // </Space> | |||||
| // ), | |||||
| // }, | |||||
| ]; | ]; | ||||
| return appItems; | return appItems; | ||||
| </Space> | </Space> | ||||
| {activated === x.id && ( | {activated === x.id && ( | ||||
| <section> | <section> | ||||
| <Dropdown menu={{ items: buildAppItems(x.id) }}> | |||||
| <Dropdown menu={{ items: buildAppItems(x) }}> | |||||
| <ChatAppCube | <ChatAppCube | ||||
| className={styles.cubeIcon} | className={styles.cubeIcon} | ||||
| ></ChatAppCube> | ></ChatAppCube> | ||||
| initialName={initialConversationName} | initialName={initialConversationName} | ||||
| loading={conversationRenameLoading} | loading={conversationRenameLoading} | ||||
| ></RenameModal> | ></RenameModal> | ||||
| <ChatOverviewModal | |||||
| visible={overviewVisible} | |||||
| hideModal={hideOverviewModal} | |||||
| dialog={currentRecord} | |||||
| ></ChatOverviewModal> | |||||
| </Flex> | </Flex> | ||||
| ); | ); | ||||
| }; | }; |
| import { IConversation, IDialog, Message } from '@/interfaces/database/chat'; | |||||
| import { | |||||
| IConversation, | |||||
| IDialog, | |||||
| IStats, | |||||
| IToken, | |||||
| Message, | |||||
| } from '@/interfaces/database/chat'; | |||||
| import i18n from '@/locales/config'; | import i18n from '@/locales/config'; | ||||
| import chatService from '@/services/chatService'; | import chatService from '@/services/chatService'; | ||||
| import { message } from 'antd'; | import { message } from 'antd'; | ||||
| import omit from 'lodash/omit'; | |||||
| import { DvaModel } from 'umi'; | import { DvaModel } from 'umi'; | ||||
| import { v4 as uuid } from 'uuid'; | import { v4 as uuid } from 'uuid'; | ||||
| import { IClientConversation, IMessage } from './interface'; | import { IClientConversation, IMessage } from './interface'; | ||||
| currentDialog: IDialog; | currentDialog: IDialog; | ||||
| conversationList: IConversation[]; | conversationList: IConversation[]; | ||||
| currentConversation: IClientConversation; | currentConversation: IClientConversation; | ||||
| tokenList: IToken[]; | |||||
| stats: IStats; | |||||
| } | } | ||||
| const model: DvaModel<ChatModelState> = { | const model: DvaModel<ChatModelState> = { | ||||
| currentDialog: <IDialog>{}, | currentDialog: <IDialog>{}, | ||||
| conversationList: [], | conversationList: [], | ||||
| currentConversation: {} as IClientConversation, | currentConversation: {} as IClientConversation, | ||||
| tokenList: [], | |||||
| stats: {} as IStats, | |||||
| }, | }, | ||||
| reducers: { | reducers: { | ||||
| save(state, action) { | save(state, action) { | ||||
| currentConversation: { ...payload, message: messageList }, | currentConversation: { ...payload, message: messageList }, | ||||
| }; | }; | ||||
| }, | }, | ||||
| setTokenList(state, { payload }) { | |||||
| return { | |||||
| ...state, | |||||
| tokenList: payload, | |||||
| }; | |||||
| }, | |||||
| setStats(state, { payload }) { | |||||
| return { | |||||
| ...state, | |||||
| stats: payload, | |||||
| }; | |||||
| }, | |||||
| }, | }, | ||||
| effects: { | effects: { | ||||
| } | } | ||||
| return data.retcode; | return data.retcode; | ||||
| }, | }, | ||||
| *createToken({ payload }, { call, put }) { | |||||
| const { data } = yield call(chatService.createToken, payload); | |||||
| if (data.retcode === 0) { | |||||
| yield put({ | |||||
| type: 'listToken', | |||||
| payload: payload, | |||||
| }); | |||||
| message.success(i18n.t('message.created')); | |||||
| } | |||||
| return data.retcode; | |||||
| }, | |||||
| *listToken({ payload }, { call, put }) { | |||||
| const { data } = yield call(chatService.listToken, payload); | |||||
| if (data.retcode === 0) { | |||||
| yield put({ | |||||
| type: 'setTokenList', | |||||
| payload: data.data, | |||||
| }); | |||||
| } | |||||
| return data.retcode; | |||||
| }, | |||||
| *removeToken({ payload }, { call, put }) { | |||||
| const { data } = yield call( | |||||
| chatService.removeToken, | |||||
| omit(payload, ['dialogId']), | |||||
| ); | |||||
| if (data.retcode === 0) { | |||||
| yield put({ | |||||
| type: 'listToken', | |||||
| payload: { dialog_id: payload.dialogId }, | |||||
| }); | |||||
| } | |||||
| return data.retcode; | |||||
| }, | |||||
| *getStats({ payload }, { call, put }) { | |||||
| const { data } = yield call(chatService.getStats, payload); | |||||
| if (data.retcode === 0) { | |||||
| yield put({ | |||||
| type: 'setStats', | |||||
| payload: data.data, | |||||
| }); | |||||
| } | |||||
| return data.retcode; | |||||
| }, | |||||
| *createExternalConversation({ payload }, { call, put }) { | |||||
| const { data } = yield call( | |||||
| chatService.createExternalConversation, | |||||
| payload, | |||||
| ); | |||||
| if (data.retcode === 0) { | |||||
| yield put({ | |||||
| type: 'getExternalConversation', | |||||
| payload: { conversation_id: payload.conversationId }, | |||||
| }); | |||||
| } | |||||
| return data.retcode; | |||||
| }, | |||||
| *getExternalConversation({ payload }, { call }) { | |||||
| const { data } = yield call( | |||||
| chatService.getExternalConversation, | |||||
| null, | |||||
| payload, | |||||
| ); | |||||
| return data.retcode; | |||||
| }, | |||||
| *completeExternalConversation({ payload }, { call }) { | |||||
| const { data } = yield call( | |||||
| chatService.completeExternalConversation, | |||||
| payload, | |||||
| ); | |||||
| return data.retcode; | |||||
| }, | |||||
| }, | }, | ||||
| }; | }; | ||||
| completeConversation, | completeConversation, | ||||
| listConversation, | listConversation, | ||||
| removeConversation, | removeConversation, | ||||
| createToken, | |||||
| listToken, | |||||
| removeToken, | |||||
| getStats, | |||||
| createExternalConversation, | |||||
| getExternalConversation, | |||||
| completeExternalConversation, | |||||
| } = api; | } = api; | ||||
| const methods = { | const methods = { | ||||
| url: removeConversation, | url: removeConversation, | ||||
| method: 'post', | method: 'post', | ||||
| }, | }, | ||||
| createToken: { | |||||
| url: createToken, | |||||
| method: 'post', | |||||
| }, | |||||
| listToken: { | |||||
| url: listToken, | |||||
| method: 'get', | |||||
| }, | |||||
| removeToken: { | |||||
| url: removeToken, | |||||
| method: 'post', | |||||
| }, | |||||
| getStats: { | |||||
| url: getStats, | |||||
| method: 'get', | |||||
| }, | |||||
| createExternalConversation: { | |||||
| url: createExternalConversation, | |||||
| method: 'post', | |||||
| }, | |||||
| getExternalConversation: { | |||||
| url: getExternalConversation, | |||||
| method: 'get', | |||||
| }, | |||||
| completeExternalConversation: { | |||||
| url: completeExternalConversation, | |||||
| method: 'post', | |||||
| }, | |||||
| } as const; | } as const; | ||||
| const chatService = registerServer<keyof typeof methods>(methods, request); | const chatService = registerServer<keyof typeof methods>(methods, request); |
| export { api_host }; | export { api_host }; | ||||
| export default { | export default { | ||||
| // 用户 | |||||
| // user | |||||
| login: `${api_host}/user/login`, | login: `${api_host}/user/login`, | ||||
| logout: `${api_host}/user/logout`, | logout: `${api_host}/user/logout`, | ||||
| register: `${api_host}/user/register`, | register: `${api_host}/user/register`, | ||||
| tenant_info: `${api_host}/user/tenant_info`, | tenant_info: `${api_host}/user/tenant_info`, | ||||
| set_tenant_info: `${api_host}/user/set_tenant_info`, | set_tenant_info: `${api_host}/user/set_tenant_info`, | ||||
| // 模型管理 | |||||
| // llm model | |||||
| factories_list: `${api_host}/llm/factories`, | factories_list: `${api_host}/llm/factories`, | ||||
| llm_list: `${api_host}/llm/list`, | llm_list: `${api_host}/llm/list`, | ||||
| my_llm: `${api_host}/llm/my_llms`, | my_llm: `${api_host}/llm/my_llms`, | ||||
| set_api_key: `${api_host}/llm/set_api_key`, | set_api_key: `${api_host}/llm/set_api_key`, | ||||
| add_llm: `${api_host}/llm/add_llm`, | add_llm: `${api_host}/llm/add_llm`, | ||||
| //知识库管理 | |||||
| // knowledge base | |||||
| kb_list: `${api_host}/kb/list`, | kb_list: `${api_host}/kb/list`, | ||||
| create_kb: `${api_host}/kb/create`, | create_kb: `${api_host}/kb/create`, | ||||
| update_kb: `${api_host}/kb/update`, | update_kb: `${api_host}/kb/update`, | ||||
| rm_kb: `${api_host}/kb/rm`, | rm_kb: `${api_host}/kb/rm`, | ||||
| get_kb_detail: `${api_host}/kb/detail`, | get_kb_detail: `${api_host}/kb/detail`, | ||||
| // chunk管理 | |||||
| // chunk | |||||
| chunk_list: `${api_host}/chunk/list`, | chunk_list: `${api_host}/chunk/list`, | ||||
| create_chunk: `${api_host}/chunk/create`, | create_chunk: `${api_host}/chunk/create`, | ||||
| set_chunk: `${api_host}/chunk/set`, | set_chunk: `${api_host}/chunk/set`, | ||||
| rm_chunk: `${api_host}/chunk/rm`, | rm_chunk: `${api_host}/chunk/rm`, | ||||
| retrieval_test: `${api_host}/chunk/retrieval_test`, | retrieval_test: `${api_host}/chunk/retrieval_test`, | ||||
| // 文件管理 | |||||
| // document | |||||
| upload: `${api_host}/document/upload`, | upload: `${api_host}/document/upload`, | ||||
| get_document_list: `${api_host}/document/list`, | get_document_list: `${api_host}/document/list`, | ||||
| document_change_status: `${api_host}/document/change_status`, | document_change_status: `${api_host}/document/change_status`, | ||||
| get_document_file: `${api_host}/document/get`, | get_document_file: `${api_host}/document/get`, | ||||
| document_upload: `${api_host}/document/upload`, | document_upload: `${api_host}/document/upload`, | ||||
| // chat | |||||
| setDialog: `${api_host}/dialog/set`, | setDialog: `${api_host}/dialog/set`, | ||||
| getDialog: `${api_host}/dialog/get`, | getDialog: `${api_host}/dialog/get`, | ||||
| removeDialog: `${api_host}/dialog/rm`, | removeDialog: `${api_host}/dialog/rm`, | ||||
| listDialog: `${api_host}/dialog/list`, | listDialog: `${api_host}/dialog/list`, | ||||
| setConversation: `${api_host}/conversation/set`, | setConversation: `${api_host}/conversation/set`, | ||||
| getConversation: `${api_host}/conversation/get`, | getConversation: `${api_host}/conversation/get`, | ||||
| listConversation: `${api_host}/conversation/list`, | listConversation: `${api_host}/conversation/list`, | ||||
| removeConversation: `${api_host}/conversation/rm`, | removeConversation: `${api_host}/conversation/rm`, | ||||
| completeConversation: `${api_host}/conversation/completion`, | completeConversation: `${api_host}/conversation/completion`, | ||||
| // chat for external | |||||
| createToken: `${api_host}/api/new_token`, | |||||
| listToken: `${api_host}/api/token_list`, | |||||
| removeToken: `${api_host}/api/rm`, | |||||
| getStats: `${api_host}/api/stats`, | |||||
| createExternalConversation: `${api_host}/api/new_conversation`, | |||||
| getExternalConversation: `${api_host}/api/conversation`, | |||||
| completeExternalConversation: `${api_host}/api/completion`, | |||||
| }; | }; |
| import isObject from 'lodash/isObject'; | |||||
| import snakeCase from 'lodash/snakeCase'; | |||||
| export const isFormData = (data: unknown): data is FormData => { | |||||
| return data instanceof FormData; | |||||
| }; | |||||
| export const convertTheKeysOfTheObjectToSnake = (data: unknown) => { | |||||
| if (isObject(data) && !isFormData(data)) { | |||||
| return Object.keys(data).reduce<Record<string, any>>((pre, cur) => { | |||||
| const value = (data as Record<string, any>)[cur]; | |||||
| pre[isFormData(value) ? cur : snakeCase(cur)] = value; | |||||
| return pre; | |||||
| }, {}); | |||||
| } | |||||
| return data; | |||||
| }; |
| import moment from 'moment'; | |||||
| import dayjs from 'dayjs'; | |||||
| export function today() { | export function today() { | ||||
| return formatDate(moment()); | |||||
| return formatDate(dayjs()); | |||||
| } | } | ||||
| export function lastDay() { | export function lastDay() { | ||||
| return formatDate(moment().subtract(1, 'days')); | |||||
| return formatDate(dayjs().subtract(1, 'days')); | |||||
| } | } | ||||
| export function lastWeek() { | export function lastWeek() { | ||||
| return formatDate(moment().subtract(1, 'weeks')); | |||||
| return formatDate(dayjs().subtract(1, 'weeks')); | |||||
| } | } | ||||
| export function formatDate(date: any) { | export function formatDate(date: any) { | ||||
| if (!date) { | if (!date) { | ||||
| return ''; | return ''; | ||||
| } | } | ||||
| return moment(date).format('DD/MM/YYYY'); | |||||
| return dayjs(date).format('DD/MM/YYYY'); | |||||
| } | } |
| ) => { | ) => { | ||||
| const server: Service<T> = {} as Service<T>; | const server: Service<T> = {} as Service<T>; | ||||
| for (let key in opt) { | for (let key in opt) { | ||||
| server[key] = (params) => { | |||||
| server[key] = (params: any, urlAppendix?: string) => { | |||||
| let url = opt[key].url; | |||||
| if (urlAppendix) { | |||||
| url = url + '/' + urlAppendix; | |||||
| } | |||||
| if (opt[key].method === 'post' || opt[key].method === 'POST') { | if (opt[key].method === 'post' || opt[key].method === 'POST') { | ||||
| return request(opt[key].url, { | |||||
| return request(url, { | |||||
| method: opt[key].method, | method: opt[key].method, | ||||
| data: params, | data: params, | ||||
| }); | }); | ||||
| } | } | ||||
| if (opt[key].method === 'get' || opt[key].method === 'GET') { | if (opt[key].method === 'get' || opt[key].method === 'GET') { | ||||
| return request.get(opt[key].url, { | |||||
| return request.get(url, { | |||||
| params, | params, | ||||
| }); | }); | ||||
| } | } |
| import { message, notification } from 'antd'; | import { message, notification } from 'antd'; | ||||
| import { history } from 'umi'; | import { history } from 'umi'; | ||||
| import { RequestMethod, extend } from 'umi-request'; | import { RequestMethod, extend } from 'umi-request'; | ||||
| import { convertTheKeysOfTheObjectToSnake } from './commonUtil'; | |||||
| const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动中断请求。errorHandler 抛出的error message | const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动中断请求。errorHandler 抛出的error message | ||||
| request.interceptors.request.use((url: string, options: any) => { | request.interceptors.request.use((url: string, options: any) => { | ||||
| const authorization = authorizationUtil.getAuthorization(); | const authorization = authorizationUtil.getAuthorization(); | ||||
| const data = convertTheKeysOfTheObjectToSnake(options.data); | |||||
| const params = convertTheKeysOfTheObjectToSnake(options.params); | |||||
| return { | return { | ||||
| url, | url, | ||||
| options: { | options: { | ||||
| ...options, | ...options, | ||||
| // data, | |||||
| // params, | |||||
| headers: { | headers: { | ||||
| ...(options.skipToken ? undefined : { [Authorization]: authorization }), | ...(options.skipToken ? undefined : { [Authorization]: authorization }), | ||||
| ...options.headers, | ...options.headers, |