### 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
| @@ -13,19 +13,21 @@ | |||
| "antd": "^5.12.7", | |||
| "axios": "^1.6.3", | |||
| "classnames": "^2.5.1", | |||
| "dayjs": "^1.11.10", | |||
| "i18next": "^23.7.16", | |||
| "js-base64": "^3.7.5", | |||
| "jsencrypt": "^3.3.2", | |||
| "lodash": "^4.17.21", | |||
| "moment": "^2.30.1", | |||
| "rc-tween-one": "^3.0.6", | |||
| "react-chat-elements": "^12.0.13", | |||
| "react-copy-to-clipboard": "^5.1.0", | |||
| "react-i18next": "^14.0.0", | |||
| "react-infinite-scroll-component": "^6.1.0", | |||
| "react-markdown": "^9.0.1", | |||
| "react-pdf-highlighter": "^6.1.0", | |||
| "react-string-replace": "^1.1.1", | |||
| "react-syntax-highlighter": "^15.5.0", | |||
| "recharts": "^2.12.4", | |||
| "remark-gfm": "^4.0.0", | |||
| "umi": "^4.0.90", | |||
| "umi-request": "^1.4.0", | |||
| @@ -36,6 +38,7 @@ | |||
| "@react-dev-inspector/umi4-plugin": "^2.0.1", | |||
| "@types/lodash": "^4.14.202", | |||
| "@types/react": "^18.0.33", | |||
| "@types/react-copy-to-clipboard": "^5.0.7", | |||
| "@types/react-dom": "^18.0.11", | |||
| "@types/react-syntax-highlighter": "^15.5.11", | |||
| "@types/uuid": "^9.0.8", | |||
| @@ -2676,6 +2679,60 @@ | |||
| "@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": { | |||
| "version": "4.1.12", | |||
| "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.12.tgz", | |||
| @@ -2884,6 +2941,15 @@ | |||
| "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": { | |||
| "version": "18.2.18", | |||
| "resolved": "https://registry.npmmirror.com/@types/react-dom/-/react-dom-18.2.18.tgz", | |||
| @@ -5832,6 +5898,14 @@ | |||
| "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": { | |||
| "version": "2.0.2", | |||
| "resolved": "https://registry.npmmirror.com/coa/-/coa-2.0.2.tgz", | |||
| @@ -6640,11 +6714,132 @@ | |||
| "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-1.2.4.tgz", | |||
| "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": { | |||
| "version": "1.0.6", | |||
| "resolved": "https://registry.npmmirror.com/d3-polygon/-/d3-polygon-1.0.6.tgz", | |||
| "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": { | |||
| "version": "4.0.1", | |||
| "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", | |||
| @@ -6705,6 +6900,11 @@ | |||
| "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": { | |||
| "version": "1.0.2", | |||
| "resolved": "https://registry.npmmirror.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", | |||
| @@ -7032,6 +7232,15 @@ | |||
| "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": { | |||
| "version": "1.4.1", | |||
| "resolved": "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-1.4.1.tgz", | |||
| @@ -8151,6 +8360,11 @@ | |||
| "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": { | |||
| "version": "3.3.0", | |||
| "resolved": "https://registry.npmmirror.com/events/-/events-3.3.0.tgz", | |||
| @@ -8356,6 +8570,14 @@ | |||
| "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", | |||
| "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": { | |||
| "version": "3.2.12", | |||
| "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.2.12.tgz", | |||
| @@ -9693,6 +9915,14 @@ | |||
| "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": { | |||
| "version": "0.12.2", | |||
| "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz", | |||
| @@ -11925,6 +12155,7 @@ | |||
| "version": "2.30.1", | |||
| "resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz", | |||
| "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", | |||
| "devOptional": true, | |||
| "engines": { | |||
| "node": "*" | |||
| } | |||
| @@ -14356,6 +14587,18 @@ | |||
| "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": { | |||
| "version": "2.0.1", | |||
| "resolved": "https://registry.npmmirror.com/react-dev-inspector/-/react-dev-inspector-2.0.1.tgz", | |||
| @@ -14934,6 +15177,20 @@ | |||
| "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": { | |||
| "version": "3.0.0", | |||
| "resolved": "https://registry.npmmirror.com/react-spinkit/-/react-spinkit-3.0.0.tgz", | |||
| @@ -14968,6 +15225,21 @@ | |||
| "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": { | |||
| "version": "1.2.3", | |||
| "resolved": "https://registry.npmmirror.com/reactcss/-/reactcss-1.2.3.tgz", | |||
| @@ -15145,6 +15417,41 @@ | |||
| "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": { | |||
| "version": "2.2.3", | |||
| "resolved": "https://registry.npmmirror.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz", | |||
| @@ -17000,9 +17307,7 @@ | |||
| "node_modules/tiny-invariant": { | |||
| "version": "1.3.1", | |||
| "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": { | |||
| "version": "1.0.3", | |||
| @@ -18221,6 +18526,38 @@ | |||
| "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": { | |||
| "version": "4.3.1", | |||
| "resolved": "https://registry.npmmirror.com/vite/-/vite-4.3.1.tgz", | |||
| @@ -17,19 +17,21 @@ | |||
| "antd": "^5.12.7", | |||
| "axios": "^1.6.3", | |||
| "classnames": "^2.5.1", | |||
| "dayjs": "^1.11.10", | |||
| "i18next": "^23.7.16", | |||
| "js-base64": "^3.7.5", | |||
| "jsencrypt": "^3.3.2", | |||
| "lodash": "^4.17.21", | |||
| "moment": "^2.30.1", | |||
| "rc-tween-one": "^3.0.6", | |||
| "react-chat-elements": "^12.0.13", | |||
| "react-copy-to-clipboard": "^5.1.0", | |||
| "react-i18next": "^14.0.0", | |||
| "react-infinite-scroll-component": "^6.1.0", | |||
| "react-markdown": "^9.0.1", | |||
| "react-pdf-highlighter": "^6.1.0", | |||
| "react-string-replace": "^1.1.1", | |||
| "react-syntax-highlighter": "^15.5.0", | |||
| "recharts": "^2.12.4", | |||
| "remark-gfm": "^4.0.0", | |||
| "umi": "^4.0.90", | |||
| "umi-request": "^1.4.0", | |||
| @@ -40,6 +42,7 @@ | |||
| "@react-dev-inspector/umi4-plugin": "^2.0.1", | |||
| "@types/lodash": "^4.14.202", | |||
| "@types/react": "^18.0.33", | |||
| "@types/react-copy-to-clipboard": "^5.0.7", | |||
| "@types/react-dom": "^18.0.11", | |||
| "@types/react-syntax-highlighter": "^15.5.11", | |||
| "@types/uuid": "^9.0.8", | |||
| @@ -6,6 +6,21 @@ import zh_HK from 'antd/locale/zh_HK'; | |||
| import React, { ReactNode, useEffect, useState } from 'react'; | |||
| 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 = { | |||
| en: enUS, | |||
| zh: zhCN, | |||
| @@ -0,0 +1,27 @@ | |||
| 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; | |||
| @@ -0,0 +1,88 @@ | |||
| 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; | |||
| @@ -1,4 +1,9 @@ | |||
| import { IConversation, IDialog } from '@/interfaces/database/chat'; | |||
| import { | |||
| IConversation, | |||
| IDialog, | |||
| IStats, | |||
| IToken, | |||
| } from '@/interfaces/database/chat'; | |||
| import { useCallback } from 'react'; | |||
| import { useDispatch, useSelector } from 'umi'; | |||
| @@ -164,3 +169,82 @@ export const useCompleteConversation = () => { | |||
| 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 | |||
| @@ -91,3 +91,21 @@ export interface Docagg { | |||
| // term_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][]; | |||
| } | |||
| @@ -20,6 +20,8 @@ export default { | |||
| language: 'Language', | |||
| languageMessage: 'Please input your language!', | |||
| languagePlaceholder: 'select your language', | |||
| copy: 'Copy', | |||
| copied: 'Copied', | |||
| }, | |||
| login: { | |||
| login: 'Sign in', | |||
| @@ -335,6 +337,24 @@ export default { | |||
| 'This sets the maximum length of the model’s output, measured in the number of tokens (words or pieces of words).', | |||
| quote: 'Show Quote', | |||
| 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: { | |||
| profile: 'Profile', | |||
| @@ -15,11 +15,13 @@ export default { | |||
| edit: '編輯', | |||
| upload: '上傳', | |||
| english: '英語', | |||
| chinese: '中文簡體', | |||
| traditionalChinese: '中文繁體', | |||
| chinese: '簡體中文', | |||
| traditionalChinese: '繁體中文', | |||
| language: '語言', | |||
| languageMessage: '請輸入語言', | |||
| languagePlaceholder: '請選擇語言', | |||
| copy: '複製', | |||
| copied: '複製成功', | |||
| }, | |||
| login: { | |||
| login: '登入', | |||
| @@ -269,7 +271,7 @@ export default { | |||
| systemMessage: '請輸入', | |||
| systemTip: | |||
| '當LLM回答問題時,你需要LLM遵循的說明,比如角色設計、答案長度和答案語言等。', | |||
| topN: 'top n', | |||
| topN: 'Top N', | |||
| topNTip: `並非所有相似度得分高於“相似度閾值”的塊都會被提供給法學碩士。LLM 只能看到這些“Top N”塊。`, | |||
| variable: '變量', | |||
| variableTip: `如果您使用对话 API,变量可能会帮助您使用不同的策略与客户聊天。 | |||
| @@ -310,6 +312,24 @@ export default { | |||
| '這設置了模型輸出的最大長度,以標記(單詞或單詞片段)的數量來衡量。', | |||
| quote: '顯示引文', | |||
| 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: { | |||
| profile: '概述', | |||
| @@ -15,11 +15,13 @@ export default { | |||
| edit: '编辑', | |||
| upload: '上传', | |||
| english: '英文', | |||
| chinese: '中文简体', | |||
| traditionalChinese: '中文繁体', | |||
| chinese: '简体中文', | |||
| traditionalChinese: '繁体中文', | |||
| language: '语言', | |||
| languageMessage: '请输入语言', | |||
| languagePlaceholder: '请选择语言', | |||
| copy: '复制', | |||
| copied: '复制成功', | |||
| }, | |||
| login: { | |||
| login: '登录', | |||
| @@ -326,6 +328,24 @@ export default { | |||
| '这设置了模型输出的最大长度,以标记(单词或单词片段)的数量来衡量。', | |||
| quote: '显示引文', | |||
| 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: { | |||
| profile: '概要', | |||
| @@ -26,6 +26,7 @@ import ParsingActionCell from './parsing-action-cell'; | |||
| import ParsingStatusCell from './parsing-status-cell'; | |||
| import RenameModal from './rename-modal'; | |||
| import { formatDate } from '@/utils/date'; | |||
| import styles from './index.less'; | |||
| const KnowledgeFile = () => { | |||
| @@ -94,6 +95,9 @@ const KnowledgeFile = () => { | |||
| title: t('uploadDate'), | |||
| dataIndex: 'create_date', | |||
| key: 'create_date', | |||
| render(value) { | |||
| return formatDate(value); | |||
| }, | |||
| }, | |||
| { | |||
| title: t('chunkMethod'), | |||
| @@ -0,0 +1,70 @@ | |||
| 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; | |||
| @@ -1,6 +1,6 @@ | |||
| import { useFetchKnowledgeList } from '@/hooks/knowledgeHook'; | |||
| 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 { ISegmentedContentProps } from '../interface'; | |||
| @@ -83,6 +83,15 @@ const AssistantSetting = ({ show }: ISegmentedContentProps) => { | |||
| > | |||
| <Input.TextArea autoSize={{ minRows: 5 }} /> | |||
| </Form.Item> | |||
| <Form.Item | |||
| label={t('quote')} | |||
| valuePropName="checked" | |||
| name={['prompt_config', 'quote']} | |||
| tooltip={t('quoteTip')} | |||
| initialValue={true} | |||
| > | |||
| <Switch /> | |||
| </Form.Item> | |||
| <Form.Item | |||
| label={t('knowledgeBases')} | |||
| name="kb_ids" | |||
| @@ -172,15 +172,7 @@ const PromptEngine = ( | |||
| > | |||
| <Slider max={30} /> | |||
| </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)}> | |||
| <Row align={'middle'} justify="end"> | |||
| <Col span={7} className={styles.variableAlign}> | |||
| @@ -0,0 +1,21 @@ | |||
| .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; | |||
| } | |||
| @@ -0,0 +1,97 @@ | |||
| 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; | |||
| @@ -2,22 +2,28 @@ import { MessageType } from '@/constants/chat'; | |||
| import { fileIconMap } from '@/constants/common'; | |||
| import { | |||
| useCompleteConversation, | |||
| useCreateToken, | |||
| useFetchConversation, | |||
| useFetchConversationList, | |||
| useFetchDialog, | |||
| useFetchDialogList, | |||
| useFetchStats, | |||
| useListToken, | |||
| useRemoveConversation, | |||
| useRemoveDialog, | |||
| useRemoveToken, | |||
| useSelectConversationList, | |||
| useSelectDialogList, | |||
| useSelectTokenList, | |||
| useSetDialog, | |||
| useUpdateConversation, | |||
| } from '@/hooks/chatHooks'; | |||
| import { useSetModalState, useShowDeleteConfirm } from '@/hooks/commonHooks'; | |||
| 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 { getFileExtension } from '@/utils'; | |||
| import dayjs, { Dayjs } from 'dayjs'; | |||
| import omit from 'lodash/omit'; | |||
| import { | |||
| ChangeEventHandler, | |||
| @@ -704,3 +710,108 @@ export const useGetSendButtonDisabled = () => { | |||
| return dialogId === '' && conversationId === ''; | |||
| }; | |||
| //#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 | |||
| @@ -35,7 +35,10 @@ import { | |||
| useSelectFirstDialogOnMount, | |||
| } 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'; | |||
| const Chat = () => { | |||
| @@ -73,6 +76,12 @@ const Chat = () => { | |||
| const dialogLoading = useSelectDialogListLoading(); | |||
| const conversationLoading = useSelectConversationListLoading(); | |||
| const { t } = useTranslate('chat'); | |||
| const { | |||
| visible: overviewVisible, | |||
| hideModal: hideOverviewModal, | |||
| showModal: showOverviewModal, | |||
| } = useSetModalState(); | |||
| const { currentRecord, setRecord } = useSetSelectedRecord<IDialog>(); | |||
| useFetchDialogOnMount(dialogId, true); | |||
| @@ -100,6 +109,15 @@ const Chat = () => { | |||
| onRemoveDialog([dialogId]); | |||
| }; | |||
| const handleShowOverviewModal = | |||
| (dialog: IDialog): any => | |||
| (info: any) => { | |||
| info?.domEvent?.preventDefault(); | |||
| info?.domEvent?.stopPropagation(); | |||
| setRecord(dialog); | |||
| showOverviewModal(); | |||
| }; | |||
| const handleRemoveConversation = | |||
| (conversationId: string): MenuItemProps['onClick'] => | |||
| ({ domEvent }) => { | |||
| @@ -141,7 +159,9 @@ const Chat = () => { | |||
| }, | |||
| ]; | |||
| const buildAppItems = (dialogId: string) => { | |||
| const buildAppItems = (dialog: IDialog) => { | |||
| const dialogId = dialog.id; | |||
| const appItems: MenuProps['items'] = [ | |||
| { | |||
| key: '1', | |||
| @@ -164,6 +184,17 @@ const Chat = () => { | |||
| </Space> | |||
| ), | |||
| }, | |||
| { type: 'divider' }, | |||
| // { | |||
| // key: '3', | |||
| // onClick: handleShowOverviewModal(dialog), | |||
| // label: ( | |||
| // <Space> | |||
| // <ProfileOutlined /> | |||
| // {t('overview')} | |||
| // </Space> | |||
| // ), | |||
| // }, | |||
| ]; | |||
| return appItems; | |||
| @@ -230,7 +261,7 @@ const Chat = () => { | |||
| </Space> | |||
| {activated === x.id && ( | |||
| <section> | |||
| <Dropdown menu={{ items: buildAppItems(x.id) }}> | |||
| <Dropdown menu={{ items: buildAppItems(x) }}> | |||
| <ChatAppCube | |||
| className={styles.cubeIcon} | |||
| ></ChatAppCube> | |||
| @@ -315,6 +346,11 @@ const Chat = () => { | |||
| initialName={initialConversationName} | |||
| loading={conversationRenameLoading} | |||
| ></RenameModal> | |||
| <ChatOverviewModal | |||
| visible={overviewVisible} | |||
| hideModal={hideOverviewModal} | |||
| dialog={currentRecord} | |||
| ></ChatOverviewModal> | |||
| </Flex> | |||
| ); | |||
| }; | |||
| @@ -1,7 +1,14 @@ | |||
| import { IConversation, IDialog, Message } from '@/interfaces/database/chat'; | |||
| import { | |||
| IConversation, | |||
| IDialog, | |||
| IStats, | |||
| IToken, | |||
| Message, | |||
| } from '@/interfaces/database/chat'; | |||
| import i18n from '@/locales/config'; | |||
| import chatService from '@/services/chatService'; | |||
| import { message } from 'antd'; | |||
| import omit from 'lodash/omit'; | |||
| import { DvaModel } from 'umi'; | |||
| import { v4 as uuid } from 'uuid'; | |||
| import { IClientConversation, IMessage } from './interface'; | |||
| @@ -13,6 +20,8 @@ export interface ChatModelState { | |||
| currentDialog: IDialog; | |||
| conversationList: IConversation[]; | |||
| currentConversation: IClientConversation; | |||
| tokenList: IToken[]; | |||
| stats: IStats; | |||
| } | |||
| const model: DvaModel<ChatModelState> = { | |||
| @@ -23,6 +32,8 @@ const model: DvaModel<ChatModelState> = { | |||
| currentDialog: <IDialog>{}, | |||
| conversationList: [], | |||
| currentConversation: {} as IClientConversation, | |||
| tokenList: [], | |||
| stats: {} as IStats, | |||
| }, | |||
| reducers: { | |||
| save(state, action) { | |||
| @@ -60,6 +71,18 @@ const model: DvaModel<ChatModelState> = { | |||
| currentConversation: { ...payload, message: messageList }, | |||
| }; | |||
| }, | |||
| setTokenList(state, { payload }) { | |||
| return { | |||
| ...state, | |||
| tokenList: payload, | |||
| }; | |||
| }, | |||
| setStats(state, { payload }) { | |||
| return { | |||
| ...state, | |||
| stats: payload, | |||
| }; | |||
| }, | |||
| }, | |||
| effects: { | |||
| @@ -160,6 +183,78 @@ const model: DvaModel<ChatModelState> = { | |||
| } | |||
| 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; | |||
| }, | |||
| }, | |||
| }; | |||
| @@ -12,6 +12,13 @@ const { | |||
| completeConversation, | |||
| listConversation, | |||
| removeConversation, | |||
| createToken, | |||
| listToken, | |||
| removeToken, | |||
| getStats, | |||
| createExternalConversation, | |||
| getExternalConversation, | |||
| completeExternalConversation, | |||
| } = api; | |||
| const methods = { | |||
| @@ -51,6 +58,34 @@ const methods = { | |||
| url: removeConversation, | |||
| 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; | |||
| const chatService = registerServer<keyof typeof methods>(methods, request); | |||
| @@ -3,7 +3,7 @@ let api_host = `/v1`; | |||
| export { api_host }; | |||
| export default { | |||
| // 用户 | |||
| // user | |||
| login: `${api_host}/user/login`, | |||
| logout: `${api_host}/user/logout`, | |||
| register: `${api_host}/user/register`, | |||
| @@ -12,21 +12,21 @@ export default { | |||
| tenant_info: `${api_host}/user/tenant_info`, | |||
| set_tenant_info: `${api_host}/user/set_tenant_info`, | |||
| // 模型管理 | |||
| // llm model | |||
| factories_list: `${api_host}/llm/factories`, | |||
| llm_list: `${api_host}/llm/list`, | |||
| my_llm: `${api_host}/llm/my_llms`, | |||
| set_api_key: `${api_host}/llm/set_api_key`, | |||
| add_llm: `${api_host}/llm/add_llm`, | |||
| //知识库管理 | |||
| // knowledge base | |||
| kb_list: `${api_host}/kb/list`, | |||
| create_kb: `${api_host}/kb/create`, | |||
| update_kb: `${api_host}/kb/update`, | |||
| rm_kb: `${api_host}/kb/rm`, | |||
| get_kb_detail: `${api_host}/kb/detail`, | |||
| // chunk管理 | |||
| // chunk | |||
| chunk_list: `${api_host}/chunk/list`, | |||
| create_chunk: `${api_host}/chunk/create`, | |||
| set_chunk: `${api_host}/chunk/set`, | |||
| @@ -35,7 +35,7 @@ export default { | |||
| rm_chunk: `${api_host}/chunk/rm`, | |||
| retrieval_test: `${api_host}/chunk/retrieval_test`, | |||
| // 文件管理 | |||
| // document | |||
| upload: `${api_host}/document/upload`, | |||
| get_document_list: `${api_host}/document/list`, | |||
| document_change_status: `${api_host}/document/change_status`, | |||
| @@ -48,14 +48,22 @@ export default { | |||
| get_document_file: `${api_host}/document/get`, | |||
| document_upload: `${api_host}/document/upload`, | |||
| // chat | |||
| setDialog: `${api_host}/dialog/set`, | |||
| getDialog: `${api_host}/dialog/get`, | |||
| removeDialog: `${api_host}/dialog/rm`, | |||
| listDialog: `${api_host}/dialog/list`, | |||
| setConversation: `${api_host}/conversation/set`, | |||
| getConversation: `${api_host}/conversation/get`, | |||
| listConversation: `${api_host}/conversation/list`, | |||
| removeConversation: `${api_host}/conversation/rm`, | |||
| 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`, | |||
| }; | |||
| @@ -0,0 +1,17 @@ | |||
| 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; | |||
| }; | |||
| @@ -1,20 +1,20 @@ | |||
| import moment from 'moment'; | |||
| import dayjs from 'dayjs'; | |||
| export function today() { | |||
| return formatDate(moment()); | |||
| return formatDate(dayjs()); | |||
| } | |||
| export function lastDay() { | |||
| return formatDate(moment().subtract(1, 'days')); | |||
| return formatDate(dayjs().subtract(1, 'days')); | |||
| } | |||
| export function lastWeek() { | |||
| return formatDate(moment().subtract(1, 'weeks')); | |||
| return formatDate(dayjs().subtract(1, 'weeks')); | |||
| } | |||
| export function formatDate(date: any) { | |||
| if (!date) { | |||
| return ''; | |||
| } | |||
| return moment(date).format('DD/MM/YYYY'); | |||
| return dayjs(date).format('DD/MM/YYYY'); | |||
| } | |||
| @@ -8,16 +8,20 @@ const registerServer = <T extends string>( | |||
| ) => { | |||
| const server: Service<T> = {} as Service<T>; | |||
| 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') { | |||
| return request(opt[key].url, { | |||
| return request(url, { | |||
| method: opt[key].method, | |||
| data: params, | |||
| }); | |||
| } | |||
| if (opt[key].method === 'get' || opt[key].method === 'GET') { | |||
| return request.get(opt[key].url, { | |||
| return request.get(url, { | |||
| params, | |||
| }); | |||
| } | |||
| @@ -4,6 +4,7 @@ import authorizationUtil from '@/utils/authorizationUtil'; | |||
| import { message, notification } from 'antd'; | |||
| import { history } from 'umi'; | |||
| import { RequestMethod, extend } from 'umi-request'; | |||
| import { convertTheKeysOfTheObjectToSnake } from './commonUtil'; | |||
| const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动中断请求。errorHandler 抛出的error message | |||
| @@ -87,10 +88,15 @@ const request: RequestMethod = extend({ | |||
| request.interceptors.request.use((url: string, options: any) => { | |||
| const authorization = authorizationUtil.getAuthorization(); | |||
| const data = convertTheKeysOfTheObjectToSnake(options.data); | |||
| const params = convertTheKeysOfTheObjectToSnake(options.params); | |||
| return { | |||
| url, | |||
| options: { | |||
| ...options, | |||
| // data, | |||
| // params, | |||
| headers: { | |||
| ...(options.skipToken ? undefined : { [Authorization]: authorization }), | |||
| ...options.headers, | |||