mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-10 11:07:06 +00:00
Compare commits
419 Commits
v0.9.8
...
86651a2b10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86651a2b10 | ||
|
|
62b9db6791 | ||
|
|
6d907b6adf | ||
|
|
da172a030e | ||
|
|
47c2595fb8 | ||
|
|
9bddd4457e | ||
|
|
55ac3d1aa5 | ||
|
|
0427917624 | ||
|
|
d8fe2ed2b3 | ||
|
|
11d1264d38 | ||
|
|
32675387d7 | ||
|
|
e408204690 | ||
|
|
269f146c11 | ||
|
|
6f497b142e | ||
|
|
79a44b27ee | ||
|
|
76cc5ee111 | ||
|
|
320fcf04bd | ||
|
|
75fc83010c | ||
|
|
37673c82da | ||
|
|
3ae0d645a7 | ||
|
|
256a6bcb3f | ||
|
|
1faf84e372 | ||
|
|
7e6639df83 | ||
|
|
075ae4c0af | ||
|
|
08133ccbfb | ||
|
|
164d2a9e23 | ||
|
|
f899d23b63 | ||
|
|
944beddafc | ||
|
|
019d737f07 | ||
|
|
0721df2e66 | ||
|
|
303392f492 | ||
|
|
e5a41765b4 | ||
|
|
87355533b4 | ||
|
|
06fb6ba744 | ||
|
|
9ffdba956e | ||
|
|
df70a3cf15 | ||
|
|
2552e2ae4b | ||
|
|
4bfa10ba7c | ||
|
|
958aca945d | ||
|
|
fae9118c28 | ||
|
|
c24ba59bb5 | ||
|
|
fa65b6eff7 | ||
|
|
0ab44c0866 | ||
|
|
449fdf180f | ||
|
|
90c4f66770 | ||
|
|
d275a145d5 | ||
|
|
c8f690c1c2 | ||
|
|
38af6e3a28 | ||
|
|
b9dd6bb7c5 | ||
|
|
dff64b62f4 | ||
|
|
8eeed87bac | ||
|
|
e171bdd97f | ||
|
|
0709575cd9 | ||
|
|
be0447ae15 | ||
|
|
1b8cd7f0d3 | ||
|
|
2fd82cc259 | ||
|
|
00814a3807 | ||
|
|
08705c9d3b | ||
|
|
1c9cf788cb | ||
|
|
1ab5d9c7e6 | ||
|
|
2b13866c0b | ||
|
|
e812884802 | ||
|
|
e2ae7e21ad | ||
|
|
3fc1ec42be | ||
|
|
c4992501bd | ||
|
|
acffc03c79 | ||
|
|
763def2de0 | ||
|
|
d0a67af684 | ||
|
|
be8b56bdde | ||
|
|
9f2c0c7699 | ||
|
|
c1fa9d7442 | ||
|
|
0d5da763b3 | ||
|
|
d1b4863a27 | ||
|
|
dce9a8a58c | ||
|
|
fbf048cb00 | ||
|
|
48a8f69cca | ||
|
|
ecdf65da3e | ||
|
|
5585b9e222 | ||
|
|
97710a90c4 | ||
|
|
0ab7643299 | ||
|
|
d2aa73b85e | ||
|
|
8828964e53 | ||
|
|
b188da8595 | ||
|
|
2e7ba468c9 | ||
|
|
d26c9180ed | ||
|
|
ca96aa725d | ||
|
|
614917ba76 | ||
|
|
1fed8ca4d9 | ||
|
|
232a202275 | ||
|
|
791c493a6a | ||
|
|
f9d4ce2128 | ||
|
|
8abfc923a0 | ||
|
|
e6598a79bb | ||
|
|
d2a43a99c8 | ||
|
|
db8f340e2d | ||
|
|
2e81b190a4 | ||
|
|
81cd60d2da | ||
|
|
3ffc8c3d9e | ||
|
|
18db24c011 | ||
|
|
cd698ac367 | ||
|
|
58b640b087 | ||
|
|
1f28aaeaed | ||
|
|
35b835172b | ||
|
|
1c85bcecc5 | ||
|
|
c3483ae340 | ||
|
|
a5051c7225 | ||
|
|
12f6cfa42d | ||
|
|
4c94f2b816 | ||
|
|
c81aa5859d | ||
|
|
21e213fb19 | ||
|
|
f67bf3eeac | ||
|
|
9d13038599 | ||
|
|
0c8c2d4804 | ||
|
|
f05a4b523c | ||
|
|
b7369abcca | ||
|
|
b40cb13740 | ||
|
|
6f8cf9853b | ||
|
|
75906037ac | ||
|
|
b58e041e8d | ||
|
|
93d585c0d5 | ||
|
|
0dbf56d357 | ||
|
|
a3293e6788 | ||
|
|
a99f5985f5 | ||
|
|
91243005bc | ||
|
|
a76b5a4300 | ||
|
|
c1f9df963c | ||
|
|
954aa4eea5 | ||
|
|
33bd0de604 | ||
|
|
881d891d70 | ||
|
|
d9db455dab | ||
|
|
e0dc3fbf1a | ||
|
|
efddf4cacf | ||
|
|
732222ab98 | ||
|
|
5b994c4f8f | ||
|
|
5d2ebdf680 | ||
|
|
f1bc18ef65 | ||
|
|
8f361f9932 | ||
|
|
f532088e38 | ||
|
|
f7ce9480bb | ||
|
|
f8104687cc | ||
|
|
6eba693982 | ||
|
|
b871ae542a | ||
|
|
3ca48e1ca1 | ||
|
|
ea7238304d | ||
|
|
1746db53c1 | ||
|
|
90c2f8b374 | ||
|
|
bd64bf1f62 | ||
|
|
56cfddea60 | ||
|
|
0aa002882d | ||
|
|
5e3bafb953 | ||
|
|
11ff99cdbe | ||
|
|
f9198cb8e0 | ||
|
|
b5aa6e046e | ||
|
|
29271f7278 | ||
|
|
50ed340ae0 | ||
|
|
75f623404d | ||
|
|
94e853f57e | ||
|
|
5fa3607874 | ||
|
|
1e01f3ef60 | ||
|
|
1155ac10d8 | ||
|
|
5a22590661 | ||
|
|
fc67411618 | ||
|
|
c03be2f5d8 | ||
|
|
08a2e889e7 | ||
|
|
87fa778416 | ||
|
|
b70b7ed01a | ||
|
|
335e1f9ada | ||
|
|
33268bf3d9 | ||
|
|
86b9d2013a | ||
|
|
aced1dfd3e | ||
|
|
d1e5e8777a | ||
|
|
b743585d3e | ||
|
|
9aa305ca7a | ||
|
|
fe51882031 | ||
|
|
17a3dd052c | ||
|
|
2e71b9b892 | ||
|
|
a067d2cace | ||
|
|
32793ecf69 | ||
|
|
43b96edc77 | ||
|
|
f31db98aba | ||
|
|
348d6df6a2 | ||
|
|
91768892cf | ||
|
|
0868a18b08 | ||
|
|
46316cadcf | ||
|
|
f804371134 | ||
|
|
d6620e6ea7 | ||
|
|
cc2d6a21c2 | ||
|
|
19395f369a | ||
|
|
baae7f74b8 | ||
|
|
e9d9c4591d | ||
|
|
6cc145935d | ||
|
|
89e07509de | ||
|
|
d942d35c93 | ||
|
|
198c7c69e6 | ||
|
|
cb139a54e8 | ||
|
|
f412ae4539 | ||
|
|
3ca46bee36 | ||
|
|
a8157ee769 | ||
|
|
eef7b3c443 | ||
|
|
c34b85c8a4 | ||
|
|
be2e380b4c | ||
|
|
eeaebe06aa | ||
|
|
4ab9cd715d | ||
|
|
fd306db3fe | ||
|
|
30adaa3f20 | ||
|
|
cc66ebd684 | ||
|
|
ef161fe1f2 | ||
|
|
0417f12324 | ||
|
|
d294fec2a0 | ||
|
|
de92b357df | ||
|
|
be5eeae707 | ||
|
|
65f0096724 | ||
|
|
416488b919 | ||
|
|
8900fde4a3 | ||
|
|
2b28aeea6f | ||
|
|
329756056c | ||
|
|
715adb5260 | ||
|
|
da6d28c18c | ||
|
|
cd863705a4 | ||
|
|
f264b3160f | ||
|
|
61e22c2104 | ||
|
|
6e4260f9f1 | ||
|
|
ab74acc84a | ||
|
|
4e653c1fb1 | ||
|
|
6fcfdc15e1 | ||
|
|
4738b9d01b | ||
|
|
e0f7ec0f40 | ||
|
|
7b46ef64fd | ||
|
|
6af345044a | ||
|
|
4821f31e15 | ||
|
|
be59b051fc | ||
|
|
83cb6967e7 | ||
|
|
22f6190e7c | ||
|
|
43140e695b | ||
|
|
a46e89af56 | ||
|
|
a2f54d4c80 | ||
|
|
24eaffb2d5 | ||
|
|
739514ddfa | ||
|
|
6486257c9e | ||
|
|
6f5e477e3c | ||
|
|
683f01c33b | ||
|
|
3e1e5ae209 | ||
|
|
0612833618 | ||
|
|
7145f27671 | ||
|
|
920d8f280a | ||
|
|
ade03627ce | ||
|
|
a23d1071a3 | ||
|
|
ce9ae1c0c1 | ||
|
|
d834e98a66 | ||
|
|
94267f6028 | ||
|
|
a4d2df4063 | ||
|
|
8e03531424 | ||
|
|
16600ed6f0 | ||
|
|
d04a086c88 | ||
|
|
68963b9ec9 | ||
|
|
265e51c429 | ||
|
|
d40400d2a4 | ||
|
|
c483bb891a | ||
|
|
6738aba19e | ||
|
|
493a8035cd | ||
|
|
b425c49c5b | ||
|
|
4dca6eec5a | ||
|
|
642d6a02e1 | ||
|
|
5de5b0a5e2 | ||
|
|
214d90772d | ||
|
|
d8b8c4e6b9 | ||
|
|
10a510409f | ||
|
|
19c1d306df | ||
|
|
8c6ae62522 | ||
|
|
758d170bbf | ||
|
|
7dc013dfb3 | ||
|
|
72780f9acf | ||
|
|
7b49412bde | ||
|
|
9f63aca132 | ||
|
|
933b54085c | ||
|
|
f7fce0217f | ||
|
|
c2d155705f | ||
|
|
5faf5f3ac4 | ||
|
|
d88d8b3beb | ||
|
|
caf03588c6 | ||
|
|
4cb2256351 | ||
|
|
8b69d57c4b | ||
|
|
91856ddebd | ||
|
|
94e97c9a1d | ||
|
|
9faa858c22 | ||
|
|
6fcd105249 | ||
|
|
1d0f5612b7 | ||
|
|
b57eed47e2 | ||
|
|
aa3b8997bd | ||
|
|
84944fa341 | ||
|
|
b4c19533a4 | ||
|
|
831fbfe475 | ||
|
|
62b64c74a3 | ||
|
|
ed5c129a4a | ||
|
|
14087825df | ||
|
|
f9cc395e49 | ||
|
|
d014a27aff | ||
|
|
2e28a4c7a5 | ||
|
|
9f8793bfe2 | ||
|
|
a8868ba9ab | ||
|
|
8c44c9f42f | ||
|
|
f97ac1da83 | ||
|
|
07f6be51c7 | ||
|
|
4062a13126 | ||
|
|
f6622319a4 | ||
|
|
2567742115 | ||
|
|
215391bb2d | ||
|
|
4a6938956b | ||
|
|
e586983ff1 | ||
|
|
a12486591b | ||
|
|
848b4a1e44 | ||
|
|
a298c670ed | ||
|
|
f2f7caa32c | ||
|
|
3db9a0dcec | ||
|
|
09ea5db0ba | ||
|
|
8000ee5237 | ||
|
|
e55f43c737 | ||
|
|
43ba1a0ba6 | ||
|
|
4bd521020a | ||
|
|
aa400176a5 | ||
|
|
c98c5ade9e | ||
|
|
28d5f38ffb | ||
|
|
9e24fd04a5 | ||
|
|
02c6a7d404 | ||
|
|
fe57a4e5cf | ||
|
|
79ab1be306 | ||
|
|
3e903b862e | ||
|
|
0ce79cbfc0 | ||
|
|
cf79ac9ece | ||
|
|
02f0063846 | ||
|
|
b8924ed45e | ||
|
|
27c6b8ecb1 | ||
|
|
7de3662259 | ||
|
|
ba4d92e11c | ||
|
|
350b6089dc | ||
|
|
350567755a | ||
|
|
efac1efdb0 | ||
|
|
4592131b55 | ||
|
|
b3b1498af7 | ||
|
|
83cfae609e | ||
|
|
0fc29304a8 | ||
|
|
89d2ac802d | ||
|
|
dee9b119eb | ||
|
|
a232c2bc4f | ||
|
|
0f1c50167d | ||
|
|
1c73453c5f | ||
|
|
639d1a78da | ||
|
|
5837a5b3ae | ||
|
|
6ecc5a9362 | ||
|
|
8299084c95 | ||
|
|
bb60c93824 | ||
|
|
d22a7d1cc6 | ||
|
|
4358ffe4a1 | ||
|
|
82c63a7f22 | ||
|
|
50accb152a | ||
|
|
66ed711416 | ||
|
|
4076d37b9b | ||
|
|
67377bc7dc | ||
|
|
593597fe26 | ||
|
|
a058dc8b6e | ||
|
|
13d4fc3feb | ||
|
|
b4669cf110 | ||
|
|
c80794e8fc | ||
|
|
111304486b | ||
|
|
25559fdaa5 | ||
|
|
dad065d0ba | ||
|
|
7bf1ba09c5 | ||
|
|
97867ca015 | ||
|
|
9bccbae3bc | ||
|
|
224c114d20 | ||
|
|
1de999dc1d | ||
|
|
2eca2d1c14 | ||
|
|
40bfcdce2c | ||
|
|
b84dde3799 | ||
|
|
91b16f95ff | ||
|
|
860fd5d299 | ||
|
|
c22e3ef2e8 | ||
|
|
296ce5cc55 | ||
|
|
722f40cdf7 | ||
|
|
0edadd01eb | ||
|
|
a942132b83 | ||
|
|
cb183b7ac8 | ||
|
|
244052e806 | ||
|
|
46d64d78f3 | ||
|
|
62fc2dd18a | ||
|
|
be05f977d5 | ||
|
|
d7586a5d3b | ||
|
|
e990b37433 | ||
|
|
eb502e740c | ||
|
|
62a4d60a0b | ||
|
|
8d63ed170a | ||
|
|
f4f0e58bfb | ||
|
|
534da49309 | ||
|
|
8c6da5dc54 | ||
|
|
159d91fd0f | ||
|
|
5a8c20a00b | ||
|
|
cd889b479c | ||
|
|
a0f53359ef | ||
|
|
36d221ab74 | ||
|
|
e8c9855163 | ||
|
|
ba1938f04b | ||
|
|
5e22b412c6 | ||
|
|
87729956e8 | ||
|
|
ea6a9ebc5f | ||
|
|
14a19a901f | ||
|
|
ca4545bb15 | ||
|
|
e0e167fd40 | ||
|
|
d4a9d5a7e6 | ||
|
|
c9c6dc4e44 | ||
|
|
524ec38edc | ||
|
|
9edcb9f91c | ||
|
|
6f2af79756 | ||
|
|
7be885d9c8 | ||
|
|
9a05b5cce6 | ||
|
|
3b65b1c80b | ||
|
|
1e5bf7909e | ||
|
|
6a4458a572 | ||
|
|
1867447b6e | ||
|
|
ff7fb50030 |
69
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
69
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -11,59 +11,28 @@ body:
|
|||||||
If it is an idea or help wanted, please go to:
|
If it is an idea or help wanted, please go to:
|
||||||
[Github Discussion](https://github.com/tencentmusic/supersonic/discussions)
|
[Github Discussion](https://github.com/tencentmusic/supersonic/discussions)
|
||||||
|
|
||||||
- type: checkboxes
|
- type: input
|
||||||
|
id: version
|
||||||
attributes:
|
attributes:
|
||||||
label: Search before asking
|
label: SuperSonic version
|
||||||
description: >
|
description: Please tell us which version you are using.
|
||||||
Please make sure to search in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) first to see
|
placeholder: "0.9.8"
|
||||||
whether the same issue was reported already.
|
validations:
|
||||||
options:
|
required: true
|
||||||
- label: >
|
|
||||||
I had searched in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) and found no similar
|
|
||||||
issues.
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
- type: input
|
||||||
|
id: organization
|
||||||
attributes:
|
attributes:
|
||||||
label: Version
|
label: Your organization
|
||||||
description: What is the current version
|
description: Please tell us your organization so that we can provide you better support and advice.
|
||||||
placeholder: >
|
placeholder: "TME..."
|
||||||
Please provide the version you are using.
|
|
||||||
If it is the trunk version, please input commit id.
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: What's Wrong?
|
label: Description
|
||||||
description: Describe the bug.
|
description: Describe the bug you met.
|
||||||
placeholder: >
|
|
||||||
Describe the specific problem, the more detailed the better.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: What You Expected?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: How to Reproduce?
|
|
||||||
placeholder: >
|
|
||||||
Please try to give reproducing steps to facilitate quick location of the problem.
|
|
||||||
|
|
||||||
- What actions were performed
|
|
||||||
- Table building statement
|
|
||||||
- Import statement
|
|
||||||
- Cluster information: number of nodes, configuration, etc.
|
|
||||||
|
|
||||||
If it is hard to reproduce, please also explain the general scene.
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Anything Else?
|
|
||||||
|
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
@@ -74,16 +43,6 @@ body:
|
|||||||
options:
|
options:
|
||||||
- label: Yes I am willing to submit a PR!
|
- label: Yes I am willing to submit a PR!
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Code of Conduct
|
|
||||||
description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.
|
|
||||||
options:
|
|
||||||
- label: >
|
|
||||||
I agree to follow this project's
|
|
||||||
[Code of Conduct](https://www.apache.org/foundation/policies/conduct)
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: "Thanks for completing our form!"
|
value: "Thanks for completing our form!"
|
||||||
|
|||||||
34
.github/ISSUE_TEMPLATE/enhancement_request.yml
vendored
34
.github/ISSUE_TEMPLATE/enhancement_request.yml
vendored
@@ -8,30 +8,20 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thank you very much for your good enhancement for SuperSonic.
|
Thank you very much for your good enhancement for SuperSonic.
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Search before asking
|
|
||||||
description: >
|
|
||||||
Please make sure to search in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) first to see
|
|
||||||
whether the same issue was reported already.
|
|
||||||
options:
|
|
||||||
- label: >
|
|
||||||
I had searched in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) and found no similar
|
|
||||||
issues.
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Description
|
label: Description
|
||||||
description: Describe the enhancement what you want, including motivation if it exists.
|
description: Describe the enhancement what you want, including motivation if it exists.
|
||||||
|
|
||||||
- type: textarea
|
- type: input
|
||||||
|
id: organization
|
||||||
attributes:
|
attributes:
|
||||||
label: Solution
|
label: Your organization
|
||||||
placeholder: >
|
description: Please tell us your organization so that we can provide you better support and advice.
|
||||||
Add overview of proposed solution.
|
placeholder: "TME..."
|
||||||
|
validations:
|
||||||
Add related materials like links if they exist.
|
required: true
|
||||||
|
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
@@ -42,16 +32,6 @@ body:
|
|||||||
options:
|
options:
|
||||||
- label: Yes I am willing to submit a PR!
|
- label: Yes I am willing to submit a PR!
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Code of Conduct
|
|
||||||
description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.
|
|
||||||
options:
|
|
||||||
- label: >
|
|
||||||
I agree to follow this project's
|
|
||||||
[Code of Conduct](https://www.apache.org/foundation/policies/conduct)
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: "Thanks for completing our form!"
|
value: "Thanks for completing our form!"
|
||||||
|
|||||||
40
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
40
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -8,33 +8,19 @@ body:
|
|||||||
value: |
|
value: |
|
||||||
Thank you very much for your good ideas and suggestions for SuperSonic
|
Thank you very much for your good ideas and suggestions for SuperSonic
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Search before asking
|
|
||||||
description: >
|
|
||||||
Please make sure to search in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) first to see
|
|
||||||
whether the same issue was reported already.
|
|
||||||
options:
|
|
||||||
- label: >
|
|
||||||
I had searched in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) and found no similar
|
|
||||||
issues.
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Description
|
label: Description
|
||||||
description: Describe your ideas and needs.
|
description: Describe your ideas and needs.
|
||||||
|
|
||||||
- type: textarea
|
- type: input
|
||||||
|
id: organization
|
||||||
attributes:
|
attributes:
|
||||||
label: Use case
|
label: Your organization
|
||||||
placeholder: >
|
description: Please tell us your organization so that we can provide you better support and advice.
|
||||||
What problem does this feature mainly solve, or what scenarios it is suitable for.
|
placeholder: "TME..."
|
||||||
|
validations:
|
||||||
- type: textarea
|
required: true
|
||||||
attributes:
|
|
||||||
label: Related issues
|
|
||||||
description: Is there currently another issue associated with this?
|
|
||||||
|
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
@@ -45,16 +31,4 @@ body:
|
|||||||
options:
|
options:
|
||||||
- label: Yes I am willing to submit a PR!
|
- label: Yes I am willing to submit a PR!
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Code of Conduct
|
|
||||||
description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.
|
|
||||||
options:
|
|
||||||
- label: >
|
|
||||||
I agree to follow this project's
|
|
||||||
[Code of Conduct](https://www.apache.org/foundation/policies/conduct)
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: "Thanks for completing our form!"
|
|
||||||
|
|||||||
46
.github/ISSUE_TEMPLATE/question_request.yml
vendored
46
.github/ISSUE_TEMPLATE/question_request.yml
vendored
@@ -8,6 +8,7 @@ body:
|
|||||||
value: |
|
value: |
|
||||||
## Ask a Question about SuperSonic
|
## Ask a Question about SuperSonic
|
||||||
Please provide a detailed description of your question or the clarification you seek regarding the SuperSonic project.
|
Please provide a detailed description of your question or the clarification you seek regarding the SuperSonic project.
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: describe-question
|
id: describe-question
|
||||||
attributes:
|
attributes:
|
||||||
@@ -16,43 +17,12 @@ body:
|
|||||||
placeholder: "Type your question here..."
|
placeholder: "Type your question here..."
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
|
||||||
id: additional-context
|
- type: input
|
||||||
|
id: organization
|
||||||
attributes:
|
attributes:
|
||||||
label: Provide any additional context or information
|
label: Your organization
|
||||||
description: If your question is related to a specific part of the SuperSonic project or if you have already looked through certain documentation, please provide that information here.
|
description: Please tell us your organization so that we can provide you better support and advice.
|
||||||
placeholder: "Add context here..."
|
placeholder: "TME..."
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: true
|
||||||
- type: textarea
|
|
||||||
id: tried-to-resolve
|
|
||||||
attributes:
|
|
||||||
label: What have you tried to resolve your question
|
|
||||||
description: Let us know what you have done to try and understand or resolve your question. This can help us provide you with the most useful guidance.
|
|
||||||
placeholder: "I've already tried..."
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
id: environment
|
|
||||||
attributes:
|
|
||||||
label: Your environment
|
|
||||||
description: Share details about your environment to help us reproduce the issue. Include your operating system, version of SuperSonic, and any other relevant details.
|
|
||||||
placeholder: "OS, SuperSonic version, etc..."
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
id: screenshots-logs
|
|
||||||
attributes:
|
|
||||||
label: Screenshots or Logs
|
|
||||||
description: If applicable, add screenshots or logs to help explain your problem.
|
|
||||||
placeholder: "Paste your logs or attach screenshots here..."
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
id: additional-information
|
|
||||||
attributes:
|
|
||||||
label: Additional information
|
|
||||||
description: Add any other context or details you think might be helpful for understanding your question.
|
|
||||||
placeholder: "Any other information..."
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
38
.github/workflows/centos-ci.yml
vendored
38
.github/workflows/centos-ci.yml
vendored
@@ -11,39 +11,36 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: quay.io/centos/centos:stream8 # 使用 CentOS Stream 8 容器
|
image: almalinux:9 # maven >=3.6.3
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
java-version: [8, 11, 21] # 定义要测试的JDK版本
|
java-version: [21] # 定义要测试的JDK版本
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up JDK ${{ matrix.java-version }}
|
||||||
|
uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
java-version: ${{ matrix.java-version }}
|
||||||
|
distribution: 'adopt'
|
||||||
|
|
||||||
- name: Reset DNF repositories
|
- name: Reset DNF repositories
|
||||||
run: |
|
run: |
|
||||||
cd /etc/yum.repos.d/
|
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
|
||||||
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
|
-e 's|^# baseurl=https://repo.almalinux.org|baseurl=https://mirrors.aliyun.com|g' \
|
||||||
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
|
/etc/yum.repos.d/almalinux*.repo
|
||||||
|
|
||||||
|
|
||||||
- name: Update DNF package index
|
- name: Update DNF package index
|
||||||
run: dnf makecache
|
run: dnf makecache
|
||||||
|
|
||||||
- name: Install Java and Maven with retry
|
- name: Install Maven with retry
|
||||||
run: |
|
run: |
|
||||||
if [ ${{ matrix.java-version }} -eq 8 ]; then
|
for i in {1..5}; do
|
||||||
for i in {1..5}; do
|
dnf install -y maven && break || sleep 15
|
||||||
dnf install -y java-1.8.0-openjdk-devel maven && break || sleep 15
|
done
|
||||||
done
|
|
||||||
elif [ ${{ matrix.java-version }} -eq 11 ]; then
|
|
||||||
for i in {1..5}; do
|
|
||||||
dnf install -y java-11-openjdk-devel maven && break || sleep 15
|
|
||||||
done
|
|
||||||
elif [ ${{ matrix.java-version }} -eq 21 ]; then
|
|
||||||
for i in {1..5}; do
|
|
||||||
dnf install -y java-21-openjdk-devel maven && break || sleep 15
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Verify Java and Maven installation
|
- name: Verify Java and Maven installation
|
||||||
run: |
|
run: |
|
||||||
@@ -51,7 +48,7 @@ jobs:
|
|||||||
mvn -version
|
mvn -version
|
||||||
|
|
||||||
- name: Cache Maven packages
|
- name: Cache Maven packages
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.m2
|
path: ~/.m2
|
||||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||||
@@ -62,3 +59,4 @@ jobs:
|
|||||||
|
|
||||||
- name: Test with Maven
|
- name: Test with Maven
|
||||||
run: mvn test
|
run: mvn test
|
||||||
|
|
||||||
|
|||||||
32
.github/workflows/docker-publish.yml
vendored
Normal file
32
.github/workflows/docker-publish.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Docker Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'Version of the Docker image'
|
||||||
|
required: true
|
||||||
|
default: 'latest'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Build and publish Docker image
|
||||||
|
run: |
|
||||||
|
VERSION=${{ github.event.inputs.version }}
|
||||||
|
chmod +x docker/docker-build-publish.sh
|
||||||
|
sh docker/docker-build-publish.sh $VERSION
|
||||||
16
.github/workflows/mac-ci.yml
vendored
16
.github/workflows/mac-ci.yml
vendored
@@ -14,24 +14,30 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
java-version: [8, 11, 21] # Define the JDK versions to test
|
java-version: [21] # Define the JDK versions to test
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up JDK ${{ matrix.java-version }}
|
- name: Set up JDK ${{ matrix.java-version }}
|
||||||
uses: actions/setup-java@v2
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
java-version: ${{ matrix.java-version }}
|
java-version: ${{ matrix.java-version }}
|
||||||
distribution: 'adopt'
|
distribution: 'temurin'
|
||||||
|
|
||||||
- name: Cache Maven packages
|
- name: Cache Maven packages
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/Library/Caches/Maven # macOS Maven cache path
|
path: ~/Library/Caches/Maven # macOS Maven cache path
|
||||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||||
restore-keys: ${{ runner.os }}-m2
|
restore-keys: ${{ runner.os }}-m2
|
||||||
|
|
||||||
|
- name: Install system dependencies
|
||||||
|
run: |
|
||||||
|
brew update
|
||||||
|
brew install cmake
|
||||||
|
brew install gcc
|
||||||
|
|
||||||
- name: Build with Maven
|
- name: Build with Maven
|
||||||
run: mvn -B package --file pom.xml
|
run: mvn -B package --file pom.xml
|
||||||
|
|
||||||
|
|||||||
4
.github/workflows/ubuntu-ci.yml
vendored
4
.github/workflows/ubuntu-ci.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
java-version: [8, 11, 21] # 定义要测试的JDK版本
|
java-version: [21] # 定义要测试的JDK版本
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -26,7 +26,7 @@ jobs:
|
|||||||
distribution: 'adopt'
|
distribution: 'adopt'
|
||||||
|
|
||||||
- name: Cache Maven packages
|
- name: Cache Maven packages
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.m2
|
path: ~/.m2
|
||||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||||
|
|||||||
4
.github/workflows/windows-ci.yml
vendored
4
.github/workflows/windows-ci.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
java-version: [8, 11, 21] # Add JDK 21 to the matrix
|
java-version: [21] # Add JDK 21 to the matrix
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -26,7 +26,7 @@ jobs:
|
|||||||
distribution: 'adopt' # You might need to change this if 'adopt' doesn't support JDK 21
|
distribution: 'adopt' # You might need to change this if 'adopt' doesn't support JDK 21
|
||||||
|
|
||||||
- name: Cache Maven packages
|
- name: Cache Maven packages
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~\.m2 # Windows uses a backslash for paths
|
path: ~\.m2 # Windows uses a backslash for paths
|
||||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -20,3 +20,5 @@ chm_db/
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
/dict
|
/dict
|
||||||
assembly/build/*-SNAPSHOT
|
assembly/build/*-SNAPSHOT
|
||||||
|
**/node_modules/
|
||||||
|
benchmark/res/
|
||||||
@@ -7,11 +7,11 @@
|
|||||||
## SuperSonic [0.9.8] - 2024-11-01
|
## SuperSonic [0.9.8] - 2024-11-01
|
||||||
- Add LLM management module to reuse connection across agents.
|
- Add LLM management module to reuse connection across agents.
|
||||||
- Add ChatAPP configuration sub-module in Agent Management.
|
- Add ChatAPP configuration sub-module in Agent Management.
|
||||||
- Add dimension value management sub-module.
|
- Enhance dimension value management sub-module.
|
||||||
- Enhance memory management and term management sub-module.
|
- Enhance memory management and term management sub-module.
|
||||||
- Support semantic translation of complex S2SQL.
|
- Enhance semantic translation of complex S2SQL.
|
||||||
|
- Enhance user experience in Chat UI.
|
||||||
- Introduce LLM-based semantic corrector and data interpreter.
|
- Introduce LLM-based semantic corrector and data interpreter.
|
||||||
- Introduce new experience in Chat UI.
|
|
||||||
|
|
||||||
## SuperSonic [0.9.2] - 2024-06-01
|
## SuperSonic [0.9.2] - 2024-06-01
|
||||||
|
|
||||||
|
|||||||
488
LICENSE
488
LICENSE
@@ -1,489 +1,41 @@
|
|||||||
SuperSonic is licensed under the MIT License, with the following additional conditions:
|
Apache License Version 2.0
|
||||||
|
|
||||||
1. You may provide SuperSonic to third parties as a commercial software or service. However,
|
Copyright (2025) The SuperSonic Project Authors. All rights reserved.
|
||||||
when the following conditions are met, you must contact the producer to obtain a commercial license:
|
|
||||||
|
|
||||||
a. Multi-tenant SaaS service: Unless explicitly authorized by SuperSonic in writing, you may not use the
|
----------
|
||||||
SuperSonic source code to operate a multi-tenant SaaS service.
|
|
||||||
b. LOGO and copyright information: In the process of using SuperSonic, you may not remove or modify
|
SuperSonic is licensed under the Apache License 2.0, with the following additional conditions:
|
||||||
the LOGO or copyright information on the SuperSonic UI. This restriction is inapplicable to uses of
|
|
||||||
SuperSonic that do not involve its frontend components.
|
1. The commercial usage of SuperSonic:
|
||||||
|
|
||||||
|
a. SuperSonic may be utilized commercially, including as a frontend and backend service without modifying the source
|
||||||
|
code and logo.
|
||||||
|
|
||||||
|
b. a commercial license must be obtained from the author if you want to develop and distribute a derivative work based
|
||||||
|
on SuperSonic.
|
||||||
|
|
||||||
|
Please contact supersonicbi@qq.com by email to inquire about licensing matters.
|
||||||
|
|
||||||
Please contact jerryjzhang@tencent.com by email to inquire about licensing matters.
|
|
||||||
|
|
||||||
2. As a contributor, you should agree that:
|
2. As a contributor, you should agree that:
|
||||||
|
|
||||||
a. The producer can adjust the open-source agreement to be more strict or relaxed as deemed necessary.
|
a. The producer can adjust the open-source agreement to be more strict or relaxed as deemed necessary.
|
||||||
b. Your contributed code may be used for commercial purposes, including but not limited to its business operations.
|
|
||||||
|
|
||||||
Terms of the MIT License:
|
b. Your contributed code may be used for commercial purposes, including but not limited to its cloud edition.
|
||||||
--------------------------------------------------------------------
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2023 Tencent Music Entertainment
|
Apart from the specific conditions mentioned above, all other rights and restrictions follow the Apache License 2.0.
|
||||||
|
Detailed information about the Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
----------
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
|
|
||||||
Other dependencies and licenses:
|
|
||||||
|
|
||||||
|
|
||||||
Open Source Software Licensed under the MIT License:
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
1. Mybatis-PageHelper 1.2.10
|
|
||||||
Copyright (c) 2014-2022 abel533@gmail.com
|
|
||||||
|
|
||||||
2. lombok
|
|
||||||
Copyright (C) 2009-2021 The Project Lombok Authors.
|
|
||||||
|
|
||||||
3. react
|
|
||||||
Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
|
|
||||||
4. ant-design
|
|
||||||
Copyright (c) 2015-present Ant UED, https://xtech.antfin.com/
|
|
||||||
|
|
||||||
5. ant-design-pro
|
|
||||||
Copyright (c) 2019 Alipay.inc
|
|
||||||
|
|
||||||
6. @ant-design/charts
|
|
||||||
Copyright (c) 2021 Ant Design
|
|
||||||
|
|
||||||
7. @ant-design/icons
|
|
||||||
Copyright (c) 2018-present Ant UED, https://xtech.antfin.com/
|
|
||||||
|
|
||||||
8. @antv/layout
|
|
||||||
Copyright (c) 2018 Alipay.inc
|
|
||||||
|
|
||||||
9. @antv/xflow
|
|
||||||
Copyright (c) 2021-2023 Alipay.inc
|
|
||||||
|
|
||||||
10. umi
|
|
||||||
Copyright (c) 2017-present ChenCheng (sorrycc@gmail.com)
|
|
||||||
|
|
||||||
11. @umijs/route-utils
|
|
||||||
Copyright (c) 2019-present chenshuai2144 (qixian.cs@outlook.com)
|
|
||||||
|
|
||||||
12. ahooks
|
|
||||||
Copyright (c) 2020 ahooks
|
|
||||||
|
|
||||||
13. axios
|
|
||||||
Copyright (c) 2014-present Matt Zabriskie & Collaborators
|
|
||||||
|
|
||||||
14. classnames
|
|
||||||
Copyright (c) 2018 Jed Watson
|
|
||||||
|
|
||||||
15. crypto-js
|
|
||||||
Copyright (c) 2009-2013 Jeff Mott
|
|
||||||
Copyright (c) 2013-2016 Evan Vosberg
|
|
||||||
|
|
||||||
16. immutability-helper
|
|
||||||
Copyright (c) 2017 Moshe Kolodny
|
|
||||||
|
|
||||||
17. lodash
|
|
||||||
Copyright JS Foundation and other contributors <https://js.foundation/>
|
|
||||||
|
|
||||||
18. moment
|
|
||||||
Copyright (c) JS Foundation and other contributors
|
|
||||||
|
|
||||||
19. numeral
|
|
||||||
Copyright (c) 2016 Adam Draper
|
|
||||||
|
|
||||||
20. omit.js
|
|
||||||
Copyright (c) 2016 Benjy Cui
|
|
||||||
|
|
||||||
21. rc-menu
|
|
||||||
Copyright (c) 2014-present yiminghe
|
|
||||||
|
|
||||||
22. rc-util
|
|
||||||
Copyright (c) 2014-present yiminghe
|
|
||||||
Copyright (c) 2015-present Alipay.com, https://www.alipay.com/
|
|
||||||
|
|
||||||
23. react-ace
|
|
||||||
Copyright (c) 2014 James Hrisho
|
|
||||||
|
|
||||||
24. react-dev-inspector
|
|
||||||
Copyright (c) zthxxx (https://blog.zthxxx.me)
|
|
||||||
|
|
||||||
25. react-lazyload
|
|
||||||
Copyright (c) 2015 Sen Yang
|
|
||||||
|
|
||||||
26. react-spinners
|
|
||||||
Copyright (c) 2017 David Hu
|
|
||||||
|
|
||||||
27.react-split-pane
|
|
||||||
Copyright (c) 2015 tomkp
|
|
||||||
|
|
||||||
28. snappyjs
|
|
||||||
Copyright (c) 2016 Zhipeng Jia
|
|
||||||
|
|
||||||
29. sql-formatter
|
|
||||||
Copyright (c) 2016-2020 ZeroTurnaround LLC
|
|
||||||
Copyright (c) 2020-2021 George Leslie-Waksman and other contributors
|
|
||||||
Copyright (c) 2021-Present inferrinizzard and other contributors
|
|
||||||
|
|
||||||
30. @ant-design/pro-cli
|
|
||||||
Copyright (c) 2017-2018 Alipay
|
|
||||||
|
|
||||||
31. cross-env
|
|
||||||
Copyright (c) 2017 Kent C. Dodds
|
|
||||||
|
|
||||||
32.cross-port-killer
|
|
||||||
Copyright (c) 2017 Rafael Milewski
|
|
||||||
|
|
||||||
33.detect-installer
|
|
||||||
Copyright (c) 2019-present chenshuai2144 (qixian.cs@outlook.com)
|
|
||||||
|
|
||||||
34.eslint
|
|
||||||
Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
|
|
||||||
|
|
||||||
35.express
|
|
||||||
Copyright (c) 2009-2014 TJ Holowaychuk <tj@vision-media.ca>
|
|
||||||
Copyright (c) 2013-2014 Roman Shtylman <shtylman+expressjs@gmail.com>
|
|
||||||
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
|
|
||||||
|
|
||||||
36.gh-pages
|
|
||||||
Copyright (c) 2014 Tim Schaub
|
|
||||||
|
|
||||||
37.inflect
|
|
||||||
Copyright (C) 2020 Pavan Kumar Sunkara
|
|
||||||
|
|
||||||
38.lint-staged
|
|
||||||
Copyright (c) 2016 Andrey Okonetchnikov
|
|
||||||
|
|
||||||
39.prettier
|
|
||||||
Copyright © James Long and contributors
|
|
||||||
|
|
||||||
40.stylelint
|
|
||||||
Copyright (c) 2015 - present Maxime Thirouin, David Clark & Richard Hallows
|
|
||||||
|
|
||||||
41.umi-serve
|
|
||||||
Copyright (c) 2017-present ChenCheng (sorrycc@gmail.com)
|
|
||||||
|
|
||||||
42.webpack
|
|
||||||
Copyright JS Foundation and other contributors
|
|
||||||
|
|
||||||
43.react-dnd
|
|
||||||
Copyright (c) 2015 Dan Abramov
|
|
||||||
|
|
||||||
44.react-grid-layout
|
|
||||||
Copyright (c) 2016 Samuel Reed
|
|
||||||
|
|
||||||
45.slat
|
|
||||||
Copyright © 2016–2023, Ian Storm Taylor
|
|
||||||
|
|
||||||
46.html2canvas
|
|
||||||
Copyright (c) 2012 Niklas von Hertzen
|
|
||||||
|
|
||||||
47.core-js
|
|
||||||
Copyright (c) 2014-2020 Denis Pushkarev
|
|
||||||
|
|
||||||
48.immer 4.0.2
|
|
||||||
Copyright (c) 2017 Michel Weststrate
|
|
||||||
|
|
||||||
49.redux
|
|
||||||
Copyright (c) 2015-present Dan Abramov
|
|
||||||
The Redux logo is dedicated to the public domain and licensed under CC0.
|
|
||||||
|
|
||||||
50.redux-saga
|
|
||||||
Copyright (c) 2015 Yassine Elouafi
|
|
||||||
The Redux-Saga logo is dedicated to the public domain and licensed under CC0.
|
|
||||||
|
|
||||||
51.ts-loader
|
|
||||||
Copyright (c) 2015 TypeStrong
|
|
||||||
|
|
||||||
52.minimist
|
|
||||||
Files:https://github.com/minimistjs/minimist/tree/v1.2.3
|
|
||||||
License Details:https://github.com/minimistjs/minimist/blob/main/LICENSE
|
|
||||||
|
|
||||||
53.intl
|
|
||||||
copyright (c) 2013 Andy Earnshaw
|
|
||||||
|
|
||||||
|
|
||||||
A copy of the MIT License is included in this file.
|
|
||||||
|
|
||||||
|
|
||||||
Open Source Software Licensed under the Apache License Version 2.0:
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
1. HanLP
|
|
||||||
Files: https://github.com/hankcs/HanLP/tree/v1.8.3
|
|
||||||
License Details: https://github.com/hankcs/HanLP/blob/v1.8.3/LICENSE
|
|
||||||
|
|
||||||
2. mybatis
|
|
||||||
iBATIS
|
|
||||||
This product includes software developed by
|
|
||||||
The Apache Software Foundation (http://www.apache.org/).
|
|
||||||
|
|
||||||
Copyright 2010 The Apache Software Foundation
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
3. guava
|
|
||||||
Files: https://github.com/google/guava/tree/v20.0
|
|
||||||
License Details: https://github.com/google/guava/blob/master/LICENSE
|
|
||||||
|
|
||||||
4. hadoop
|
|
||||||
This product includes software developed by The Apache Software Foundation (http://www.apache.org/).
|
|
||||||
|
|
||||||
5. Jackson
|
|
||||||
Files: https://github.com/FasterXML/jackson-core/tree/2.11
|
|
||||||
License Details: https://github.com/FasterXML/jackson-core/blob/2.11/LICENSE
|
|
||||||
|
|
||||||
6. commons-lang
|
|
||||||
Apache Commons Lang
|
|
||||||
Copyright 2001-2017 The Apache Software Foundation
|
|
||||||
|
|
||||||
This product includes software developed at
|
|
||||||
The Apache Software Foundation (http://www.apache.org/).
|
|
||||||
|
|
||||||
This product includes software from the Spring Framework,
|
|
||||||
under the Apache License 2.0 (see: StringUtils.containsWhitespace())
|
|
||||||
|
|
||||||
7. testng
|
|
||||||
Files:https://github.com/testng-team/testng/tree/6.13.1
|
|
||||||
License Details:https://github.com/testng-team/testng/blob/6.13.1/LICENSE.txt
|
|
||||||
|
|
||||||
8. jackson-dataformat-yaml
|
|
||||||
Files:https://github.com/FasterXML/jackson-dataformat-yaml/tree/jackson-dataformat-yaml-2.8.11
|
|
||||||
License Details:https://www.apache.org/licenses/LICENSE-2.0.txt
|
|
||||||
|
|
||||||
9. druid
|
|
||||||
Copyright 1999-2018 Alibaba Group Holding Ltd.
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
10. davinci
|
|
||||||
Licensed to Apereo under one or more contributor license
|
|
||||||
agreements. See the NOTICE file distributed with this work
|
|
||||||
for additional information regarding copyright ownership.
|
|
||||||
Apereo licenses this file to you under the Apache License,
|
|
||||||
Version 2.0 (the "License"); you may not use this file
|
|
||||||
except in compliance with the License. You may obtain a
|
|
||||||
copy of the License at the following location:
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
|
|
||||||
11. echarts
|
|
||||||
Apache ECharts
|
|
||||||
Copyright 2017-2023 The Apache Software Foundation
|
|
||||||
|
|
||||||
This product includes software developed at
|
|
||||||
The Apache Software Foundation (https://www.apache.org/).
|
|
||||||
|
|
||||||
12. echarts-wordcloud
|
|
||||||
Apache ECharts
|
|
||||||
Copyright 2017-2023 The Apache Software Foundation
|
|
||||||
|
|
||||||
This product includes software developed at
|
|
||||||
The Apache Software Foundation (https://www.apache.org/).
|
|
||||||
|
|
||||||
13. carlo
|
|
||||||
Files:https://github.com/GoogleChromeLabs/carlo
|
|
||||||
License Details:https://github.com/GoogleChromeLabs/carlo/blob/master/LICENSE
|
|
||||||
|
|
||||||
14. puppeteer-core
|
|
||||||
Copyright 2017 Google Inc.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
15. swagger-ui-react
|
|
||||||
swagger-ui
|
|
||||||
Copyright 2020-2021 SmartBear Software Inc.
|
|
||||||
|
|
||||||
16. typescript
|
|
||||||
files:https://github.com/microsoft/TypeScript
|
|
||||||
License Details:https://github.com/microsoft/TypeScript/blob/main/LICENSE.txt
|
|
||||||
|
|
||||||
17. io.jsonwebtoken
|
|
||||||
Copyright (C) 2014 jsonwebtoken.io
|
|
||||||
Files: https://repo1.maven.org/maven2/io/jsonwebtoken/jjwt/0.9.1/jjwt-0.9.1.jar
|
|
||||||
|
|
||||||
|
|
||||||
Terms of the Apache License Version 2.0:
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
Apache License
|
|
||||||
|
|
||||||
Version 2.0, January 2004
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
|
||||||
|
|
||||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
|
||||||
|
|
||||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
|
||||||
|
|
||||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
|
|
||||||
Open Source Software Licensed under the Modified BSD License:
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
1. node-sha1
|
|
||||||
Copyright © 2009, Jeff Mott. All rights reserved.
|
|
||||||
Copyright © 2011, Paul Vorbach. All rights reserved.
|
|
||||||
|
|
||||||
This project is licensed under the terms of the Modified BSD License, as follows:
|
|
||||||
-------------------------------------------------------------------
|
|
||||||
|
|
||||||
Copyright (c) 2005-2023, NumPy Developers.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
Redistributions in binary form must reproduce the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer in the documentation and/or
|
|
||||||
other materials provided with the distribution.
|
|
||||||
|
|
||||||
Neither the name oCrypto-JS nor the names of any contributors
|
|
||||||
may be used to endorse or promote products derived from this
|
|
||||||
software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
2. ace-builds
|
|
||||||
Copyright (c) 2010, Ajax.org B.V.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
This project is licensed under the terms of the Modified BSD License, as follows:
|
|
||||||
-------------------------------------------------------------------
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of Ajax.org B.V. nor the
|
|
||||||
names of its contributors may be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
|
||||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
|
|
||||||
Other Open Source Software:
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
1. jsencrypt
|
|
||||||
Files:https://github.com/travist/jsencrypt
|
|
||||||
License Details:https://github.com/travist/jsencrypt/blob/master/LICENSE.txt
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
# SuperSonic
|
# SuperSonic
|
||||||
|
|
||||||
SuperSonic is the next-generation BI platform that unifies **Chat BI** (powered by LLM) and **Headless BI** (powered by semantic layer) paradigms. This unification ensures that Chat BI has access to the same curated and governed semantic data models as traditional BI. Furthermore, the implementation of both paradigms benefit from each other:
|
SuperSonic is the next-generation AI+BI platform that unifies **Chat BI** (powered by LLM) and **Headless BI** (powered by semantic layer) paradigms. This unification ensures that Chat BI has access to the same curated and governed semantic data models as traditional BI. Furthermore, the implementation of both paradigms benefit from each other:
|
||||||
|
|
||||||
- Chat BI's Text2SQL gets augmented with context-retrieval from semantic models.
|
- Chat BI's Text2SQL gets augmented with context-retrieval from semantic models.
|
||||||
- Headless BI's query interface gets extended with natural language API.
|
- Headless BI's query interface gets extended with natural language API.
|
||||||
@@ -75,7 +75,7 @@ SuperSonic comes with sample semantic models as well as chat conversations that
|
|||||||
|
|
||||||
## Build and Development
|
## Build and Development
|
||||||
|
|
||||||
Please refer to project [Docs](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E7%BC%96%E8%AF%91%E6%9E%84%E5%BB%BA/).
|
Please refer to project [Docs](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E9%83%A8%E7%BD%B2/).
|
||||||
|
|
||||||
## WeChat Contact
|
## WeChat Contact
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ SuperSonic自带样例的语义模型和问答对话,只需以下三步即可
|
|||||||
|
|
||||||
## 如何构建和部署
|
## 如何构建和部署
|
||||||
|
|
||||||
请参考项目[文档](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E7%BC%96%E8%AF%91%E6%9E%84%E5%BB%BA/)。
|
请参考项目[文档](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E9%83%A8%E7%BD%B2/)。
|
||||||
|
|
||||||
## 微信联系方式
|
## 微信联系方式
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ SuperSonicには、サンプルのセマンティックモデルとチャット
|
|||||||
|
|
||||||
## ビルドと開発
|
## ビルドと開発
|
||||||
|
|
||||||
プロジェクト[ドキュメント](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E7%BC%96%E8%AF%91%E6%9E%84%E5%BB%BA/)を参照してください。
|
プロジェクト[ドキュメント](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E9%83%A8%E7%BD%B2/)を参照してください。
|
||||||
|
|
||||||
## WeChat連絡先
|
## WeChat連絡先
|
||||||
|
|
||||||
|
|||||||
@@ -43,10 +43,26 @@ if "%service%"=="webapp" (
|
|||||||
call mvn -f %projectDir% clean package -DskipTests -Dspotless.skip=true
|
call mvn -f %projectDir% clean package -DskipTests -Dspotless.skip=true
|
||||||
IF ERRORLEVEL 1 (
|
IF ERRORLEVEL 1 (
|
||||||
ECHO Failed to build backend Java modules.
|
ECHO Failed to build backend Java modules.
|
||||||
|
ECHO Please check Maven and Java versions are compatible.
|
||||||
|
ECHO Current Java: %JAVA_HOME%
|
||||||
|
ECHO Current Maven: %MAVEN_HOME%
|
||||||
EXIT /B 1
|
EXIT /B 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
REM extract and copy files to deployment directory
|
||||||
|
cd %projectDir%\launchers\%model_name%\target
|
||||||
|
if exist "launchers-%model_name%-%MVN_VERSION%-bin.tar.gz" (
|
||||||
|
echo "Extracting launchers-%model_name%-%MVN_VERSION%-bin.tar.gz..."
|
||||||
|
tar -xf "launchers-%model_name%-%MVN_VERSION%-bin.tar.gz"
|
||||||
|
if exist "launchers-%model_name%-%MVN_VERSION%" (
|
||||||
|
echo "Copying files to deployment directory..."
|
||||||
|
xcopy /E /Y "launchers-%model_name%-%MVN_VERSION%\*" "%buildDir%\supersonic-%model_name%-%MVN_VERSION%\"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
copy /y %projectDir%\launchers\%model_name%\target\*.tar.gz %buildDir%\
|
copy /y %projectDir%\launchers\%model_name%\target\*.tar.gz %buildDir%\
|
||||||
echo "finished building supersonic-%model_name% service"
|
echo "finished building supersonic-%model_name% service"
|
||||||
|
cd %baseDir%
|
||||||
goto :EOF
|
goto :EOF
|
||||||
|
|
||||||
|
|
||||||
@@ -72,22 +88,55 @@ if "%service%"=="webapp" (
|
|||||||
cd %buildDir%
|
cd %buildDir%
|
||||||
if exist %release_dir% rmdir /s /q %release_dir%
|
if exist %release_dir% rmdir /s /q %release_dir%
|
||||||
if exist %release_dir%.zip del %release_dir%.zip
|
if exist %release_dir%.zip del %release_dir%.zip
|
||||||
mkdir %release_dir%
|
|
||||||
rem package webapp
|
rem check if release directory already exists from buildJavaService
|
||||||
tar xvf supersonic-webapp.tar.gz
|
if exist %release_dir% (
|
||||||
move /y supersonic-webapp webapp
|
echo "Release directory already prepared by buildJavaService"
|
||||||
echo {"env": ""} > webapp\supersonic.config.json
|
) else (
|
||||||
move /y webapp %release_dir%
|
mkdir %release_dir%
|
||||||
rem package java service
|
|
||||||
tar xvf %service_name%-bin.tar.gz
|
rem package java service
|
||||||
for /d %%D in ("%service_name%\*") do (
|
tar xvf %service_name%-bin.tar.gz 2>nul
|
||||||
move "%%D" "%release_dir%"
|
if errorlevel 1 (
|
||||||
|
echo "Warning: tar command failed, trying PowerShell extraction..."
|
||||||
|
powershell -Command "Expand-Archive -Path '%service_name%-bin.tar.gz' -DestinationPath '.' -Force"
|
||||||
|
)
|
||||||
|
for /d %%D in ("%service_name%\*") do (
|
||||||
|
move "%%D" "%release_dir%"
|
||||||
|
)
|
||||||
|
rmdir /s /q %service_name% 2>nul
|
||||||
)
|
)
|
||||||
|
|
||||||
|
rem package webapp
|
||||||
|
if exist supersonic-webapp.tar.gz (
|
||||||
|
tar xvf supersonic-webapp.tar.gz 2>nul
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo "Warning: tar command failed, trying PowerShell extraction..."
|
||||||
|
powershell -Command "Expand-Archive -Path 'supersonic-webapp.tar.gz' -DestinationPath '.' -Force"
|
||||||
|
)
|
||||||
|
move /y supersonic-webapp webapp
|
||||||
|
echo {"env": ""} > webapp\supersonic.config.json
|
||||||
|
move /y webapp %release_dir%
|
||||||
|
del supersonic-webapp.tar.gz 2>nul
|
||||||
|
)
|
||||||
|
|
||||||
|
rem verify deployment structure
|
||||||
|
if exist "%release_dir%\lib\launchers-%model_name%-%MVN_VERSION%.jar" (
|
||||||
|
echo "Deployment structure verified successfully"
|
||||||
|
) else (
|
||||||
|
echo "Warning: Main jar file not found in deployment structure"
|
||||||
|
echo "Expected: %release_dir%\lib\launchers-%model_name%-%MVN_VERSION%.jar"
|
||||||
|
)
|
||||||
|
|
||||||
rem generate zip file
|
rem generate zip file
|
||||||
powershell Compress-Archive -Path %release_dir% -DestinationPath %release_dir%.zip
|
powershell -Command "Compress-Archive -Path '%release_dir%' -DestinationPath '%release_dir%.zip' -Force"
|
||||||
del %service_name%-bin.tar.gz
|
if errorlevel 1 (
|
||||||
del supersonic-webapp.tar.gz
|
echo "Warning: PowerShell compression failed, release directory still available: %release_dir%"
|
||||||
rmdir /s /q %service_name%
|
) else (
|
||||||
|
echo "Successfully created release package: %release_dir%.zip"
|
||||||
|
)
|
||||||
|
|
||||||
|
del %service_name%-bin.tar.gz 2>nul
|
||||||
echo "finished packaging supersonic release"
|
echo "finished packaging supersonic release"
|
||||||
goto :EOF
|
goto :EOF
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,13 @@ sbinDir=$(cd "$(dirname "$0")"; pwd)
|
|||||||
chmod +x $sbinDir/supersonic-common.sh
|
chmod +x $sbinDir/supersonic-common.sh
|
||||||
source $sbinDir/supersonic-common.sh
|
source $sbinDir/supersonic-common.sh
|
||||||
cd $projectDir
|
cd $projectDir
|
||||||
MVN_VERSION=$(mvn help:evaluate -Dexpression=project.version | grep -e '^[^\[]')
|
|
||||||
|
MVN_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout | grep -v '^\[' | sed -n '/^[0-9]/p')
|
||||||
|
if [ -z "$MVN_VERSION" ]; then
|
||||||
|
echo "Failed to retrieve Maven project version."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Maven project version: $MVN_VERSION"
|
||||||
|
|
||||||
cd $baseDir
|
cd $baseDir
|
||||||
service=$1
|
service=$1
|
||||||
@@ -29,12 +35,17 @@ function buildWebapp {
|
|||||||
chmod +x $projectDir/webapp/start-fe-prod.sh
|
chmod +x $projectDir/webapp/start-fe-prod.sh
|
||||||
cd $projectDir/webapp
|
cd $projectDir/webapp
|
||||||
sh ./start-fe-prod.sh
|
sh ./start-fe-prod.sh
|
||||||
cp -fr ./supersonic-webapp.tar.gz ${buildDir}/
|
|
||||||
# check build result
|
# check build result
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Failed to build frontend webapp."
|
echo "Failed to build frontend webapp."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
cp -fr ./supersonic-webapp.tar.gz ${buildDir}/
|
||||||
|
# check build result
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Failed to get supersonic webapp package."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
echo "finished building supersonic webapp"
|
echo "finished building supersonic webapp"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +61,11 @@ function packageRelease {
|
|||||||
# package webapp
|
# package webapp
|
||||||
tar xvf supersonic-webapp.tar.gz
|
tar xvf supersonic-webapp.tar.gz
|
||||||
mv supersonic-webapp webapp
|
mv supersonic-webapp webapp
|
||||||
|
# check webapp build result
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Failed to get supersonic webapp package."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
json='{"env": "''"}'
|
json='{"env": "''"}'
|
||||||
echo $json > webapp/supersonic.config.json
|
echo $json > webapp/supersonic.config.json
|
||||||
mv webapp $release_dir/
|
mv webapp $release_dir/
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ chcp 65001
|
|||||||
|
|
||||||
set "sbinDir=%~dp0"
|
set "sbinDir=%~dp0"
|
||||||
call %sbinDir%/supersonic-common.bat %*
|
call %sbinDir%/supersonic-common.bat %*
|
||||||
|
call %sbinDir%/supersonic-env.bat %*
|
||||||
|
|
||||||
set "command=%~1"
|
set "command=%~1"
|
||||||
set "service=%~2"
|
set "service=%~2"
|
||||||
@@ -14,12 +15,14 @@ if "%service%"=="" (
|
|||||||
)
|
)
|
||||||
|
|
||||||
if "%profile%"=="" (
|
if "%profile%"=="" (
|
||||||
set "profile=local"
|
set "profile=%S2_DB_TYPE%"
|
||||||
)
|
)
|
||||||
|
|
||||||
set "model_name=%service%"
|
set "model_name=%service%"
|
||||||
|
|
||||||
cd %baseDir%
|
REM fix path configuration - point to the correct release package directory
|
||||||
|
set "releaseDir=%buildDir%\supersonic-%service%-1.0.0-SNAPSHOT"
|
||||||
|
cd %releaseDir%
|
||||||
|
|
||||||
if "%command%"=="restart" (
|
if "%command%"=="restart" (
|
||||||
call :stop
|
call :stop
|
||||||
@@ -49,19 +52,58 @@ if "%command%"=="restart" (
|
|||||||
|
|
||||||
:runJavaService
|
:runJavaService
|
||||||
echo 'java service starting, see logs in logs/'
|
echo 'java service starting, see logs in logs/'
|
||||||
set "libDir=%baseDir%\lib"
|
echo 'Using release directory: %releaseDir%'
|
||||||
set "confDir=%baseDir%\conf"
|
|
||||||
set "webDir=%baseDir%\webapp"
|
REM use release package directory as base path
|
||||||
set "logDir=%baseDir%\logs"
|
set "libDir=%releaseDir%\lib"
|
||||||
set "classpath=%baseDir%;%webDir%;%libDir%\*;%confDir%"
|
set "confDir=%releaseDir%\conf"
|
||||||
set "java-command=-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dspring.profiles.active=%profile% -Xms1024m -Xmx1024m -cp %CLASSPATH% %MAIN_CLASS%"
|
set "webDir=%releaseDir%\webapp"
|
||||||
|
set "logDir=%releaseDir%\logs"
|
||||||
|
|
||||||
|
REM fix variable name matching problem
|
||||||
|
set "CLASSPATH=%releaseDir%;%webDir%;%libDir%\*;%confDir%"
|
||||||
|
set "MAIN_CLASS=%main_class%"
|
||||||
|
|
||||||
|
REM add port configuration
|
||||||
|
set "property=-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dspring.profiles.active=%profile% -Dserver.port=9080"
|
||||||
|
set "java_command=%property% -Xms1024m -Xmx2048m -cp "%CLASSPATH%" %MAIN_CLASS%"
|
||||||
|
|
||||||
if not exist %logDir% mkdir %logDir%
|
if not exist %logDir% mkdir %logDir%
|
||||||
start /B java %java-command% >nul 2>&1
|
|
||||||
timeout /t 10 >nul
|
REM check if the main jar file exists
|
||||||
|
if not exist "%libDir%\launchers-standalone-1.0.0-SNAPSHOT.jar" (
|
||||||
|
echo "Error: Main jar file not found in %libDir%"
|
||||||
|
echo "Please make sure the application has been built and packaged correctly."
|
||||||
|
goto :EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
echo 'Main Class: %MAIN_CLASS%'
|
||||||
|
echo 'Profile: %profile%'
|
||||||
|
echo 'Starting Java service...'
|
||||||
|
|
||||||
|
REM start service and save logs
|
||||||
|
start /B java %java_command% > "%logDir%\supersonic.log" 2>&1
|
||||||
|
timeout /t 15 >nul
|
||||||
|
|
||||||
|
REM check service status
|
||||||
|
netstat -an | findstr ":9080" >nul
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo "Warning: Port 9080 is not listening"
|
||||||
|
echo "Please check the log file: %logDir%\supersonic.log"
|
||||||
|
if exist "%logDir%\supersonic.log" (
|
||||||
|
echo "Recent log entries:"
|
||||||
|
powershell -Command "Get-Content '%logDir%\supersonic.log' | Select-Object -Last 10"
|
||||||
|
)
|
||||||
|
) else (
|
||||||
|
echo "Service started successfully on port 9080"
|
||||||
|
echo "You can access the application at: http://localhost:9080"
|
||||||
|
)
|
||||||
|
|
||||||
echo 'java service started'
|
echo 'java service started'
|
||||||
goto :EOF
|
goto :EOF
|
||||||
|
|
||||||
:stopJavaService
|
:stopJavaService
|
||||||
|
echo 'Stopping Java service...'
|
||||||
for /f "tokens=2" %%i in ('tasklist ^| findstr /i "java"') do (
|
for /f "tokens=2" %%i in ('tasklist ^| findstr /i "java"') do (
|
||||||
taskkill /PID %%i /F
|
taskkill /PID %%i /F
|
||||||
echo "java service (PID = %%i) is killed."
|
echo "java service (PID = %%i) is killed."
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
sbinDir=$(cd "$(dirname "$0")"; pwd)
|
sbinDir=$(cd "$(dirname "$0")"; pwd)
|
||||||
source $sbinDir/supersonic-common.sh
|
source $sbinDir/supersonic-common.sh
|
||||||
|
source $sbinDir/supersonic-env.sh
|
||||||
|
|
||||||
command=$1
|
command=$1
|
||||||
service=$2
|
service=$2
|
||||||
@@ -12,7 +13,7 @@ if [ -z "$service" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$profile" ]; then
|
if [ -z "$profile" ]; then
|
||||||
profile="local"
|
profile=${S2_DB_TYPE}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
model_name=$service
|
model_name=$service
|
||||||
@@ -59,7 +60,8 @@ function runJavaService {
|
|||||||
JAVA_HOME=$(ls /usr/jdk64/jdk* -d 2>/dev/null | xargs | awk '{print "'$local_app_name'"}')
|
JAVA_HOME=$(ls /usr/jdk64/jdk* -d 2>/dev/null | xargs | awk '{print "'$local_app_name'"}')
|
||||||
fi
|
fi
|
||||||
export PATH=$JAVA_HOME/bin:$PATH
|
export PATH=$JAVA_HOME/bin:$PATH
|
||||||
command="-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dapp_name=${local_app_name} -Xms1024m -Xmx1024m $main_class"
|
command="-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08
|
||||||
|
-Dapp_name=${local_app_name} -Xms1024m -Xmx2048m -XX:+UseZGC -XX:+ZGenerational $main_class"
|
||||||
|
|
||||||
mkdir -p $javaRunDir/logs
|
mkdir -p $javaRunDir/logs
|
||||||
java -Dspring.profiles.active="$profile" $command >/dev/null 2>$javaRunDir/logs/error.log &
|
java -Dspring.profiles.active="$profile" $command >/dev/null 2>$javaRunDir/logs/error.log &
|
||||||
|
|||||||
5
assembly/bin/supersonic-docker-compose.sh
Normal file
5
assembly/bin/supersonic-docker-compose.sh
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
export SUPERSONIC_VERSION=latest
|
||||||
|
|
||||||
|
docker-compose -f docker-compose.yml -p supersonic up
|
||||||
23
assembly/bin/supersonic-docker-run.sh
Normal file
23
assembly/bin/supersonic-docker-run.sh
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
export SUPERSONIC_VERSION=latest
|
||||||
|
|
||||||
|
#### Set below DB configs to connect to your own database
|
||||||
|
# Supported DB_TYPE: h2, mysql, postgres
|
||||||
|
export S2_DB_TYPE=h2
|
||||||
|
export S2_DB_HOST=
|
||||||
|
export S2_DB_PORT=
|
||||||
|
export S2_DB_USER=
|
||||||
|
export S2_DB_PASSWORD=
|
||||||
|
export S2_DB_DATABASE=
|
||||||
|
|
||||||
|
docker run --rm -it -d \
|
||||||
|
--name supersonic_standalone \
|
||||||
|
-p 9080:9080 \
|
||||||
|
-e S2_DB_TYPE=${S2_DB_TYPE} \
|
||||||
|
-e S2_DB_HOST=${S2_DB_HOST} \
|
||||||
|
-e S2_DB_PORT=${S2_DB_PORT} \
|
||||||
|
-e S2_DB_USER=${S2_DB_USER} \
|
||||||
|
-e S2_DB_PASSWORD=${S2_DB_PASSWORD} \
|
||||||
|
-e S2_DB_DATABASE=${S2_DB_DATABASE} \
|
||||||
|
supersonicbi/supersonic:${SUPERSONIC_VERSION}
|
||||||
8
assembly/bin/supersonic-env.bat
Executable file
8
assembly/bin/supersonic-env.bat
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
:: Set below DB configs to connect to your own database
|
||||||
|
:: Supported DB_TYPE: h2, mysql, postgres
|
||||||
|
set "S2_DB_TYPE=h2"
|
||||||
|
set "S2_DB_HOST="
|
||||||
|
set "S2_DB_PORT="
|
||||||
|
set "S2_DB_USER="
|
||||||
|
set "S2_DB_PASSWORD="
|
||||||
|
set "S2_DB_DATABASE="
|
||||||
11
assembly/bin/supersonic-env.sh
Executable file
11
assembly/bin/supersonic-env.sh
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#### Set below DB configs to connect to your own database
|
||||||
|
# Comment out below exports to config your DB connection
|
||||||
|
# Supported DB_TYPE: h2, mysql, postgres
|
||||||
|
#export S2_DB_TYPE=h2
|
||||||
|
#export S2_DB_HOST=
|
||||||
|
#export S2_DB_PORT=
|
||||||
|
#export S2_DB_USER=
|
||||||
|
#export S2_DB_PASSWORD=
|
||||||
|
#export S2_DB_DATABASE=
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>8</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
<maven.compiler.target>8</maven.compiler.target>
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.tencent.supersonic.auth.api.authentication.adaptor;
|
package com.tencent.supersonic.auth.api.authentication.adaptor;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
||||||
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -21,6 +21,8 @@ public interface UserAdaptor {
|
|||||||
|
|
||||||
void register(UserReq userReq);
|
void register(UserReq userReq);
|
||||||
|
|
||||||
|
void deleteUser(long userId);
|
||||||
|
|
||||||
String login(UserReq userReq, HttpServletRequest request);
|
String login(UserReq userReq, HttpServletRequest request);
|
||||||
|
|
||||||
String login(UserReq userReq, String appKey);
|
String login(UserReq userReq, String appKey);
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ public class AuthenticationConfig {
|
|||||||
@Value("${s2.authentication.include.path:/api}")
|
@Value("${s2.authentication.include.path:/api}")
|
||||||
private String includePath;
|
private String includePath;
|
||||||
|
|
||||||
|
@Value("${s2.authentication.strategy:http}")
|
||||||
|
private String strategy;
|
||||||
|
|
||||||
@Value("${s2.authentication.enable:false}")
|
@Value("${s2.authentication.enable:false}")
|
||||||
private boolean enabled;
|
private boolean enabled;
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.util.Map;
|
|||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_CREATE_TIME;
|
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_CREATE_TIME;
|
||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_IS_ADMIN;
|
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_IS_ADMIN;
|
||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_DISPLAY_NAME;
|
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_DISPLAY_NAME;
|
||||||
|
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_EMAIL;
|
||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_ID;
|
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_ID;
|
||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_NAME;
|
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_NAME;
|
||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_PASSWORD;
|
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_PASSWORD;
|
||||||
@@ -23,7 +24,7 @@ public class UserWithPassword extends User {
|
|||||||
|
|
||||||
public UserWithPassword(Long id, String name, String displayName, String email, String password,
|
public UserWithPassword(Long id, String name, String displayName, String email, String password,
|
||||||
Integer isAdmin) {
|
Integer isAdmin) {
|
||||||
super(id, name, displayName, email, isAdmin);
|
super(id, name, displayName, email, isAdmin, null);
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +39,7 @@ public class UserWithPassword extends User {
|
|||||||
claims.put(TOKEN_USER_NAME, StringUtils.isEmpty(user.getName()) ? "" : user.getName());
|
claims.put(TOKEN_USER_NAME, StringUtils.isEmpty(user.getName()) ? "" : user.getName());
|
||||||
claims.put(TOKEN_USER_PASSWORD,
|
claims.put(TOKEN_USER_PASSWORD,
|
||||||
StringUtils.isEmpty(user.getPassword()) ? "" : user.getPassword());
|
StringUtils.isEmpty(user.getPassword()) ? "" : user.getPassword());
|
||||||
|
claims.put(TOKEN_USER_EMAIL, StringUtils.isEmpty(user.getEmail()) ? "" : user.getEmail());
|
||||||
claims.put(TOKEN_USER_DISPLAY_NAME, user.getDisplayName());
|
claims.put(TOKEN_USER_DISPLAY_NAME, user.getDisplayName());
|
||||||
claims.put(TOKEN_CREATE_TIME, System.currentTimeMillis());
|
claims.put(TOKEN_CREATE_TIME, System.currentTimeMillis());
|
||||||
claims.put(TOKEN_IS_ADMIN, user.getIsAdmin());
|
claims.put(TOKEN_IS_ADMIN, user.getIsAdmin());
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.tencent.supersonic.auth.api.authentication.request;
|
package com.tencent.supersonic.auth.api.authentication.request;
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -12,4 +12,7 @@ public class UserReq {
|
|||||||
|
|
||||||
@NotBlank(message = "password can not be null")
|
@NotBlank(message = "password can not be null")
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
@NotBlank(message = "password can not be null")
|
||||||
|
private String newPassword;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.tencent.supersonic.auth.api.authentication.request;
|
package com.tencent.supersonic.auth.api.authentication.request;
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package com.tencent.supersonic.auth.api.authentication.service;
|
package com.tencent.supersonic.auth.api.authentication.service;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
||||||
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -22,6 +23,8 @@ public interface UserService {
|
|||||||
|
|
||||||
void register(UserReq userCmd);
|
void register(UserReq userCmd);
|
||||||
|
|
||||||
|
void deleteUser(long userId);
|
||||||
|
|
||||||
String login(UserReq userCmd, HttpServletRequest request);
|
String login(UserReq userCmd, HttpServletRequest request);
|
||||||
|
|
||||||
String login(UserReq userCmd, String appKey);
|
String login(UserReq userCmd, String appKey);
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package com.tencent.supersonic.auth.api.authentication.service;
|
package com.tencent.supersonic.auth.api.authentication.service;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
public interface UserStrategy {
|
public interface UserStrategy {
|
||||||
|
|
||||||
|
String getStrategyName();
|
||||||
|
|
||||||
boolean accept(boolean isEnableAuthentication);
|
boolean accept(boolean isEnableAuthentication);
|
||||||
|
|
||||||
User findUser(HttpServletRequest request, HttpServletResponse response);
|
User findUser(HttpServletRequest request, HttpServletResponse response);
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package com.tencent.supersonic.auth.api.authentication.utils;
|
package com.tencent.supersonic.auth.api.authentication.utils;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.service.UserStrategy;
|
import com.tencent.supersonic.auth.api.authentication.service.UserStrategy;
|
||||||
import com.tencent.supersonic.common.config.SystemConfig;
|
import com.tencent.supersonic.common.config.SystemConfig;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
import com.tencent.supersonic.common.service.SystemConfigService;
|
import com.tencent.supersonic.common.service.SystemConfigService;
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
public final class UserHolder {
|
public final class UserHolder {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.adaptor;
|
package com.tencent.supersonic.auth.authentication.adaptor;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.tencent.supersonic.auth.api.authentication.adaptor.UserAdaptor;
|
import com.tencent.supersonic.auth.api.authentication.adaptor.UserAdaptor;
|
||||||
@@ -16,9 +14,12 @@ import com.tencent.supersonic.auth.authentication.utils.TokenService;
|
|||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
import com.tencent.supersonic.common.util.AESEncryptionUtil;
|
import com.tencent.supersonic.common.util.AESEncryptionUtil;
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -91,6 +92,12 @@ public class DefaultUserAdaptor implements UserAdaptor {
|
|||||||
userRepository.addUser(userDO);
|
userRepository.addUser(userDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteUser(long userId) {
|
||||||
|
UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
|
||||||
|
userRepository.deleteUser(userId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String login(UserReq userReq, HttpServletRequest request) {
|
public String login(UserReq userReq, HttpServletRequest request) {
|
||||||
TokenService tokenService = ContextUtils.getBean(TokenService.class);
|
TokenService tokenService = ContextUtils.getBean(TokenService.class);
|
||||||
@@ -103,7 +110,9 @@ public class DefaultUserAdaptor implements UserAdaptor {
|
|||||||
TokenService tokenService = ContextUtils.getBean(TokenService.class);
|
TokenService tokenService = ContextUtils.getBean(TokenService.class);
|
||||||
try {
|
try {
|
||||||
UserWithPassword user = getUserWithPassword(userReq);
|
UserWithPassword user = getUserWithPassword(userReq);
|
||||||
return tokenService.generateToken(UserWithPassword.convert(user), appKey);
|
String token = tokenService.generateToken(UserWithPassword.convert(user), appKey);
|
||||||
|
updateLastLogin(userReq.getName());
|
||||||
|
return token;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("", e);
|
log.error("", e);
|
||||||
throw new RuntimeException("password encrypt error, please try again");
|
throw new RuntimeException("password encrypt error, please try again");
|
||||||
@@ -214,8 +223,9 @@ public class DefaultUserAdaptor implements UserAdaptor {
|
|||||||
new UserWithPassword(userDO.getId(), userDO.getName(), userDO.getDisplayName(),
|
new UserWithPassword(userDO.getId(), userDO.getName(), userDO.getDisplayName(),
|
||||||
userDO.getEmail(), userDO.getPassword(), userDO.getIsAdmin());
|
userDO.getEmail(), userDO.getPassword(), userDO.getIsAdmin());
|
||||||
|
|
||||||
String token =
|
// 使用令牌名称作为生成key ,这样可以区分正常请求和api 请求,api 的令牌失效时间很长,需考虑令牌泄露的情况
|
||||||
tokenService.generateToken(UserWithPassword.convert(userWithPassword), expireTime);
|
String token = tokenService.generateToken(UserWithPassword.convert(userWithPassword),
|
||||||
|
"SysDbToken:" + name, (new Date().getTime() + expireTime));
|
||||||
UserTokenDO userTokenDO = saveUserToken(name, userName, token, expireTime);
|
UserTokenDO userTokenDO = saveUserToken(name, userName, token, expireTime);
|
||||||
return convertUserToken(userTokenDO);
|
return convertUserToken(userTokenDO);
|
||||||
}
|
}
|
||||||
@@ -268,4 +278,11 @@ public class DefaultUserAdaptor implements UserAdaptor {
|
|||||||
userToken.setExpireDate(userTokenDO.getExpireDateTime());
|
userToken.setExpireDate(userTokenDO.getExpireDateTime());
|
||||||
return userToken;
|
return userToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateLastLogin(String userName) {
|
||||||
|
UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
|
||||||
|
UserDO userDO = userRepository.getUser(userName);
|
||||||
|
userDO.setLastLogin(new Timestamp(System.currentTimeMillis()));
|
||||||
|
userRepository.updateUser(userDO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,13 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.interceptor;
|
package com.tencent.supersonic.auth.authentication.interceptor;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
||||||
import com.tencent.supersonic.auth.api.authentication.constant.UserConstants;
|
import com.tencent.supersonic.auth.api.authentication.service.UserService;
|
||||||
import com.tencent.supersonic.auth.authentication.service.UserServiceImpl;
|
|
||||||
import com.tencent.supersonic.auth.authentication.utils.TokenService;
|
import com.tencent.supersonic.auth.authentication.utils.TokenService;
|
||||||
import com.tencent.supersonic.common.util.S2ThreadContext;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.catalina.connector.RequestFacade;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.tomcat.util.http.MimeHeaders;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
|
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -24,12 +16,10 @@ public abstract class AuthenticationInterceptor implements HandlerInterceptor {
|
|||||||
|
|
||||||
protected AuthenticationConfig authenticationConfig;
|
protected AuthenticationConfig authenticationConfig;
|
||||||
|
|
||||||
protected UserServiceImpl userServiceImpl;
|
protected UserService userService;
|
||||||
|
|
||||||
protected TokenService tokenService;
|
protected TokenService tokenService;
|
||||||
|
|
||||||
protected S2ThreadContext s2ThreadContext;
|
|
||||||
|
|
||||||
protected boolean isExcludedUri(String uri) {
|
protected boolean isExcludedUri(String uri) {
|
||||||
String excludePathStr = authenticationConfig.getExcludePath();
|
String excludePathStr = authenticationConfig.getExcludePath();
|
||||||
if (StringUtils.isEmpty(excludePathStr)) {
|
if (StringUtils.isEmpty(excludePathStr)) {
|
||||||
@@ -54,52 +44,4 @@ public abstract class AuthenticationInterceptor implements HandlerInterceptor {
|
|||||||
return includePaths.stream().anyMatch(uri::startsWith);
|
return includePaths.stream().anyMatch(uri::startsWith);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isInternalRequest(HttpServletRequest request) {
|
|
||||||
String internal = request.getHeader(UserConstants.INTERNAL);
|
|
||||||
return "true".equalsIgnoreCase(internal);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isAppRequest(HttpServletRequest request) {
|
|
||||||
String appId = request.getHeader(authenticationConfig.getAppId());
|
|
||||||
return StringUtils.isNotBlank(appId);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void reflectSetParam(HttpServletRequest request, String key, String value) {
|
|
||||||
try {
|
|
||||||
if (request instanceof StandardMultipartHttpServletRequest) {
|
|
||||||
RequestFacade servletRequest =
|
|
||||||
(RequestFacade) ((StandardMultipartHttpServletRequest) request)
|
|
||||||
.getRequest();
|
|
||||||
Class<? extends HttpServletRequest> servletRequestClazz = servletRequest.getClass();
|
|
||||||
Field request1 = servletRequestClazz.getDeclaredField("request");
|
|
||||||
request1.setAccessible(true);
|
|
||||||
Object o = request1.get(servletRequest);
|
|
||||||
Field coyoteRequest = o.getClass().getDeclaredField("coyoteRequest");
|
|
||||||
coyoteRequest.setAccessible(true);
|
|
||||||
Object o1 = coyoteRequest.get(o);
|
|
||||||
Field headers = o1.getClass().getDeclaredField("headers");
|
|
||||||
headers.setAccessible(true);
|
|
||||||
MimeHeaders o2 = (MimeHeaders) headers.get(o1);
|
|
||||||
if (o2.getValue(key) != null) {
|
|
||||||
o2.setValue(key).setString(value);
|
|
||||||
} else {
|
|
||||||
o2.addValue(key).setString(value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Class<? extends HttpServletRequest> requestClass = request.getClass();
|
|
||||||
Field request1 = requestClass.getDeclaredField("request");
|
|
||||||
request1.setAccessible(true);
|
|
||||||
Object o = request1.get(request);
|
|
||||||
Field coyoteRequest = o.getClass().getDeclaredField("coyoteRequest");
|
|
||||||
coyoteRequest.setAccessible(true);
|
|
||||||
Object o1 = coyoteRequest.get(o);
|
|
||||||
Field headers = o1.getClass().getDeclaredField("headers");
|
|
||||||
headers.setAccessible(true);
|
|
||||||
MimeHeaders o2 = (MimeHeaders) headers.get(o1);
|
|
||||||
o2.addValue(key).setString(value);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("reflectSetParam error:", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,22 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.interceptor;
|
package com.tencent.supersonic.auth.authentication.interceptor;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.annotation.AuthenticationIgnore;
|
import com.tencent.supersonic.auth.api.authentication.annotation.AuthenticationIgnore;
|
||||||
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword;
|
import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword;
|
||||||
import com.tencent.supersonic.auth.authentication.service.UserServiceImpl;
|
import com.tencent.supersonic.auth.api.authentication.service.UserService;
|
||||||
import com.tencent.supersonic.auth.authentication.utils.TokenService;
|
import com.tencent.supersonic.auth.authentication.utils.TokenService;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
|
||||||
import com.tencent.supersonic.common.pojo.exception.AccessException;
|
import com.tencent.supersonic.common.pojo.exception.AccessException;
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
import com.tencent.supersonic.common.util.S2ThreadContext;
|
|
||||||
import com.tencent.supersonic.common.util.ThreadContext;
|
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_IS_ADMIN;
|
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.*;
|
||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_DISPLAY_NAME;
|
|
||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_EMAIL;
|
|
||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_ID;
|
|
||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_NAME;
|
|
||||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_PASSWORD;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor {
|
public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor {
|
||||||
@@ -34,21 +25,12 @@ public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor
|
|||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
|
||||||
Object handler) throws AccessException {
|
Object handler) throws AccessException {
|
||||||
authenticationConfig = ContextUtils.getBean(AuthenticationConfig.class);
|
authenticationConfig = ContextUtils.getBean(AuthenticationConfig.class);
|
||||||
userServiceImpl = ContextUtils.getBean(UserServiceImpl.class);
|
userService = ContextUtils.getBean(UserService.class);
|
||||||
tokenService = ContextUtils.getBean(TokenService.class);
|
tokenService = ContextUtils.getBean(TokenService.class);
|
||||||
s2ThreadContext = ContextUtils.getBean(S2ThreadContext.class);
|
|
||||||
if (!authenticationConfig.isEnabled()) {
|
if (!authenticationConfig.isEnabled()) {
|
||||||
setFakerUser(request);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (isInternalRequest(request)) {
|
|
||||||
setFakerUser(request);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (isAppRequest(request)) {
|
|
||||||
setFakerUser(request);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handler instanceof HandlerMethod) {
|
if (handler instanceof HandlerMethod) {
|
||||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||||
Method method = handlerMethod.getMethod();
|
Method method = handlerMethod.getMethod();
|
||||||
@@ -69,35 +51,11 @@ public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor
|
|||||||
|
|
||||||
UserWithPassword user = getUserWithPassword(request);
|
UserWithPassword user = getUserWithPassword(request);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
setContext(user.getName(), request);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
throw new AccessException("authentication failed, please login");
|
throw new AccessException("authentication failed, please login");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setFakerUser(HttpServletRequest request) {
|
|
||||||
String token = generateAdminToken(request);
|
|
||||||
reflectSetParam(request, authenticationConfig.getTokenHttpHeaderKey(), token);
|
|
||||||
setContext(User.getDefaultUser().getName(), request);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setContext(String userName, HttpServletRequest request) {
|
|
||||||
ThreadContext threadContext = ThreadContext.builder()
|
|
||||||
.token(request.getHeader(authenticationConfig.getTokenHttpHeaderKey()))
|
|
||||||
.userName(userName).build();
|
|
||||||
s2ThreadContext.set(threadContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String generateAdminToken(HttpServletRequest request) {
|
|
||||||
UserWithPassword admin = new UserWithPassword("admin");
|
|
||||||
admin.setId(1L);
|
|
||||||
admin.setName("admin");
|
|
||||||
admin.setPassword("c3VwZXJzb25pY0BiaWNvbdktJJYWw6A3rEmBUPzbn/6DNeYnD+y3mAwDKEMS3KVT");
|
|
||||||
admin.setDisplayName("admin");
|
|
||||||
admin.setIsAdmin(1);
|
|
||||||
return tokenService.generateToken(UserWithPassword.convert(admin), request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserWithPassword getUserWithPassword(HttpServletRequest request) {
|
public UserWithPassword getUserWithPassword(HttpServletRequest request) {
|
||||||
final Optional<Claims> claimsOptional = tokenService.getClaims(request);
|
final Optional<Claims> claimsOptional = tokenService.getClaims(request);
|
||||||
if (!claimsOptional.isPresent()) {
|
if (!claimsOptional.isPresent()) {
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.persistence.dataobject;
|
package com.tencent.supersonic.auth.authentication.persistence.dataobject;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("s2_user")
|
||||||
public class UserDO {
|
public class UserDO {
|
||||||
/** */
|
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@@ -21,71 +31,25 @@ public class UserDO {
|
|||||||
/** */
|
/** */
|
||||||
private Integer isAdmin;
|
private Integer isAdmin;
|
||||||
|
|
||||||
/** @return id */
|
private Timestamp lastLogin;
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param id */
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return name */
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param name */
|
/** @param name */
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name == null ? null : name.trim();
|
this.name = name == null ? null : name.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return password */
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param password */
|
/** @param password */
|
||||||
public void setPassword(String password) {
|
public void setPassword(String password) {
|
||||||
this.password = password == null ? null : password.trim();
|
this.password = password == null ? null : password.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSalt() {
|
|
||||||
return salt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSalt(String salt) {
|
public void setSalt(String salt) {
|
||||||
this.salt = salt == null ? null : salt.trim();
|
this.salt = salt == null ? null : salt.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return display_name */
|
|
||||||
public String getDisplayName() {
|
|
||||||
return displayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param displayName */
|
|
||||||
public void setDisplayName(String displayName) {
|
|
||||||
this.displayName = displayName == null ? null : displayName.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return email */
|
|
||||||
public String getEmail() {
|
|
||||||
return email;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param email */
|
/** @param email */
|
||||||
public void setEmail(String email) {
|
public void setEmail(String email) {
|
||||||
this.email = email == null ? null : email.trim();
|
this.email = email == null ? null : email.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return is_admin */
|
|
||||||
public Integer getIsAdmin() {
|
|
||||||
return isAdmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param isAdmin */
|
|
||||||
public void setIsAdmin(Integer isAdmin) {
|
|
||||||
this.isAdmin = isAdmin;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.persistence.mapper;
|
package com.tencent.supersonic.auth.authentication.persistence.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO;
|
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO;
|
||||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDOExample;
|
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDOExample;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
@@ -7,12 +9,8 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface UserDOMapper {
|
public interface UserDOMapper extends BaseMapper<UserDO> {
|
||||||
|
|
||||||
/** @mbg.generated */
|
|
||||||
int insert(UserDO record);
|
|
||||||
|
|
||||||
/** @mbg.generated */
|
|
||||||
List<UserDO> selectByExample(UserDOExample example);
|
List<UserDO> selectByExample(UserDOExample example);
|
||||||
|
|
||||||
void updateByPrimaryKey(UserDO userDO);
|
void updateByPrimaryKey(UserDO userDO);
|
||||||
|
|||||||
@@ -21,7 +21,11 @@ public interface UserRepository {
|
|||||||
|
|
||||||
UserTokenDO getUserToken(Long tokenId);
|
UserTokenDO getUserToken(Long tokenId);
|
||||||
|
|
||||||
|
UserTokenDO getUserTokenByName(String tokenName);
|
||||||
|
|
||||||
void deleteUserTokenByName(String userName);
|
void deleteUserTokenByName(String userName);
|
||||||
|
|
||||||
void deleteUserToken(Long tokenId);
|
void deleteUserToken(Long tokenId);
|
||||||
|
|
||||||
|
void deleteUser(long userId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class UserRepositoryImpl implements UserRepository {
|
|||||||
@Override
|
@Override
|
||||||
public List<UserTokenDO> getUserTokenListByName(String userName) {
|
public List<UserTokenDO> getUserTokenListByName(String userName) {
|
||||||
QueryWrapper<UserTokenDO> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<UserTokenDO> queryWrapper = new QueryWrapper<>();
|
||||||
queryWrapper.eq("user_name", userName);
|
queryWrapper.lambda().eq(UserTokenDO::getUserName, userName);
|
||||||
return userTokenDOMapper.selectList(queryWrapper);
|
return userTokenDOMapper.selectList(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,10 +65,17 @@ public class UserRepositoryImpl implements UserRepository {
|
|||||||
return userTokenDOMapper.selectById(tokenId);
|
return userTokenDOMapper.selectById(tokenId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserTokenDO getUserTokenByName(String tokenName) {
|
||||||
|
QueryWrapper<UserTokenDO> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.lambda().eq(UserTokenDO::getName, tokenName);
|
||||||
|
return userTokenDOMapper.selectOne(queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteUserTokenByName(String userName) {
|
public void deleteUserTokenByName(String userName) {
|
||||||
QueryWrapper<UserTokenDO> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<UserTokenDO> queryWrapper = new QueryWrapper<>();
|
||||||
queryWrapper.eq("user_name", userName);
|
queryWrapper.lambda().eq(UserTokenDO::getUserName, userName);
|
||||||
userTokenDOMapper.delete(queryWrapper);
|
userTokenDOMapper.delete(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,4 +83,9 @@ public class UserRepositoryImpl implements UserRepository {
|
|||||||
public void deleteUserToken(Long tokenId) {
|
public void deleteUserToken(Long tokenId) {
|
||||||
userTokenDOMapper.deleteById(tokenId);
|
userTokenDOMapper.deleteById(tokenId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteUser(long userId) {
|
||||||
|
userDOMapper.deleteById(userId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,15 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.rest;
|
package com.tencent.supersonic.auth.authentication.rest;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
||||||
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
||||||
import com.tencent.supersonic.auth.api.authentication.request.UserTokenReq;
|
import com.tencent.supersonic.auth.api.authentication.request.UserTokenReq;
|
||||||
import com.tencent.supersonic.auth.api.authentication.service.UserService;
|
import com.tencent.supersonic.auth.api.authentication.service.UserService;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -68,11 +61,28 @@ public class UserController {
|
|||||||
userService.register(userCmd);
|
userService.register(userCmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete/{userId}")
|
||||||
|
public void delete(@PathVariable("userId") long userId, HttpServletRequest httpServletRequest,
|
||||||
|
HttpServletResponse httpServletResponse) throws IllegalAccessException {
|
||||||
|
User user = userService.getCurrentUser(httpServletRequest, httpServletResponse);
|
||||||
|
if (user.getIsAdmin() != 1) {
|
||||||
|
throw new IllegalAccessException("only admin can delete user");
|
||||||
|
}
|
||||||
|
userService.deleteUser(userId);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public String login(@RequestBody UserReq userCmd, HttpServletRequest request) {
|
public String login(@RequestBody UserReq userCmd, HttpServletRequest request) {
|
||||||
return userService.login(userCmd, request);
|
return userService.login(userCmd, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/resetPassword")
|
||||||
|
public void resetPassword(@RequestBody UserReq userCmd, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
User user = userService.getCurrentUser(request, response);
|
||||||
|
userService.resetPassword(user.getName(), userCmd.getPassword(), userCmd.getNewPassword());
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/generateToken")
|
@PostMapping("/generateToken")
|
||||||
public UserToken generateToken(@RequestBody UserTokenReq userTokenReq,
|
public UserToken generateToken(@RequestBody UserTokenReq userTokenReq,
|
||||||
HttpServletRequest request, HttpServletResponse response) {
|
HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.service;
|
package com.tencent.supersonic.auth.authentication.service;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
||||||
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
||||||
@@ -12,6 +9,8 @@ import com.tencent.supersonic.auth.authentication.utils.ComponentFactory;
|
|||||||
import com.tencent.supersonic.common.config.SystemConfig;
|
import com.tencent.supersonic.common.config.SystemConfig;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
import com.tencent.supersonic.common.service.SystemConfigService;
|
import com.tencent.supersonic.common.service.SystemConfigService;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
@@ -71,6 +70,11 @@ public class UserServiceImpl implements UserService {
|
|||||||
ComponentFactory.getUserAdaptor().register(userReq);
|
ComponentFactory.getUserAdaptor().register(userReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteUser(long userId) {
|
||||||
|
ComponentFactory.getUserAdaptor().deleteUser(userId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String login(UserReq userReq, HttpServletRequest request) {
|
public String login(UserReq userReq, HttpServletRequest request) {
|
||||||
return ComponentFactory.getUserAdaptor().login(userReq, request);
|
return ComponentFactory.getUserAdaptor().login(userReq, request);
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.strategy;
|
package com.tencent.supersonic.auth.authentication.strategy;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.service.UserStrategy;
|
import com.tencent.supersonic.auth.api.authentication.service.UserStrategy;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class FakeUserStrategy implements UserStrategy {
|
public class FakeUserStrategy implements UserStrategy {
|
||||||
|
|
||||||
|
public static final String STRATEGY_NAME = "fake";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStrategyName() {
|
||||||
|
return STRATEGY_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(boolean isEnableAuthentication) {
|
public boolean accept(boolean isEnableAuthentication) {
|
||||||
return !isEnableAuthentication;
|
return !isEnableAuthentication;
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.strategy;
|
package com.tencent.supersonic.auth.authentication.strategy;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.constant.UserConstants;
|
import com.tencent.supersonic.auth.api.authentication.constant.UserConstants;
|
||||||
import com.tencent.supersonic.auth.api.authentication.service.UserStrategy;
|
import com.tencent.supersonic.auth.api.authentication.service.UserStrategy;
|
||||||
import com.tencent.supersonic.auth.authentication.utils.TokenService;
|
import com.tencent.supersonic.auth.authentication.utils.TokenService;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -15,12 +14,18 @@ import java.util.Optional;
|
|||||||
@Service
|
@Service
|
||||||
public class HttpHeaderUserStrategy implements UserStrategy {
|
public class HttpHeaderUserStrategy implements UserStrategy {
|
||||||
|
|
||||||
|
public static final String STRATEGY_NAME = "http";
|
||||||
private final TokenService tokenService;
|
private final TokenService tokenService;
|
||||||
|
|
||||||
public HttpHeaderUserStrategy(TokenService tokenService) {
|
public HttpHeaderUserStrategy(TokenService tokenService) {
|
||||||
this.tokenService = tokenService;
|
this.tokenService = tokenService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStrategyName() {
|
||||||
|
return STRATEGY_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(boolean isEnableAuthentication) {
|
public boolean accept(boolean isEnableAuthentication) {
|
||||||
return isEnableAuthentication;
|
return isEnableAuthentication;
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.strategy;
|
package com.tencent.supersonic.auth.authentication.strategy;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
||||||
import com.tencent.supersonic.auth.api.authentication.service.UserStrategy;
|
import com.tencent.supersonic.auth.api.authentication.service.UserStrategy;
|
||||||
import com.tencent.supersonic.auth.api.authentication.utils.UserHolder;
|
import com.tencent.supersonic.auth.api.authentication.utils.UserHolder;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Data
|
@Data
|
||||||
@@ -26,10 +27,26 @@ public class UserStrategyFactory {
|
|||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void setUserStrategy() {
|
public void setUserStrategy() {
|
||||||
for (UserStrategy userStrategy : userStrategyList) {
|
|
||||||
if (userStrategy.accept(authenticationConfig.isEnabled())) {
|
boolean enabled = authenticationConfig.isEnabled();
|
||||||
UserHolder.setStrategy(userStrategy);
|
if (!enabled) {
|
||||||
|
for (UserStrategy userStrategy : userStrategyList) {
|
||||||
|
if (userStrategy.accept(authenticationConfig.isEnabled())) {
|
||||||
|
UserHolder.setStrategy(userStrategy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String strategy = authenticationConfig.getStrategy();
|
||||||
|
Optional<UserStrategy> strategyOptional = userStrategyList.stream()
|
||||||
|
.filter(t -> t.accept(true) && strategy.equalsIgnoreCase(t.getStrategyName()))
|
||||||
|
.findAny();
|
||||||
|
|
||||||
|
if (strategyOptional.isPresent()) {
|
||||||
|
UserHolder.setStrategy(strategyOptional.get());
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("strategy is not found: " + strategy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.utils;
|
package com.tencent.supersonic.auth.authentication.utils;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword;
|
import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword;
|
||||||
|
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserTokenDO;
|
||||||
|
import com.tencent.supersonic.auth.authentication.persistence.repository.UserRepository;
|
||||||
import com.tencent.supersonic.common.pojo.exception.AccessException;
|
import com.tencent.supersonic.common.pojo.exception.AccessException;
|
||||||
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.Jwts;
|
||||||
import io.jsonwebtoken.SignatureAlgorithm;
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -69,6 +74,7 @@ public class TokenService {
|
|||||||
return generateToken(UserWithPassword.convert(appUser), request);
|
return generateToken(UserWithPassword.convert(appUser), request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Optional<Claims> getClaims(HttpServletRequest request) {
|
public Optional<Claims> getClaims(HttpServletRequest request) {
|
||||||
String token = request.getHeader(authenticationConfig.getTokenHttpHeaderKey());
|
String token = request.getHeader(authenticationConfig.getTokenHttpHeaderKey());
|
||||||
String appKey = getAppKey(request);
|
String appKey = getAppKey(request);
|
||||||
@@ -88,6 +94,14 @@ public class TokenService {
|
|||||||
|
|
||||||
public Optional<Claims> getClaims(String token, String appKey) {
|
public Optional<Claims> getClaims(String token, String appKey) {
|
||||||
try {
|
try {
|
||||||
|
if (StringUtils.isNotBlank(appKey) && appKey.startsWith("SysDbToken:")) {// 如果是配置的长期令牌,需校验数据库是否存在该配置
|
||||||
|
UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
|
||||||
|
UserTokenDO dbToken =
|
||||||
|
userRepository.getUserTokenByName(appKey.substring("SysDbToken:".length()));
|
||||||
|
if (dbToken == null || !dbToken.getToken().equals(token.replace("Bearer ", ""))) {
|
||||||
|
throw new AccessException("Token does not exist :" + appKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
String tokenSecret = getTokenSecret(appKey);
|
String tokenSecret = getTokenSecret(appKey);
|
||||||
Claims claims =
|
Claims claims =
|
||||||
Jwts.parser().setSigningKey(tokenSecret.getBytes(StandardCharsets.UTF_8))
|
Jwts.parser().setSigningKey(tokenSecret.getBytes(StandardCharsets.UTF_8))
|
||||||
@@ -120,6 +134,16 @@ public class TokenService {
|
|||||||
Map<String, String> appKeyToSecretMap = authenticationConfig.getAppKeyToSecretMap();
|
Map<String, String> appKeyToSecretMap = authenticationConfig.getAppKeyToSecretMap();
|
||||||
String secret = appKeyToSecretMap.get(appKey);
|
String secret = appKeyToSecretMap.get(appKey);
|
||||||
if (StringUtils.isBlank(secret)) {
|
if (StringUtils.isBlank(secret)) {
|
||||||
|
if (StringUtils.isNotBlank(appKey) && appKey.startsWith("SysDbToken:")) { // 是配置的长期令牌
|
||||||
|
String realAppKey = appKey.substring("SysDbToken:".length());
|
||||||
|
String tmp =
|
||||||
|
"WIaO9YRRVt+7QtpPvyWsARFngnEcbaKBk783uGFwMrbJBaochsqCH62L4Kijcb0sZCYoSsiKGV/zPml5MnZ3uQ==";
|
||||||
|
if (tmp.length() <= realAppKey.length()) {
|
||||||
|
return realAppKey;
|
||||||
|
} else {
|
||||||
|
return realAppKey + tmp.substring(realAppKey.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
throw new AccessException("get secret from appKey failed :" + appKey);
|
throw new AccessException("get secret from appKey failed :" + appKey);
|
||||||
}
|
}
|
||||||
return secret;
|
return secret;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<result column="display_name" jdbcType="VARCHAR" property="displayName" />
|
<result column="display_name" jdbcType="VARCHAR" property="displayName" />
|
||||||
<result column="email" jdbcType="VARCHAR" property="email" />
|
<result column="email" jdbcType="VARCHAR" property="email" />
|
||||||
<result column="is_admin" jdbcType="INTEGER" property="isAdmin" />
|
<result column="is_admin" jdbcType="INTEGER" property="isAdmin" />
|
||||||
|
<result column="last_login" jdbcType="TIMESTAMP" property="lastLogin" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<sql id="Example_Where_Clause">
|
<sql id="Example_Where_Clause">
|
||||||
<where>
|
<where>
|
||||||
@@ -40,7 +41,7 @@
|
|||||||
</where>
|
</where>
|
||||||
</sql>
|
</sql>
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, name, password, salt, display_name, email, is_admin
|
id, name, password, salt, display_name, email, is_admin, last_login
|
||||||
</sql>
|
</sql>
|
||||||
<select id="selectByExample" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDOExample" resultMap="BaseResultMap">
|
<select id="selectByExample" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDOExample" resultMap="BaseResultMap">
|
||||||
select
|
select
|
||||||
@@ -59,14 +60,6 @@
|
|||||||
limit #{limitStart} , #{limitEnd}
|
limit #{limitStart} , #{limitEnd}
|
||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
<insert id="insert" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO">
|
|
||||||
insert into s2_user (id, name, password, salt,
|
|
||||||
display_name, email, is_admin
|
|
||||||
)
|
|
||||||
values (#{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, #{salt,jdbcType=VARCHAR},
|
|
||||||
#{displayName,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, #{isAdmin,jdbcType=INTEGER}
|
|
||||||
)
|
|
||||||
</insert>
|
|
||||||
<insert id="insertSelective" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO">
|
<insert id="insertSelective" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO">
|
||||||
insert into s2_user
|
insert into s2_user
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
@@ -144,6 +137,9 @@
|
|||||||
<if test="isAdmin != null">
|
<if test="isAdmin != null">
|
||||||
is_admin = #{isAdmin,jdbcType=INTEGER},
|
is_admin = #{isAdmin,jdbcType=INTEGER},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="lastLogin != null">
|
||||||
|
last_login = #{lastLogin,jdbcType=TIMESTAMP},
|
||||||
|
</if>
|
||||||
</set>
|
</set>
|
||||||
where id = #{id,jdbcType=BIGINT}
|
where id = #{id,jdbcType=BIGINT}
|
||||||
</update>
|
</update>
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
<artifactId>auth-authorization</artifactId>
|
<artifactId>auth-authorization</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>8</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
<maven.compiler.target>8</maven.compiler.target>
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package com.tencent.supersonic.auth.authorization.rest;
|
package com.tencent.supersonic.auth.authorization.rest;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.utils.UserHolder;
|
import com.tencent.supersonic.auth.api.authentication.utils.UserHolder;
|
||||||
import com.tencent.supersonic.auth.api.authorization.pojo.AuthGroup;
|
import com.tencent.supersonic.auth.api.authorization.pojo.AuthGroup;
|
||||||
import com.tencent.supersonic.auth.api.authorization.request.QueryAuthResReq;
|
import com.tencent.supersonic.auth.api.authorization.request.QueryAuthResReq;
|
||||||
import com.tencent.supersonic.auth.api.authorization.response.AuthorizedResourceResp;
|
import com.tencent.supersonic.auth.api.authorization.response.AuthorizedResourceResp;
|
||||||
import com.tencent.supersonic.auth.api.authorization.service.AuthService;
|
import com.tencent.supersonic.auth.api.authorization.service.AuthService;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
|||||||
@@ -15,6 +15,68 @@ import requests
|
|||||||
import time
|
import time
|
||||||
import jwt
|
import jwt
|
||||||
import traceback
|
import traceback
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
class DataFrameAppender:
|
||||||
|
def __init__(self,file_name = "output"):
|
||||||
|
# 定义表头
|
||||||
|
columns = ['问题', '解析状态', '解析耗时', '执行状态', '执行耗时', '总耗时']
|
||||||
|
# 创建只有表头的 DataFrame
|
||||||
|
self.df = pd.DataFrame(columns=columns)
|
||||||
|
self.file_name = file_name
|
||||||
|
|
||||||
|
def append_data(self, new_data):
|
||||||
|
# 假设 new_data 是一维数组,将其转换为字典
|
||||||
|
columns = ['问题', '解析状态', '解析耗时', '执行状态', '执行耗时', '总耗时']
|
||||||
|
new_dict = dict(zip(columns, new_data))
|
||||||
|
# 使用 loc 方法追加数据
|
||||||
|
self.df.loc[len(self.df)] = new_dict
|
||||||
|
def print_analysis_result(self):
|
||||||
|
# 测试样例总数
|
||||||
|
total_samples = len(self.df)
|
||||||
|
|
||||||
|
# 解析成功数量
|
||||||
|
parse_success_count = (self.df['解析状态'] == '解析成功').sum()
|
||||||
|
|
||||||
|
# 执行成功数量
|
||||||
|
execute_success_count = (self.df['执行状态'] == '执行成功').sum()
|
||||||
|
|
||||||
|
# 解析平均耗时,保留两位小数
|
||||||
|
avg_parse_time = round(self.df['解析耗时'].mean(), 2)
|
||||||
|
|
||||||
|
# 执行平均耗时,保留两位小数
|
||||||
|
avg_execute_time = round(self.df['执行耗时'].mean(), 2)
|
||||||
|
|
||||||
|
# 总平均耗时,保留两位小数
|
||||||
|
avg_total_time = round(self.df['总耗时'].mean(), 2)
|
||||||
|
|
||||||
|
# 最长耗时,保留两位小数
|
||||||
|
max_time = round(self.df['总耗时'].max(), 2)
|
||||||
|
|
||||||
|
# 最短耗时,保留两位小数
|
||||||
|
min_time = round(self.df['总耗时'].min(), 2)
|
||||||
|
|
||||||
|
print(f"测试样例总数 : {total_samples}")
|
||||||
|
print(f"解析成功数量 : {parse_success_count}")
|
||||||
|
print(f"执行成功数量 : {execute_success_count}")
|
||||||
|
print(f"解析平均耗时 : {avg_parse_time} 秒")
|
||||||
|
print(f"执行平均耗时 : {avg_execute_time} 秒")
|
||||||
|
print(f"总平均耗时 : {avg_total_time} 秒")
|
||||||
|
print(f"最长耗时 : {max_time} 秒")
|
||||||
|
print(f"最短耗时 : {min_time} 秒")
|
||||||
|
|
||||||
|
def write_to_csv(self):
|
||||||
|
# 检查 data 文件夹是否存在,如果不存在则创建
|
||||||
|
if not os.path.exists('res'):
|
||||||
|
os.makedirs('res')
|
||||||
|
# 获取当前时间戳
|
||||||
|
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
||||||
|
# 生成带时间戳的文件名
|
||||||
|
file_path = os.path.join('res', f'{self.file_name}_{timestamp}.csv')
|
||||||
|
self.df.to_csv(file_path, index=False)
|
||||||
|
print(f"测试结果已保存到 {file_path}")
|
||||||
|
|
||||||
class BatchTest:
|
class BatchTest:
|
||||||
def __init__(self, url, agentId, chatId, userName):
|
def __init__(self, url, agentId, chatId, userName):
|
||||||
@@ -70,18 +132,35 @@ class BatchTest:
|
|||||||
def benchmark(url:str, agentId:str, chatId:str, filePath:str, userName:str):
|
def benchmark(url:str, agentId:str, chatId:str, filePath:str, userName:str):
|
||||||
batch_test = BatchTest(url, agentId, chatId, userName)
|
batch_test = BatchTest(url, agentId, chatId, userName)
|
||||||
df = batch_test.read_question_from_csv(filePath)
|
df = batch_test.read_question_from_csv(filePath)
|
||||||
|
appender = DataFrameAppender(os.path.basename(filePath))
|
||||||
for index, row in df.iterrows():
|
for index, row in df.iterrows():
|
||||||
question = row['question']
|
question = row['question']
|
||||||
print('start to ask question:', question)
|
print('start to ask question:', question)
|
||||||
# 捕获异常,防止程序中断
|
# 捕获异常,防止程序中断
|
||||||
try:
|
try:
|
||||||
parse_resp = batch_test.parse(question)
|
parse_resp = batch_test.parse(question)
|
||||||
batch_test.execute(agentId, question, parse_resp['data']['queryId'])
|
parse_status = '解析失败'
|
||||||
|
if parse_resp.get('data').get('errorMsg') is None:
|
||||||
|
parse_status = '解析成功'
|
||||||
|
parse_cost = parse_resp.get('data').get('parseTimeCost').get('parseTime')
|
||||||
|
execute_resp = batch_test.execute(agentId, question, parse_resp['data']['queryId'])
|
||||||
|
execute_status = '执行失败'
|
||||||
|
execute_cost = 0
|
||||||
|
if parse_status == '解析成功' and execute_resp.get('data').get('errorMsg') is None:
|
||||||
|
execute_status = '执行成功'
|
||||||
|
execute_cost = execute_resp.get('data').get('queryTimeCost')
|
||||||
|
res = [question.replace(',', '#'),parse_status,parse_cost/1000,execute_status,execute_cost/1000,(parse_cost+execute_cost)/1000]
|
||||||
|
appender.append_data(res)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('error:', e)
|
print('error:', e)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
continue
|
continue
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
# 打印分析结果
|
||||||
|
appender.print_analysis_result()
|
||||||
|
# 分析明细输出
|
||||||
|
appender.write_to_csv()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import java.util.List;
|
|||||||
|
|
||||||
/** extended information command about model */
|
/** extended information command about model */
|
||||||
@Data
|
@Data
|
||||||
@ToString
|
|
||||||
public class ChatConfigBaseReq {
|
public class ChatConfigBaseReq {
|
||||||
|
|
||||||
private Long modelId;
|
private Long modelId;
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ public class ChatMemoryFilter {
|
|||||||
|
|
||||||
private Integer agentId;
|
private Integer agentId;
|
||||||
|
|
||||||
|
private Long queryId;
|
||||||
|
|
||||||
private String question;
|
private String question;
|
||||||
|
|
||||||
private List<String> questions;
|
private List<String> questions;
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
package com.tencent.supersonic.chat.api.pojo.request;
|
package com.tencent.supersonic.chat.api.pojo.request;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryReviewResult;
|
import com.tencent.supersonic.chat.api.pojo.enums.MemoryReviewResult;
|
||||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryStatus;
|
import com.tencent.supersonic.chat.api.pojo.enums.MemoryStatus;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
public class ChatMemoryUpdateReq {
|
public class ChatMemoryUpdateReq {
|
||||||
|
|
||||||
@NotNull(message = "id不可为空")
|
@NotNull(message = "id不可为空")
|
||||||
@@ -21,4 +26,8 @@ public class ChatMemoryUpdateReq {
|
|||||||
private MemoryReviewResult humanReviewRet;
|
private MemoryReviewResult humanReviewRet;
|
||||||
|
|
||||||
private String humanReviewCmt;
|
private String humanReviewCmt;
|
||||||
|
|
||||||
|
private MemoryReviewResult llmReviewRet;
|
||||||
|
|
||||||
|
private String llmReviewCmt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.api.pojo.request;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/** the entity info about the model */
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
@ToString
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class Entity {
|
|
||||||
|
|
||||||
/** uniquely identifies an entity */
|
|
||||||
private Long entityId;
|
|
||||||
|
|
||||||
/** entity name list */
|
|
||||||
private List<String> names;
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ import lombok.Data;
|
|||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ToString
|
|
||||||
public class ItemNameVisibility {
|
public class ItemNameVisibility {
|
||||||
|
|
||||||
private ItemNameVisibilityInfo aggVisibilityInfo;
|
private ItemNameVisibilityInfo aggVisibilityInfo;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ToString
|
|
||||||
public class ItemNameVisibilityInfo {
|
public class ItemNameVisibilityInfo {
|
||||||
|
|
||||||
/** invisible dimensions */
|
/** invisible dimensions */
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ToString
|
|
||||||
public class ItemVisibility {
|
public class ItemVisibility {
|
||||||
|
|
||||||
/** invisible dimensions */
|
/** invisible dimensions */
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package com.tencent.supersonic.chat.api.pojo.request;
|
package com.tencent.supersonic.chat.api.pojo.request;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.common.pojo.enums.TypeEnums;
|
import com.tencent.supersonic.common.pojo.enums.TypeEnums;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/** information about dictionary about the model */
|
/** information about dictionary about the model */
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import lombok.NoArgsConstructor;
|
|||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ToString
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class RecommendedQuestionReq {
|
public class RecommendedQuestionReq {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import lombok.ToString;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ToString
|
|
||||||
@Data
|
@Data
|
||||||
public class DictLatestTaskResp {
|
public class DictLatestTaskResp {
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.api.pojo.response;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class EntityRichInfoResp {
|
|
||||||
/** entity alias */
|
|
||||||
private List<String> names;
|
|
||||||
|
|
||||||
private SchemaElement dimItem;
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ package com.tencent.supersonic.chat.api.pojo.response;
|
|||||||
import com.tencent.supersonic.common.pojo.QueryAuthorization;
|
import com.tencent.supersonic.common.pojo.QueryAuthorization;
|
||||||
import com.tencent.supersonic.common.pojo.QueryColumn;
|
import com.tencent.supersonic.common.pojo.QueryColumn;
|
||||||
import com.tencent.supersonic.headless.api.pojo.AggregateInfo;
|
import com.tencent.supersonic.headless.api.pojo.AggregateInfo;
|
||||||
import com.tencent.supersonic.headless.api.pojo.EntityInfo;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.QueryState;
|
import com.tencent.supersonic.headless.api.pojo.response.QueryState;
|
||||||
@@ -26,7 +25,6 @@ public class QueryResult {
|
|||||||
private String textResult;
|
private String textResult;
|
||||||
private String textSummary;
|
private String textSummary;
|
||||||
private Long queryTimeCost;
|
private Long queryTimeCost;
|
||||||
private EntityInfo entityInfo;
|
|
||||||
private List<SchemaElement> recommendedDimensions;
|
private List<SchemaElement> recommendedDimensions;
|
||||||
private AggregateInfo aggregateInfo;
|
private AggregateInfo aggregateInfo;
|
||||||
private String errorMsg;
|
private String errorMsg;
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ package com.tencent.supersonic.chat.api.pojo.response;
|
|||||||
import com.tencent.supersonic.chat.api.pojo.request.RecommendedQuestionReq;
|
import com.tencent.supersonic.chat.api.pojo.request.RecommendedQuestionReq;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class RecommendQuestionResp {
|
public class RecommendQuestionResp {
|
||||||
private Long modelId;
|
private Long modelId;
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
package com.tencent.supersonic.chat.api.pojo.response;
|
package com.tencent.supersonic.chat.api.pojo.response;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
public class SimilarQueryRecallResp {
|
public class SimilarQueryRecallResp {
|
||||||
|
|
||||||
private Long queryId;
|
private Long queryId;
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.tencent.supersonic.chat.server.agent;
|
package com.tencent.supersonic.chat.server.agent;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.tencent.supersonic.chat.server.memory.MemoryReviewTask;
|
import com.tencent.supersonic.chat.server.memory.MemoryReviewTask;
|
||||||
import com.tencent.supersonic.common.pojo.ChatApp;
|
import com.tencent.supersonic.common.pojo.ChatApp;
|
||||||
import com.tencent.supersonic.common.pojo.RecordInfo;
|
import com.tencent.supersonic.common.pojo.RecordInfo;
|
||||||
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
@@ -12,6 +14,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -33,6 +36,11 @@ public class Agent extends RecordInfo {
|
|||||||
private String toolConfig;
|
private String toolConfig;
|
||||||
private Map<String, ChatApp> chatAppConfig = Collections.emptyMap();
|
private Map<String, ChatApp> chatAppConfig = Collections.emptyMap();
|
||||||
private VisualConfig visualConfig;
|
private VisualConfig visualConfig;
|
||||||
|
private List<String> admins = Lists.newArrayList();
|
||||||
|
private List<String> viewers = Lists.newArrayList();
|
||||||
|
private List<String> adminOrgs = Lists.newArrayList();
|
||||||
|
private List<String> viewOrgs = Lists.newArrayList();
|
||||||
|
private Integer isOpen = 0;
|
||||||
|
|
||||||
public List<String> getTools(AgentToolType type) {
|
public List<String> getTools(AgentToolType type) {
|
||||||
Map<String, Object> map = JSONObject.parseObject(toolConfig, Map.class);
|
Map<String, Object> map = JSONObject.parseObject(toolConfig, Map.class);
|
||||||
@@ -105,4 +113,13 @@ public class Agent extends RecordInfo {
|
|||||||
.filter(dataSetIds -> !CollectionUtils.isEmpty(dataSetIds))
|
.filter(dataSetIds -> !CollectionUtils.isEmpty(dataSetIds))
|
||||||
.flatMap(Collection::stream).collect(Collectors.toSet());
|
.flatMap(Collection::stream).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean contains(User user, Function<Agent, List<String>> list) {
|
||||||
|
return list.apply(this).contains(user.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean openToAll() {
|
||||||
|
return isOpen != null && isOpen == 1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,5 +5,7 @@ import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
|||||||
|
|
||||||
public interface ChatQueryExecutor {
|
public interface ChatQueryExecutor {
|
||||||
|
|
||||||
|
boolean accept(ExecuteContext executeContext);
|
||||||
|
|
||||||
QueryResult execute(ExecuteContext executeContext);
|
QueryResult execute(ExecuteContext executeContext);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import java.util.stream.Collectors;
|
|||||||
public class PlainTextExecutor implements ChatQueryExecutor {
|
public class PlainTextExecutor implements ChatQueryExecutor {
|
||||||
|
|
||||||
public static final String APP_KEY = "SMALL_TALK";
|
public static final String APP_KEY = "SMALL_TALK";
|
||||||
private static final String INSTRUCTION = "" + "#Role: You are a nice person to talk to."
|
private static final String INSTRUCTION = "#Role: You are a nice person to talk to."
|
||||||
+ "\n#Task: Respond quickly and nicely to the user."
|
+ "\n#Task: Respond quickly and nicely to the user."
|
||||||
+ "\n#Rules: 1.ALWAYS use the same language as the `#Current Input`."
|
+ "\n#Rules: 1.ALWAYS use the same language as the `#Current Input`."
|
||||||
+ "\n#History Inputs: %s" + "\n#Current Input: %s" + "\n#Response: ";
|
+ "\n#History Inputs: %s" + "\n#Current Input: %s" + "\n#Response: ";
|
||||||
@@ -37,11 +37,12 @@ public class PlainTextExecutor implements ChatQueryExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryResult execute(ExecuteContext executeContext) {
|
public boolean accept(ExecuteContext executeContext) {
|
||||||
if (!"PLAIN_TEXT".equals(executeContext.getParseInfo().getQueryMode())) {
|
return "PLAIN_TEXT".equals(executeContext.getParseInfo().getQueryMode());
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryResult execute(ExecuteContext executeContext) {
|
||||||
AgentService agentService = ContextUtils.getBean(AgentService.class);
|
AgentService agentService = ContextUtils.getBean(AgentService.class);
|
||||||
Agent chatAgent = agentService.getAgent(executeContext.getAgent().getId());
|
Agent chatAgent = agentService.getAgent(executeContext.getAgent().getId());
|
||||||
ChatApp chatApp = chatAgent.getChatAppConfig().get(APP_KEY);
|
ChatApp chatApp = chatAgent.getChatAppConfig().get(APP_KEY);
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
|||||||
|
|
||||||
public class PluginExecutor implements ChatQueryExecutor {
|
public class PluginExecutor implements ChatQueryExecutor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(ExecuteContext executeContext) {
|
||||||
|
return PluginQueryManager.isPluginQuery(executeContext.getParseInfo().getQueryMode());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryResult execute(ExecuteContext executeContext) {
|
public QueryResult execute(ExecuteContext executeContext) {
|
||||||
SemanticParseInfo parseInfo = executeContext.getParseInfo();
|
SemanticParseInfo parseInfo = executeContext.getParseInfo();
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package com.tencent.supersonic.chat.server.executor;
|
|||||||
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryStatus;
|
import com.tencent.supersonic.chat.api.pojo.enums.MemoryStatus;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatMemoryDO;
|
|
||||||
import com.tencent.supersonic.chat.server.pojo.ChatContext;
|
import com.tencent.supersonic.chat.server.pojo.ChatContext;
|
||||||
|
import com.tencent.supersonic.chat.server.pojo.ChatMemory;
|
||||||
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
||||||
import com.tencent.supersonic.chat.server.service.ChatContextService;
|
import com.tencent.supersonic.chat.server.service.ChatContextService;
|
||||||
import com.tencent.supersonic.chat.server.service.MemoryService;
|
import com.tencent.supersonic.chat.server.service.MemoryService;
|
||||||
@@ -25,6 +25,11 @@ import java.util.Objects;
|
|||||||
|
|
||||||
public class SqlExecutor implements ChatQueryExecutor {
|
public class SqlExecutor implements ChatQueryExecutor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(ExecuteContext executeContext) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@Override
|
@Override
|
||||||
public QueryResult execute(ExecuteContext executeContext) {
|
public QueryResult execute(ExecuteContext executeContext) {
|
||||||
@@ -44,7 +49,7 @@ public class SqlExecutor implements ChatQueryExecutor {
|
|||||||
Text2SQLExemplar.class);
|
Text2SQLExemplar.class);
|
||||||
|
|
||||||
MemoryService memoryService = ContextUtils.getBean(MemoryService.class);
|
MemoryService memoryService = ContextUtils.getBean(MemoryService.class);
|
||||||
memoryService.createMemory(ChatMemoryDO.builder()
|
memoryService.createMemory(ChatMemory.builder().queryId(queryResult.getQueryId())
|
||||||
.agentId(executeContext.getAgent().getId()).status(MemoryStatus.PENDING)
|
.agentId(executeContext.getAgent().getId()).status(MemoryStatus.PENDING)
|
||||||
.question(exemplar.getQuestion()).sideInfo(exemplar.getSideInfo())
|
.question(exemplar.getQuestion()).sideInfo(exemplar.getSideInfo())
|
||||||
.dbSchema(exemplar.getDbSchema()).s2sql(exemplar.getSql())
|
.dbSchema(exemplar.getDbSchema()).s2sql(exemplar.getSql())
|
||||||
@@ -70,21 +75,26 @@ public class SqlExecutor implements ChatQueryExecutor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
QuerySqlReq sqlReq =
|
// 使用querySQL,它已经包含了所有修正(包括物理SQL修正)
|
||||||
QuerySqlReq.builder().sql(parseInfo.getSqlInfo().getCorrectedS2SQL()).build();
|
String finalSql = StringUtils.isNotBlank(parseInfo.getSqlInfo().getQuerySQL())
|
||||||
|
? parseInfo.getSqlInfo().getQuerySQL()
|
||||||
|
: parseInfo.getSqlInfo().getCorrectedS2SQL();
|
||||||
|
|
||||||
|
QuerySqlReq sqlReq = QuerySqlReq.builder().sql(finalSql).build();
|
||||||
sqlReq.setSqlInfo(parseInfo.getSqlInfo());
|
sqlReq.setSqlInfo(parseInfo.getSqlInfo());
|
||||||
sqlReq.setDataSetId(parseInfo.getDataSetId());
|
sqlReq.setDataSetId(parseInfo.getDataSetId());
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
QueryResult queryResult = new QueryResult();
|
QueryResult queryResult = new QueryResult();
|
||||||
|
queryResult.setQueryId(executeContext.getRequest().getQueryId());
|
||||||
queryResult.setChatContext(parseInfo);
|
queryResult.setChatContext(parseInfo);
|
||||||
queryResult.setQueryMode(parseInfo.getQueryMode());
|
queryResult.setQueryMode(parseInfo.getQueryMode());
|
||||||
queryResult.setQueryTimeCost(System.currentTimeMillis() - startTime);
|
|
||||||
SemanticQueryResp queryResp =
|
SemanticQueryResp queryResp =
|
||||||
semanticLayer.queryByReq(sqlReq, executeContext.getRequest().getUser());
|
semanticLayer.queryByReq(sqlReq, executeContext.getRequest().getUser());
|
||||||
|
queryResult.setQueryTimeCost(System.currentTimeMillis() - startTime);
|
||||||
if (queryResp != null) {
|
if (queryResp != null) {
|
||||||
queryResult.setQueryAuthorization(queryResp.getQueryAuthorization());
|
queryResult.setQueryAuthorization(queryResp.getQueryAuthorization());
|
||||||
queryResult.setQuerySql(queryResp.getSql());
|
queryResult.setQuerySql(finalSql);
|
||||||
queryResult.setQueryResults(queryResp.getResultList());
|
queryResult.setQueryResults(queryResp.getResultList());
|
||||||
queryResult.setQueryColumns(queryResp.getColumns());
|
queryResult.setQueryColumns(queryResp.getColumns());
|
||||||
queryResult.setQueryState(QueryState.SUCCESS);
|
queryResult.setQueryState(QueryState.SUCCESS);
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
package com.tencent.supersonic.chat.server.memory;
|
package com.tencent.supersonic.chat.server.memory;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryReviewResult;
|
import com.tencent.supersonic.chat.api.pojo.enums.MemoryReviewResult;
|
||||||
|
import com.tencent.supersonic.chat.api.pojo.enums.MemoryStatus;
|
||||||
|
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryFilter;
|
||||||
|
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryUpdateReq;
|
||||||
import com.tencent.supersonic.chat.server.agent.Agent;
|
import com.tencent.supersonic.chat.server.agent.Agent;
|
||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatMemoryDO;
|
import com.tencent.supersonic.chat.server.pojo.ChatMemory;
|
||||||
import com.tencent.supersonic.chat.server.service.AgentService;
|
import com.tencent.supersonic.chat.server.service.AgentService;
|
||||||
import com.tencent.supersonic.chat.server.service.MemoryService;
|
import com.tencent.supersonic.chat.server.service.MemoryService;
|
||||||
import com.tencent.supersonic.common.pojo.ChatApp;
|
import com.tencent.supersonic.common.pojo.ChatApp;
|
||||||
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
import com.tencent.supersonic.common.pojo.enums.AppModule;
|
import com.tencent.supersonic.common.pojo.enums.AppModule;
|
||||||
import com.tencent.supersonic.common.util.ChatAppManager;
|
import com.tencent.supersonic.common.util.ChatAppManager;
|
||||||
import com.tencent.supersonic.headless.server.utils.ModelConfigHelper;
|
import com.tencent.supersonic.headless.server.utils.ModelConfigHelper;
|
||||||
@@ -21,6 +25,7 @@ import org.springframework.scheduling.annotation.Scheduled;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -57,24 +62,36 @@ public class MemoryReviewTask {
|
|||||||
|
|
||||||
@Scheduled(fixedDelay = 60 * 1000)
|
@Scheduled(fixedDelay = 60 * 1000)
|
||||||
public void review() {
|
public void review() {
|
||||||
memoryService.getMemoriesForLlmReview().stream().forEach(memory -> {
|
List<Agent> agentList = agentService.getAgents();
|
||||||
try {
|
for (Agent agent : agentList) {
|
||||||
processMemory(memory);
|
if (!agent.enableMemoryReview()) {
|
||||||
} catch (Exception e) {
|
continue;
|
||||||
log.error("Exception occurred while processing memory with id {}: {}",
|
|
||||||
memory.getId(), e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
});
|
ChatMemoryFilter chatMemoryFilter =
|
||||||
|
ChatMemoryFilter.builder().agentId(agent.getId()).build();
|
||||||
|
memoryService.getMemories(chatMemoryFilter).forEach(memory -> {
|
||||||
|
try {
|
||||||
|
processMemory(memory, agent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Exception occurred while processing memory with id {}: {}",
|
||||||
|
memory.getId(), e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processMemory(ChatMemoryDO m) {
|
private void processMemory(ChatMemory m, Agent agent) {
|
||||||
Agent chatAgent = agentService.getAgent(m.getAgentId());
|
if (Objects.isNull(agent)) {
|
||||||
if (Objects.isNull(chatAgent)) {
|
|
||||||
log.warn("Agent id {} not found or memory review disabled", m.getAgentId());
|
log.warn("Agent id {} not found or memory review disabled", m.getAgentId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatApp chatApp = chatAgent.getChatAppConfig().get(APP_KEY);
|
// if either LLM or human has reviewed, just return
|
||||||
|
if (Objects.nonNull(m.getLlmReviewRet()) || Objects.nonNull(m.getHumanReviewRet())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatApp chatApp = agent.getChatAppConfig().get(APP_KEY);
|
||||||
if (Objects.isNull(chatApp) || !chatApp.isEnable()) {
|
if (Objects.isNull(chatApp) || !chatApp.isEnable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -90,25 +107,28 @@ public class MemoryReviewTask {
|
|||||||
response);
|
response);
|
||||||
processResponse(response, m);
|
processResponse(response, m);
|
||||||
} else {
|
} else {
|
||||||
log.debug("ChatLanguageModel not found for agent:{}", chatAgent.getId());
|
log.debug("ChatLanguageModel not found for agent:{}", agent.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createPromptString(ChatMemoryDO m, String promptTemplate) {
|
private String createPromptString(ChatMemory m, String promptTemplate) {
|
||||||
return String.format(promptTemplate, m.getQuestion(), m.getDbSchema(), m.getSideInfo(),
|
return String.format(promptTemplate, m.getQuestion(), m.getDbSchema(), m.getSideInfo(),
|
||||||
m.getS2sql());
|
m.getS2sql());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processResponse(String response, ChatMemoryDO m) {
|
private void processResponse(String response, ChatMemory m) {
|
||||||
Matcher matcher = OUTPUT_PATTERN.matcher(response);
|
Matcher matcher = OUTPUT_PATTERN.matcher(response);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
m.setLlmReviewRet(MemoryReviewResult.getMemoryReviewResult(matcher.group(1)));
|
m.setLlmReviewRet(MemoryReviewResult.getMemoryReviewResult(matcher.group(1)));
|
||||||
m.setLlmReviewCmt(matcher.group(2));
|
m.setLlmReviewCmt(matcher.group(2));
|
||||||
// directly enable memory if the LLM determines it positive
|
// directly enable memory if the LLM determines it positive
|
||||||
if (MemoryReviewResult.POSITIVE.equals(m.getLlmReviewRet())) {
|
if (MemoryReviewResult.POSITIVE.equals(m.getLlmReviewRet())) {
|
||||||
memoryService.enableMemory(m);
|
m.setStatus(MemoryStatus.ENABLED);
|
||||||
}
|
}
|
||||||
memoryService.updateMemory(m);
|
ChatMemoryUpdateReq memoryUpdateReq = ChatMemoryUpdateReq.builder().id(m.getId())
|
||||||
|
.status(m.getStatus()).llmReviewRet(m.getLlmReviewRet())
|
||||||
|
.llmReviewCmt(m.getLlmReviewCmt()).build();
|
||||||
|
memoryService.updateMemory(memoryUpdateReq, User.getDefaultUser());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,7 @@ import com.tencent.supersonic.chat.server.pojo.ParseContext;
|
|||||||
|
|
||||||
public interface ChatQueryParser {
|
public interface ChatQueryParser {
|
||||||
|
|
||||||
|
boolean accept(ParseContext parseContext);
|
||||||
|
|
||||||
void parse(ParseContext parseContext);
|
void parse(ParseContext parseContext);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ public class NL2PluginParser implements ChatQueryParser {
|
|||||||
private final List<PluginRecognizer> pluginRecognizers =
|
private final List<PluginRecognizer> pluginRecognizers =
|
||||||
ComponentFactory.getPluginRecognizers();
|
ComponentFactory.getPluginRecognizers();
|
||||||
|
|
||||||
|
public boolean accept(ParseContext parseContext) {
|
||||||
|
return parseContext.getAgent().containsPluginTool();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void parse(ParseContext parseContext) {
|
public void parse(ParseContext parseContext) {
|
||||||
if (!parseContext.getAgent().containsPluginTool()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pluginRecognizers.forEach(pluginRecognizer -> {
|
pluginRecognizers.forEach(pluginRecognizer -> {
|
||||||
pluginRecognizer.recognize(parseContext);
|
pluginRecognizer.recognize(parseContext);
|
||||||
log.info("{} recallResult:{}", pluginRecognizer.getClass().getSimpleName(),
|
log.info("{} recallResult:{}", pluginRecognizer.getClass().getSimpleName(),
|
||||||
|
|||||||
@@ -73,21 +73,25 @@ public class NL2SQLParser implements ChatQueryParser {
|
|||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean accept(ParseContext parseContext) {
|
||||||
|
return parseContext.enableNL2SQL();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void parse(ParseContext parseContext) {
|
public void parse(ParseContext parseContext) {
|
||||||
if (!parseContext.enableNL2SQL()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// first go with rule-based parsers unless the user has already selected one parse.
|
// first go with rule-based parsers unless the user has already selected one parse.
|
||||||
if (Objects.isNull(parseContext.getRequest().getSelectedParse())) {
|
if (Objects.isNull(parseContext.getRequest().getSelectedParse())) {
|
||||||
QueryNLReq queryNLReq = QueryReqConverter.buildQueryNLReq(parseContext);
|
QueryNLReq queryNLReq = QueryReqConverter.buildQueryNLReq(parseContext);
|
||||||
queryNLReq.setText2SQLType(Text2SQLType.ONLY_RULE);
|
queryNLReq.setText2SQLType(Text2SQLType.ONLY_RULE);
|
||||||
|
if (parseContext.enableLLM()) {
|
||||||
|
queryNLReq.setText2SQLType(Text2SQLType.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
// for every requested dataSet, recursively invoke rule-based parser with different
|
// for every requested dataSet, recursively invoke rule-based parser with different
|
||||||
// mapModes
|
// mapModes
|
||||||
Set<Long> requestedDatasets = queryNLReq.getDataSetIds();
|
Set<Long> requestedDatasets = queryNLReq.getDataSetIds();
|
||||||
List<SemanticParseInfo> candidateParses = Lists.newArrayList();
|
List<SemanticParseInfo> candidateParses = Lists.newArrayList();
|
||||||
|
StringBuilder errMsg = new StringBuilder();
|
||||||
for (Long datasetId : requestedDatasets) {
|
for (Long datasetId : requestedDatasets) {
|
||||||
queryNLReq.setDataSetIds(Collections.singleton(datasetId));
|
queryNLReq.setDataSetIds(Collections.singleton(datasetId));
|
||||||
ChatParseResp parseResp = new ChatParseResp(parseContext.getRequest().getQueryId());
|
ChatParseResp parseResp = new ChatParseResp(parseContext.getRequest().getQueryId());
|
||||||
@@ -96,10 +100,16 @@ public class NL2SQLParser implements ChatQueryParser {
|
|||||||
queryNLReq.setMapModeEnum(mode);
|
queryNLReq.setMapModeEnum(mode);
|
||||||
doParse(queryNLReq, parseResp);
|
doParse(queryNLReq, parseResp);
|
||||||
}
|
}
|
||||||
if (parseResp.getSelectedParses().isEmpty()) {
|
|
||||||
|
if (parseResp.getSelectedParses().isEmpty() && candidateParses.isEmpty()) {
|
||||||
queryNLReq.setMapModeEnum(MapModeEnum.LOOSE);
|
queryNLReq.setMapModeEnum(MapModeEnum.LOOSE);
|
||||||
doParse(queryNLReq, parseResp);
|
doParse(queryNLReq, parseResp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parseResp.getSelectedParses().isEmpty()) {
|
||||||
|
errMsg.append(parseResp.getErrorMsg());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// for one dataset select the top 1 parse after sorting
|
// for one dataset select the top 1 parse after sorting
|
||||||
SemanticParseInfo.sort(parseResp.getSelectedParses());
|
SemanticParseInfo.sort(parseResp.getSelectedParses());
|
||||||
candidateParses.add(parseResp.getSelectedParses().get(0));
|
candidateParses.add(parseResp.getSelectedParses().get(0));
|
||||||
@@ -110,6 +120,10 @@ public class NL2SQLParser implements ChatQueryParser {
|
|||||||
SemanticParseInfo.sort(candidateParses);
|
SemanticParseInfo.sort(candidateParses);
|
||||||
parseContext.getResponse().setSelectedParses(
|
parseContext.getResponse().setSelectedParses(
|
||||||
candidateParses.subList(0, Math.min(parserShowCount, candidateParses.size())));
|
candidateParses.subList(0, Math.min(parserShowCount, candidateParses.size())));
|
||||||
|
if (parseContext.getResponse().getSelectedParses().isEmpty()) {
|
||||||
|
parseContext.getResponse().setState(ParseResp.ParseState.FAILED);
|
||||||
|
parseContext.getResponse().setErrorMsg(errMsg.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// next go with llm-based parsers unless LLM is disabled or use feedback is needed.
|
// next go with llm-based parsers unless LLM is disabled or use feedback is needed.
|
||||||
@@ -125,11 +139,18 @@ public class NL2SQLParser implements ChatQueryParser {
|
|||||||
SemanticParseInfo userSelectParse = parseContext.getRequest().getSelectedParse();
|
SemanticParseInfo userSelectParse = parseContext.getRequest().getSelectedParse();
|
||||||
queryNLReq.setSelectedParseInfo(Objects.nonNull(userSelectParse) ? userSelectParse
|
queryNLReq.setSelectedParseInfo(Objects.nonNull(userSelectParse) ? userSelectParse
|
||||||
: parseContext.getResponse().getSelectedParses().get(0));
|
: parseContext.getResponse().getSelectedParses().get(0));
|
||||||
|
|
||||||
parseContext.setResponse(new ChatParseResp(parseContext.getResponse().getQueryId()));
|
parseContext.setResponse(new ChatParseResp(parseContext.getResponse().getQueryId()));
|
||||||
|
|
||||||
rewriteMultiTurn(parseContext, queryNLReq);
|
rewriteMultiTurn(parseContext, queryNLReq);
|
||||||
addDynamicExemplars(parseContext, queryNLReq);
|
addDynamicExemplars(parseContext, queryNLReq);
|
||||||
doParse(queryNLReq, parseContext.getResponse());
|
doParse(queryNLReq, parseContext.getResponse());
|
||||||
|
|
||||||
|
// try again with all semantic fields passed to LLM
|
||||||
|
if (parseContext.getResponse().getState().equals(ParseResp.ParseState.FAILED)) {
|
||||||
|
queryNLReq.setSelectedParseInfo(null);
|
||||||
|
queryNLReq.setMapModeEnum(MapModeEnum.ALL);
|
||||||
|
doParse(queryNLReq, parseContext.getResponse());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
|||||||
|
|
||||||
public class PlainTextParser implements ChatQueryParser {
|
public class PlainTextParser implements ChatQueryParser {
|
||||||
|
|
||||||
|
public boolean accept(ParseContext parseContext) {
|
||||||
|
return !parseContext.getAgent().containsAnyTool();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void parse(ParseContext parseContext) {
|
public void parse(ParseContext parseContext) {
|
||||||
if (parseContext.getAgent().containsAnyTool()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SemanticParseInfo parseInfo = new SemanticParseInfo();
|
SemanticParseInfo parseInfo = new SemanticParseInfo();
|
||||||
parseInfo.setQueryMode("PLAIN_TEXT");
|
parseInfo.setQueryMode("PLAIN_TEXT");
|
||||||
parseInfo.setId(1);
|
parseInfo.setId(1);
|
||||||
|
|||||||
@@ -40,4 +40,14 @@ public class AgentDO {
|
|||||||
private String chatModelConfig;
|
private String chatModelConfig;
|
||||||
|
|
||||||
private String visualConfig;
|
private String visualConfig;
|
||||||
|
|
||||||
|
private String admin;
|
||||||
|
|
||||||
|
private String viewer;
|
||||||
|
|
||||||
|
private String adminOrg;
|
||||||
|
|
||||||
|
private String viewOrg;
|
||||||
|
|
||||||
|
private Integer isOpen;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.dataobject;
|
package com.tencent.supersonic.chat.server.persistence.dataobject;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@@ -7,9 +10,10 @@ import java.util.Date;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ToString
|
@ToString
|
||||||
|
@TableName("s2_chat_config")
|
||||||
public class ChatConfigDO {
|
public class ChatConfigDO {
|
||||||
|
|
||||||
/** database auto-increment primary key */
|
@TableId(type = IdType.AUTO)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
private Long modelId;
|
private Long modelId;
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.dataobject;
|
package com.tencent.supersonic.chat.server.persistence.dataobject;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@TableName("s2_chat_context")
|
||||||
public class ChatContextDO implements Serializable {
|
public class ChatContextDO implements Serializable {
|
||||||
|
|
||||||
|
@TableId
|
||||||
private Integer chatId;
|
private Integer chatId;
|
||||||
private Instant modifiedAt;
|
private Instant modifiedAt;
|
||||||
private String user;
|
@TableField("query_user")
|
||||||
|
private String queryUser;
|
||||||
private String queryText;
|
private String queryText;
|
||||||
private String semanticParse;
|
private String semanticParse;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.dataobject;
|
package com.tencent.supersonic.chat.server.persistence.dataobject;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@TableName("s2_chat")
|
||||||
public class ChatDO {
|
public class ChatDO {
|
||||||
|
|
||||||
private long chatId;
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long chatId;
|
||||||
private Integer agentId;
|
private Integer agentId;
|
||||||
private String chatName;
|
private String chatName;
|
||||||
private String createTime;
|
private String createTime;
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryReviewResult;
|
import lombok.AllArgsConstructor;
|
||||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryStatus;
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.ToString;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@ToString
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
@TableName("s2_chat_memory")
|
@TableName("s2_chat_memory")
|
||||||
public class ChatMemoryDO {
|
public class ChatMemoryDO {
|
||||||
@TableId(type = IdType.AUTO)
|
@TableId(type = IdType.AUTO)
|
||||||
@@ -23,6 +23,9 @@ public class ChatMemoryDO {
|
|||||||
@TableField("agent_id")
|
@TableField("agent_id")
|
||||||
private Integer agentId;
|
private Integer agentId;
|
||||||
|
|
||||||
|
@TableField("query_id")
|
||||||
|
private Long queryId;
|
||||||
|
|
||||||
@TableField("question")
|
@TableField("question")
|
||||||
private String question;
|
private String question;
|
||||||
|
|
||||||
@@ -36,16 +39,16 @@ public class ChatMemoryDO {
|
|||||||
private String s2sql;
|
private String s2sql;
|
||||||
|
|
||||||
@TableField("status")
|
@TableField("status")
|
||||||
private MemoryStatus status;
|
private String status;
|
||||||
|
|
||||||
@TableField("llm_review")
|
@TableField("llm_review")
|
||||||
private MemoryReviewResult llmReviewRet;
|
private String llmReviewRet;
|
||||||
|
|
||||||
@TableField("llm_comment")
|
@TableField("llm_comment")
|
||||||
private String llmReviewCmt;
|
private String llmReviewCmt;
|
||||||
|
|
||||||
@TableField("human_review")
|
@TableField("human_review")
|
||||||
private MemoryReviewResult humanReviewRet;
|
private String humanReviewRet;
|
||||||
|
|
||||||
@TableField("human_comment")
|
@TableField("human_comment")
|
||||||
private String humanReviewCmt;
|
private String humanReviewCmt;
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.dataobject;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class DictConfDO {
|
|
||||||
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
private Long modelId;
|
|
||||||
|
|
||||||
private String dimValueInfos;
|
|
||||||
|
|
||||||
private String createdBy;
|
|
||||||
private String updatedBy;
|
|
||||||
private Date createdAt;
|
|
||||||
private Date updatedAt;
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.dataobject;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.ToString;
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@ToString
|
|
||||||
public class DictTaskDO {
|
|
||||||
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
private String command;
|
|
||||||
|
|
||||||
private String commandMd5;
|
|
||||||
|
|
||||||
private String dimIds;
|
|
||||||
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
private String createdBy;
|
|
||||||
|
|
||||||
private Date createdAt;
|
|
||||||
|
|
||||||
private Double progress;
|
|
||||||
|
|
||||||
private Long elapsedMs;
|
|
||||||
|
|
||||||
public String getCommandMd5() {
|
|
||||||
return DigestUtils.md5Hex(command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,9 +5,6 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class QueryDO {
|
public class QueryDO {
|
||||||
|
|
||||||
public String aggregator = "trend";
|
|
||||||
public String startTime;
|
|
||||||
public String endTime;
|
|
||||||
private long id;
|
private long id;
|
||||||
private long questionId;
|
private long questionId;
|
||||||
private String createTime;
|
private String createTime;
|
||||||
@@ -25,7 +22,6 @@ public class QueryDO {
|
|||||||
private int topNum;
|
private int topNum;
|
||||||
private String querySql;
|
private String querySql;
|
||||||
private Object queryColumn;
|
private Object queryColumn;
|
||||||
private Object entityInfo;
|
|
||||||
private int score;
|
private int score;
|
||||||
private String feedback;
|
private String feedback;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.mapper;
|
package com.tencent.supersonic.chat.server.persistence.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.tencent.supersonic.chat.server.config.ChatConfigFilterInternal;
|
import com.tencent.supersonic.chat.server.config.ChatConfigFilterInternal;
|
||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatConfigDO;
|
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatConfigDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
@@ -7,11 +8,7 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface ChatConfigMapper {
|
public interface ChatConfigMapper extends BaseMapper<ChatConfigDO> {
|
||||||
|
|
||||||
Long addConfig(ChatConfigDO chaConfigPO);
|
|
||||||
|
|
||||||
Long editConfig(ChatConfigDO chaConfigPO);
|
|
||||||
|
|
||||||
List<ChatConfigDO> search(ChatConfigFilterInternal filterInternal);
|
List<ChatConfigDO> search(ChatConfigFilterInternal filterInternal);
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.mapper;
|
package com.tencent.supersonic.chat.server.persistence.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatContextDO;
|
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatContextDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface ChatContextMapper {
|
public interface ChatContextMapper extends BaseMapper<ChatContextDO> {
|
||||||
|
|
||||||
ChatContextDO getContextByChatId(Integer chatId);
|
ChatContextDO getContextByChatId(Integer chatId);
|
||||||
|
|
||||||
int updateContext(ChatContextDO contextDO);
|
|
||||||
|
|
||||||
int addContext(ChatContextDO contextDO);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,15 +32,15 @@ public class ChatConfigRepositoryImpl implements ChatConfigRepository {
|
|||||||
@Override
|
@Override
|
||||||
public Long createConfig(ChatConfig chaConfig) {
|
public Long createConfig(ChatConfig chaConfig) {
|
||||||
ChatConfigDO chaConfigDO = chatConfigHelper.chatConfig2DO(chaConfig);
|
ChatConfigDO chaConfigDO = chatConfigHelper.chatConfig2DO(chaConfig);
|
||||||
chatConfigMapper.addConfig(chaConfigDO);
|
chatConfigMapper.insert(chaConfigDO);
|
||||||
return chaConfigDO.getId();
|
return chaConfigDO.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long updateConfig(ChatConfig chaConfig) {
|
public Long updateConfig(ChatConfig chaConfig) {
|
||||||
ChatConfigDO chaConfigDO = chatConfigHelper.chatConfig2DO(chaConfig);
|
ChatConfigDO chaConfigDO = chatConfigHelper.chatConfig2DO(chaConfig);
|
||||||
|
chatConfigMapper.updateById(chaConfigDO);
|
||||||
return chatConfigMapper.editConfig(chaConfigDO);
|
return chaConfigDO.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,18 +35,13 @@ public class ChatContextRepositoryImpl implements ChatContextRepository {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateContext(ChatContext chatCtx) {
|
public void updateContext(ChatContext chatCtx) {
|
||||||
ChatContextDO context = cast(chatCtx);
|
chatContextMapper.insertOrUpdate(cast(chatCtx));
|
||||||
if (chatContextMapper.getContextByChatId(chatCtx.getChatId()) == null) {
|
|
||||||
chatContextMapper.addContext(context);
|
|
||||||
} else {
|
|
||||||
chatContextMapper.updateContext(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChatContext cast(ChatContextDO contextDO) {
|
private ChatContext cast(ChatContextDO contextDO) {
|
||||||
ChatContext chatContext = new ChatContext();
|
ChatContext chatContext = new ChatContext();
|
||||||
chatContext.setChatId(contextDO.getChatId());
|
chatContext.setChatId(contextDO.getChatId());
|
||||||
chatContext.setUser(contextDO.getUser());
|
chatContext.setUser(contextDO.getQueryUser());
|
||||||
chatContext.setQueryText(contextDO.getQueryText());
|
chatContext.setQueryText(contextDO.getQueryText());
|
||||||
if (contextDO.getSemanticParse() != null && !contextDO.getSemanticParse().isEmpty()) {
|
if (contextDO.getSemanticParse() != null && !contextDO.getSemanticParse().isEmpty()) {
|
||||||
SemanticParseInfo semanticParseInfo =
|
SemanticParseInfo semanticParseInfo =
|
||||||
@@ -60,7 +55,7 @@ public class ChatContextRepositoryImpl implements ChatContextRepository {
|
|||||||
ChatContextDO chatContextDO = new ChatContextDO();
|
ChatContextDO chatContextDO = new ChatContextDO();
|
||||||
chatContextDO.setChatId(chatContext.getChatId());
|
chatContextDO.setChatId(chatContext.getChatId());
|
||||||
chatContextDO.setQueryText(chatContext.getQueryText());
|
chatContextDO.setQueryText(chatContext.getQueryText());
|
||||||
chatContextDO.setUser(chatContext.getUser());
|
chatContextDO.setQueryUser(chatContext.getUser());
|
||||||
if (chatContext.getParseInfo() != null) {
|
if (chatContext.getParseInfo() != null) {
|
||||||
Gson g = new Gson();
|
Gson g = new Gson();
|
||||||
chatContextDO.setSemanticParse(g.toJson(chatContext.getParseInfo()));
|
chatContextDO.setSemanticParse(g.toJson(chatContext.getParseInfo()));
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ import com.tencent.supersonic.chat.server.persistence.mapper.ChatParseMapper;
|
|||||||
import com.tencent.supersonic.chat.server.persistence.mapper.ChatQueryDOMapper;
|
import com.tencent.supersonic.chat.server.persistence.mapper.ChatQueryDOMapper;
|
||||||
import com.tencent.supersonic.chat.server.persistence.mapper.custom.ShowCaseCustomMapper;
|
import com.tencent.supersonic.chat.server.persistence.mapper.custom.ShowCaseCustomMapper;
|
||||||
import com.tencent.supersonic.chat.server.persistence.repository.ChatQueryRepository;
|
import com.tencent.supersonic.chat.server.persistence.repository.ChatQueryRepository;
|
||||||
|
import com.tencent.supersonic.common.pojo.QueryColumn;
|
||||||
import com.tencent.supersonic.common.util.JsonUtil;
|
import com.tencent.supersonic.common.util.JsonUtil;
|
||||||
import com.tencent.supersonic.common.util.PageUtils;
|
import com.tencent.supersonic.common.util.PageUtils;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ParseTimeCostResp;
|
import com.tencent.supersonic.headless.api.pojo.response.ParseTimeCostResp;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -117,6 +117,20 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository {
|
|||||||
JsonUtil.toObject(chatQueryDO.getQueryResult(), QueryResult.class);
|
JsonUtil.toObject(chatQueryDO.getQueryResult(), QueryResult.class);
|
||||||
if (queryResult != null) {
|
if (queryResult != null) {
|
||||||
queryResult.setQueryId(chatQueryDO.getQuestionId());
|
queryResult.setQueryId(chatQueryDO.getQuestionId());
|
||||||
|
// fix bugs, compatible with bugs caused by history field changes
|
||||||
|
if (!CollectionUtils.isEmpty(queryResult.getQueryColumns())) {
|
||||||
|
List<QueryColumn> queryColumns = queryResult.getQueryColumns().stream().peek(x -> {
|
||||||
|
if (StringUtils.isEmpty(x.getBizName())
|
||||||
|
&& StringUtils.isNotEmpty(x.getNameEn())) {
|
||||||
|
x.setBizName(x.getNameEn());
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(x.getBizName())
|
||||||
|
&& StringUtils.isEmpty(x.getNameEn())) {
|
||||||
|
x.setNameEn(x.getBizName());
|
||||||
|
}
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
queryResult.setQueryColumns(queryColumns);
|
||||||
|
}
|
||||||
queryResp.setQueryResult(queryResult);
|
queryResp.setQueryResult(queryResult);
|
||||||
}
|
}
|
||||||
queryResp.setSimilarQueries(JSONObject.parseArray(chatQueryDO.getSimilarQueries(),
|
queryResp.setSimilarQueries(JSONObject.parseArray(chatQueryDO.getSimilarQueries(),
|
||||||
@@ -134,7 +148,7 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository {
|
|||||||
chatQueryDO.setUserName(chatParseReq.getUser().getName());
|
chatQueryDO.setUserName(chatParseReq.getUser().getName());
|
||||||
chatQueryDO.setQueryText(chatParseReq.getQueryText());
|
chatQueryDO.setQueryText(chatParseReq.getQueryText());
|
||||||
chatQueryDO.setAgentId(chatParseReq.getAgentId());
|
chatQueryDO.setAgentId(chatParseReq.getAgentId());
|
||||||
chatQueryDO.setQueryResult("");
|
chatQueryDO.setQueryResult("{}");
|
||||||
chatQueryDO.setQueryState(1);
|
chatQueryDO.setQueryState(1);
|
||||||
try {
|
try {
|
||||||
chatQueryDOMapper.insert(chatQueryDO);
|
chatQueryDOMapper.insert(chatQueryDO);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class PluginQueryManager {
|
public class PluginQueryManager {
|
||||||
|
|
||||||
private static Map<String, PluginSemanticQuery> pluginQueries = new HashMap<>();
|
private static final Map<String, PluginSemanticQuery> pluginQueries = new HashMap<>();
|
||||||
|
|
||||||
public static void register(String queryMode, PluginSemanticQuery pluginSemanticQuery) {
|
public static void register(String queryMode, PluginSemanticQuery pluginSemanticQuery) {
|
||||||
pluginQueries.put(queryMode, pluginSemanticQuery);
|
pluginQueries.put(queryMode, pluginSemanticQuery);
|
||||||
|
|||||||
@@ -88,10 +88,10 @@ public class WebServiceQuery extends PluginSemanticQuery {
|
|||||||
restTemplate = ContextUtils.getBean(RestTemplate.class);
|
restTemplate = ContextUtils.getBean(RestTemplate.class);
|
||||||
try {
|
try {
|
||||||
responseEntity =
|
responseEntity =
|
||||||
restTemplate.exchange(requestUrl, HttpMethod.POST, entity, Object.class);
|
restTemplate.exchange(requestUrl, HttpMethod.POST, entity, String.class);
|
||||||
objectResponse = responseEntity.getBody();
|
objectResponse = responseEntity.getBody();
|
||||||
log.info("objectResponse:{}", objectResponse);
|
log.info("objectResponse:{}", objectResponse);
|
||||||
Map<String, Object> response = JsonUtil.objectToMap(objectResponse);
|
Map<String, Object> response = JSON.parseObject(objectResponse.toString());
|
||||||
webServiceResponse.setResult(response);
|
webServiceResponse.setResult(response);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.info("Exception:{}", e.getMessage());
|
log.info("Exception:{}", e.getMessage());
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.pojo;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.chat.api.pojo.enums.MemoryReviewResult;
|
||||||
|
import com.tencent.supersonic.chat.api.pojo.enums.MemoryStatus;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString
|
||||||
|
public class ChatMemory {
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private Integer agentId;
|
||||||
|
|
||||||
|
private Long queryId;
|
||||||
|
|
||||||
|
private String question;
|
||||||
|
|
||||||
|
private String sideInfo;
|
||||||
|
|
||||||
|
private String dbSchema;
|
||||||
|
|
||||||
|
private String s2sql;
|
||||||
|
|
||||||
|
private MemoryStatus status;
|
||||||
|
|
||||||
|
private MemoryReviewResult llmReviewRet;
|
||||||
|
|
||||||
|
private String llmReviewCmt;
|
||||||
|
|
||||||
|
private MemoryReviewResult humanReviewRet;
|
||||||
|
|
||||||
|
private String humanReviewCmt;
|
||||||
|
|
||||||
|
private String createdBy;
|
||||||
|
|
||||||
|
private Date createdAt;
|
||||||
|
|
||||||
|
private String updatedBy;
|
||||||
|
|
||||||
|
private Date updatedAt;
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.tencent.supersonic.chat.server.pojo;
|
package com.tencent.supersonic.chat.server.pojo;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatExecuteReq;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatExecuteReq;
|
||||||
|
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
||||||
import com.tencent.supersonic.chat.server.agent.Agent;
|
import com.tencent.supersonic.chat.server.agent.Agent;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -8,6 +9,7 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class ExecuteContext {
|
public class ExecuteContext {
|
||||||
private ChatExecuteReq request;
|
private ChatExecuteReq request;
|
||||||
|
private QueryResult response;
|
||||||
private Agent agent;
|
private Agent agent;
|
||||||
private SemanticParseInfo parseInfo;
|
private SemanticParseInfo parseInfo;
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class ParseContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean enableNL2SQL() {
|
public boolean enableNL2SQL() {
|
||||||
return Objects.nonNull(agent) && agent.containsDatasetTool();
|
return Objects.nonNull(agent) && agent.containsDatasetTool()&&response.getSelectedParses().size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean enableLLM() {
|
public boolean enableLLM() {
|
||||||
|
|||||||
@@ -43,15 +43,31 @@ public class DataInterpretProcessor implements ExecuteResultProcessor {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
public boolean accept(ExecuteContext executeContext) {
|
||||||
|
Agent agent = executeContext.getAgent();
|
||||||
|
ChatApp chatApp = agent.getChatAppConfig().get(APP_KEY);
|
||||||
|
return Objects.nonNull(chatApp) && chatApp.isEnable()
|
||||||
|
&& StringUtils.isNotBlank(executeContext.getResponse().getTextResult()) // 如果都没结果,则无法处理
|
||||||
|
&& StringUtils.isBlank(executeContext.getResponse().getTextSummary()); // 如果已经有汇总的结果了,无法再次处理
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(ExecuteContext executeContext) {
|
||||||
|
QueryResult queryResult = executeContext.getResponse();
|
||||||
Agent agent = executeContext.getAgent();
|
Agent agent = executeContext.getAgent();
|
||||||
ChatApp chatApp = agent.getChatAppConfig().get(APP_KEY);
|
ChatApp chatApp = agent.getChatAppConfig().get(APP_KEY);
|
||||||
if (Objects.isNull(chatApp) || !chatApp.isEnable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> variable = new HashMap<>();
|
Map<String, Object> variable = new HashMap<>();
|
||||||
variable.put("question", executeContext.getRequest().getQueryText());
|
String question = executeContext.getResponse().getTextResult();// 结果解析应该用改写的问题,因为改写的内容信息量更大
|
||||||
|
if (executeContext.getParseInfo().getProperties() != null
|
||||||
|
&& executeContext.getParseInfo().getProperties().containsKey("CONTEXT")) {
|
||||||
|
Map<String, Object> context = (Map<String, Object>) executeContext.getParseInfo()
|
||||||
|
.getProperties().get("CONTEXT");
|
||||||
|
if (context.get("queryText") != null && "".equals(context.get("queryText"))) {
|
||||||
|
question = context.get("queryText").toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variable.put("question", question);
|
||||||
variable.put("data", queryResult.getTextResult());
|
variable.put("data", queryResult.getTextResult());
|
||||||
|
|
||||||
Prompt prompt = PromptTemplate.from(chatApp.getPrompt()).apply(variable);
|
Prompt prompt = PromptTemplate.from(chatApp.getPrompt()).apply(variable);
|
||||||
|
|||||||
@@ -27,17 +27,18 @@ public class DimensionRecommendProcessor implements ExecuteResultProcessor {
|
|||||||
private static final int recommend_dimension_size = 5;
|
private static final int recommend_dimension_size = 5;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
public boolean accept(ExecuteContext executeContext) {
|
||||||
|
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
||||||
|
return QueryType.AGGREGATE.equals(semanticParseInfo.getQueryType())
|
||||||
|
&& !CollectionUtils.isEmpty(semanticParseInfo.getMetrics());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(ExecuteContext executeContext) {
|
||||||
|
QueryResult queryResult = executeContext.getResponse();
|
||||||
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
||||||
if (!QueryType.AGGREGATE.equals(semanticParseInfo.getQueryType())
|
|
||||||
|| CollectionUtils.isEmpty(semanticParseInfo.getMetrics())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Long dataSetId = semanticParseInfo.getDataSetId();
|
Long dataSetId = semanticParseInfo.getDataSetId();
|
||||||
Optional<SchemaElement> firstMetric = semanticParseInfo.getMetrics().stream().findFirst();
|
Optional<SchemaElement> firstMetric = semanticParseInfo.getMetrics().stream().findFirst();
|
||||||
if (!firstMetric.isPresent()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<SchemaElement> dimensionRecommended =
|
List<SchemaElement> dimensionRecommended =
|
||||||
getDimensions(firstMetric.get().getId(), dataSetId);
|
getDimensions(firstMetric.get().getId(), dataSetId);
|
||||||
queryResult.setRecommendedDimensions(dimensionRecommended);
|
queryResult.setRecommendedDimensions(dimensionRecommended);
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package com.tencent.supersonic.chat.server.processor.execute;
|
package com.tencent.supersonic.chat.server.processor.execute;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
|
||||||
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
||||||
import com.tencent.supersonic.chat.server.processor.ResultProcessor;
|
import com.tencent.supersonic.chat.server.processor.ResultProcessor;
|
||||||
|
|
||||||
/** A ExecuteResultProcessor wraps things up before returning execution results to the users. */
|
/** A ExecuteResultProcessor wraps things up before returning execution results to the users. */
|
||||||
public interface ExecuteResultProcessor extends ResultProcessor {
|
public interface ExecuteResultProcessor extends ResultProcessor {
|
||||||
|
|
||||||
void process(ExecuteContext executeContext, QueryResult queryResult);
|
boolean accept(ExecuteContext executeContext);
|
||||||
|
|
||||||
|
void process(ExecuteContext executeContext);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,14 +59,18 @@ import static com.tencent.supersonic.common.pojo.Constants.TIME_FORMAT;
|
|||||||
public class MetricRatioCalcProcessor implements ExecuteResultProcessor {
|
public class MetricRatioCalcProcessor implements ExecuteResultProcessor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
public boolean accept(ExecuteContext executeContext) {
|
||||||
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
||||||
AggregatorConfig aggregatorConfig = ContextUtils.getBean(AggregatorConfig.class);
|
AggregatorConfig aggregatorConfig = ContextUtils.getBean(AggregatorConfig.class);
|
||||||
if (CollectionUtils.isEmpty(semanticParseInfo.getMetrics())
|
return !CollectionUtils.isEmpty(semanticParseInfo.getMetrics())
|
||||||
|| !aggregatorConfig.getEnableRatio()
|
&& aggregatorConfig.getEnableRatio()
|
||||||
|| !QueryType.AGGREGATE.equals(semanticParseInfo.getQueryType())) {
|
&& QueryType.AGGREGATE.equals(semanticParseInfo.getQueryType());
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void process(ExecuteContext executeContext) {
|
||||||
|
QueryResult queryResult = executeContext.getResponse();
|
||||||
|
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
||||||
AggregateInfo aggregateInfo = getAggregateInfo(executeContext.getRequest().getUser(),
|
AggregateInfo aggregateInfo = getAggregateInfo(executeContext.getRequest().getUser(),
|
||||||
semanticParseInfo, queryResult);
|
semanticParseInfo, queryResult);
|
||||||
queryResult.setAggregateInfo(aggregateInfo);
|
queryResult.setAggregateInfo(aggregateInfo);
|
||||||
@@ -117,8 +121,12 @@ public class MetricRatioCalcProcessor implements ExecuteResultProcessor {
|
|||||||
|
|
||||||
CompletableFuture.allOf(metricInfoRoll, metricInfoOver).join();
|
CompletableFuture.allOf(metricInfoRoll, metricInfoOver).join();
|
||||||
|
|
||||||
metricInfo.setName(metricInfoRoll.get().getName());
|
if (metricInfoRoll.get().getName() != null) {
|
||||||
metricInfo.setValue(metricInfoRoll.get().getValue());
|
metricInfo.setName(metricInfoRoll.get().getName());
|
||||||
|
}
|
||||||
|
if (metricInfoOver.get().getValue() != null) {
|
||||||
|
metricInfo.setValue(metricInfoRoll.get().getValue());
|
||||||
|
}
|
||||||
metricInfo.getStatistics().putAll(metricInfoRoll.get().getStatistics());
|
metricInfo.getStatistics().putAll(metricInfoRoll.get().getStatistics());
|
||||||
metricInfo.getStatistics().putAll(metricInfoOver.get().getStatistics());
|
metricInfo.getStatistics().putAll(metricInfoOver.get().getStatistics());
|
||||||
|
|
||||||
@@ -134,7 +142,7 @@ public class MetricRatioCalcProcessor implements ExecuteResultProcessor {
|
|||||||
return new HashSet<>();
|
return new HashSet<>();
|
||||||
}
|
}
|
||||||
return queryResult.getQueryColumns().stream()
|
return queryResult.getQueryColumns().stream()
|
||||||
.flatMap(c -> SqlSelectHelper.getColumnFromExpr(c.getNameEn()).stream())
|
.flatMap(c -> SqlSelectHelper.getFieldsFromExpr(c.getBizName()).stream())
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,16 +167,16 @@ public class MetricRatioCalcProcessor implements ExecuteResultProcessor {
|
|||||||
|
|
||||||
Map<String, Object> result = queryResp.getResultList().get(0);
|
Map<String, Object> result = queryResp.getResultList().get(0);
|
||||||
Optional<QueryColumn> valueColumn = queryResp.getColumns().stream()
|
Optional<QueryColumn> valueColumn = queryResp.getColumns().stream()
|
||||||
.filter(c -> c.getNameEn().equals(metric.getBizName())).findFirst();
|
.filter(c -> c.getBizName().equals(metric.getBizName())).findFirst();
|
||||||
|
|
||||||
if (!valueColumn.isPresent()) {
|
if (!valueColumn.isPresent()) {
|
||||||
return metricInfo;
|
return metricInfo;
|
||||||
}
|
}
|
||||||
String valueField = String.format("%s_%s", valueColumn.get().getNameEn(),
|
String valueField = String.format("%s_%s", valueColumn.get().getBizName(),
|
||||||
aggOperatorEnum.getOperator());
|
aggOperatorEnum.getOperator());
|
||||||
if (result.containsKey(valueColumn.get().getNameEn())) {
|
if (result.containsKey(valueColumn.get().getBizName())) {
|
||||||
DecimalFormat df = new DecimalFormat("#.####");
|
DecimalFormat df = new DecimalFormat("#.####");
|
||||||
metricInfo.setValue(df.format(result.get(valueColumn.get().getNameEn())));
|
metricInfo.setValue(df.format(result.get(valueColumn.get().getBizName())));
|
||||||
}
|
}
|
||||||
String ratio = "";
|
String ratio = "";
|
||||||
if (Objects.nonNull(result.get(valueField))) {
|
if (Objects.nonNull(result.get(valueField))) {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.tencent.supersonic.chat.server.processor.execute;
|
package com.tencent.supersonic.chat.server.processor.execute;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
|
||||||
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
||||||
import com.tencent.supersonic.common.pojo.Constants;
|
import com.tencent.supersonic.common.pojo.Constants;
|
||||||
import com.tencent.supersonic.common.pojo.enums.DictWordType;
|
import com.tencent.supersonic.common.pojo.enums.DictWordType;
|
||||||
@@ -16,14 +15,7 @@ import dev.langchain4j.store.embedding.RetrieveQuery;
|
|||||||
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,16 +26,20 @@ public class MetricRecommendProcessor implements ExecuteResultProcessor {
|
|||||||
private static final int METRIC_RECOMMEND_SIZE = 5;
|
private static final int METRIC_RECOMMEND_SIZE = 5;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
public boolean accept(ExecuteContext executeContext) {
|
||||||
|
SemanticParseInfo parseInfo = executeContext.getParseInfo();
|
||||||
|
return Objects.nonNull(parseInfo.getQueryType())
|
||||||
|
&& parseInfo.getQueryType().equals(QueryType.AGGREGATE)
|
||||||
|
&& !CollectionUtils.isEmpty(parseInfo.getMetrics())
|
||||||
|
&& parseInfo.getMetrics().size() <= METRIC_RECOMMEND_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(ExecuteContext executeContext) {
|
||||||
fillSimilarMetric(executeContext.getParseInfo());
|
fillSimilarMetric(executeContext.getParseInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillSimilarMetric(SemanticParseInfo parseInfo) {
|
private void fillSimilarMetric(SemanticParseInfo parseInfo) {
|
||||||
if (!parseInfo.getQueryType().equals(QueryType.AGGREGATE)
|
|
||||||
|| parseInfo.getMetrics().size() > METRIC_RECOMMEND_SIZE
|
|
||||||
|| CollectionUtils.isEmpty(parseInfo.getMetrics())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<String> metricNames =
|
List<String> metricNames =
|
||||||
Collections.singletonList(parseInfo.getMetrics().iterator().next().getName());
|
Collections.singletonList(parseInfo.getMetrics().iterator().next().getName());
|
||||||
Map<String, Object> filterCondition = new HashMap<>();
|
Map<String, Object> filterCondition = new HashMap<>();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.tencent.supersonic.chat.server.pojo.ParseContext;
|
|||||||
import com.tencent.supersonic.common.pojo.ChatApp;
|
import com.tencent.supersonic.common.pojo.ChatApp;
|
||||||
import com.tencent.supersonic.common.pojo.enums.AppModule;
|
import com.tencent.supersonic.common.pojo.enums.AppModule;
|
||||||
import com.tencent.supersonic.common.util.ChatAppManager;
|
import com.tencent.supersonic.common.util.ChatAppManager;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
||||||
import com.tencent.supersonic.headless.server.utils.ModelConfigHelper;
|
import com.tencent.supersonic.headless.server.utils.ModelConfigHelper;
|
||||||
import dev.langchain4j.data.message.AiMessage;
|
import dev.langchain4j.data.message.AiMessage;
|
||||||
import dev.langchain4j.model.chat.ChatLanguageModel;
|
import dev.langchain4j.model.chat.ChatLanguageModel;
|
||||||
@@ -26,7 +27,7 @@ public class ErrorMsgRewriteProcessor implements ParseResultProcessor {
|
|||||||
|
|
||||||
private static final Logger keyPipelineLog = LoggerFactory.getLogger("keyPipeline");
|
private static final Logger keyPipelineLog = LoggerFactory.getLogger("keyPipeline");
|
||||||
|
|
||||||
public static final String APP_KEY_ERROR_MESSAGE = "REWRITE_ERROR_MESSAGE";
|
public static final String APP_KEY = "REWRITE_ERROR_MESSAGE";
|
||||||
private static final String REWRITE_ERROR_MESSAGE_INSTRUCTION = ""
|
private static final String REWRITE_ERROR_MESSAGE_INSTRUCTION = ""
|
||||||
+ "#Role: You are a data business partner who closely interacts with business people.\n"
|
+ "#Role: You are a data business partner who closely interacts with business people.\n"
|
||||||
+ "#Task: Your will be provided with user input, system output and some examples, "
|
+ "#Task: Your will be provided with user input, system output and some examples, "
|
||||||
@@ -37,29 +38,36 @@ public class ErrorMsgRewriteProcessor implements ParseResultProcessor {
|
|||||||
+ "#Examples: {{examples}}\n" + "#Response: ";
|
+ "#Examples: {{examples}}\n" + "#Response: ";
|
||||||
|
|
||||||
public ErrorMsgRewriteProcessor() {
|
public ErrorMsgRewriteProcessor() {
|
||||||
ChatAppManager.register(APP_KEY_ERROR_MESSAGE,
|
ChatAppManager.register(APP_KEY,
|
||||||
ChatApp.builder().prompt(REWRITE_ERROR_MESSAGE_INSTRUCTION).name("异常提示改写")
|
ChatApp.builder().prompt(REWRITE_ERROR_MESSAGE_INSTRUCTION).name("异常提示改写")
|
||||||
.appModule(AppModule.CHAT).description("通过大模型将异常信息改写为更友好和引导性的提示用语")
|
.appModule(AppModule.CHAT).description("通过大模型将异常信息改写为更友好和引导性的提示用语")
|
||||||
.enable(false).build());
|
.enable(true).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(ParseContext parseContext) {
|
||||||
|
ChatApp chatApp = parseContext.getAgent().getChatAppConfig().get(APP_KEY);
|
||||||
|
return StringUtils.isNotBlank(parseContext.getResponse().getErrorMsg())
|
||||||
|
&& Objects.nonNull(chatApp) && chatApp.isEnable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(ParseContext parseContext) {
|
public void process(ParseContext parseContext) {
|
||||||
String errMsg = parseContext.getResponse().getErrorMsg();
|
String errMsg = parseContext.getResponse().getErrorMsg();
|
||||||
ChatApp chatApp = parseContext.getAgent().getChatAppConfig().get(APP_KEY_ERROR_MESSAGE);
|
ChatApp chatApp = parseContext.getAgent().getChatAppConfig().get(APP_KEY);
|
||||||
if (StringUtils.isBlank(errMsg) || Objects.isNull(chatApp) || !chatApp.isEnable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> variables = new HashMap<>();
|
Map<String, Object> variables = new HashMap<>();
|
||||||
variables.put("user_question", parseContext.getRequest().getQueryText());
|
variables.put("user_question", parseContext.getRequest().getQueryText());
|
||||||
variables.put("system_message", errMsg);
|
variables.put("system_message", errMsg);
|
||||||
|
|
||||||
StringBuilder exampleStr = new StringBuilder();
|
StringBuilder exampleStr = new StringBuilder();
|
||||||
parseContext.getResponse().getUsedExemplars().forEach(e -> exampleStr.append(
|
if (parseContext.getResponse().getUsedExemplars() != null) {
|
||||||
String.format("<Question:{%s},Schema:{%s}> ", e.getQuestion(), e.getDbSchema())));
|
parseContext.getResponse().getUsedExemplars().forEach(e -> exampleStr.append(String
|
||||||
parseContext.getAgent().getExamples()
|
.format("<Question:{%s},Schema:{%s}> ", e.getQuestion(), e.getDbSchema())));
|
||||||
.forEach(e -> exampleStr.append(String.format("<Question:{%s}> ", e)));
|
}
|
||||||
|
if (parseContext.getAgent().getExamples() != null) {
|
||||||
|
parseContext.getAgent().getExamples()
|
||||||
|
.forEach(e -> exampleStr.append(String.format("<Question:{%s}> ", e)));
|
||||||
|
}
|
||||||
variables.put("examples", exampleStr);
|
variables.put("examples", exampleStr);
|
||||||
|
|
||||||
Prompt prompt = PromptTemplate.from(chatApp.getPrompt()).apply(variables);
|
Prompt prompt = PromptTemplate.from(chatApp.getPrompt()).apply(variables);
|
||||||
@@ -68,6 +76,7 @@ public class ErrorMsgRewriteProcessor implements ParseResultProcessor {
|
|||||||
Response<AiMessage> response = chatLanguageModel.generate(prompt.toUserMessage());
|
Response<AiMessage> response = chatLanguageModel.generate(prompt.toUserMessage());
|
||||||
String rewrittenMsg = response.content().text();
|
String rewrittenMsg = response.content().text();
|
||||||
parseContext.getResponse().setErrorMsg(rewrittenMsg);
|
parseContext.getResponse().setErrorMsg(rewrittenMsg);
|
||||||
|
parseContext.getResponse().setState(ParseResp.ParseState.FAILED);
|
||||||
keyPipelineLog.info("ErrorMessageProcessor modelReq:\n{} \nmodelResp:\n{}", prompt.text(),
|
keyPipelineLog.info("ErrorMessageProcessor modelReq:\n{} \nmodelResp:\n{}", prompt.text(),
|
||||||
rewrittenMsg);
|
rewrittenMsg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,52 @@
|
|||||||
package com.tencent.supersonic.chat.server.processor.parse;
|
package com.tencent.supersonic.chat.server.processor.parse;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.server.plugin.PluginQueryManager;
|
import com.google.common.collect.Lists;
|
||||||
import com.tencent.supersonic.chat.server.pojo.ParseContext;
|
import com.tencent.supersonic.chat.server.pojo.ParseContext;
|
||||||
|
import com.tencent.supersonic.common.jsqlparser.FieldExpression;
|
||||||
|
import com.tencent.supersonic.common.jsqlparser.SqlSelectFunctionHelper;
|
||||||
|
import com.tencent.supersonic.common.jsqlparser.SqlSelectHelper;
|
||||||
|
import com.tencent.supersonic.common.pojo.DateConf;
|
||||||
|
import com.tencent.supersonic.common.pojo.enums.FilterOperatorEnum;
|
||||||
|
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
||||||
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.DataSetSchema;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SqlInfo;
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QueryFilter;
|
import com.tencent.supersonic.headless.api.pojo.request.QueryFilter;
|
||||||
|
import com.tencent.supersonic.headless.server.facade.service.SemanticLayerService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ParseInfoFormatProcessor formats parse info to make it more readable to the users.
|
* ParseInfoFormatProcessor formats parse info to make it more readable to the users.
|
||||||
**/
|
**/
|
||||||
|
@Slf4j
|
||||||
public class ParseInfoFormatProcessor implements ParseResultProcessor {
|
public class ParseInfoFormatProcessor implements ParseResultProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(ParseContext parseContext) {
|
||||||
|
return !parseContext.getResponse().getSelectedParses().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(ParseContext parseContext) {
|
public void process(ParseContext parseContext) {
|
||||||
parseContext.getResponse().getSelectedParses().forEach(p -> {
|
parseContext.getResponse().getSelectedParses().forEach(p -> {
|
||||||
if (PluginQueryManager.isPluginQuery(p.getQueryMode())
|
if (Objects.isNull(p.getDataSet()) || Objects.isNull(p.getSqlInfo().getParsedS2SQL())) {
|
||||||
|| "PLAIN_TEXT".equals(p.getQueryMode())) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
formatNL2SQLParseInfo(p);
|
buildParseInfoFromSQL(p);
|
||||||
|
buildTextInfo(p);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void formatNL2SQLParseInfo(SemanticParseInfo parseInfo) {
|
private void buildTextInfo(SemanticParseInfo parseInfo) {
|
||||||
StringBuilder textBuilder = new StringBuilder();
|
StringBuilder textBuilder = new StringBuilder();
|
||||||
textBuilder.append("**数据集:** ").append(parseInfo.getDataSet().getName()).append(" ");
|
textBuilder.append("**数据集:** ").append(parseInfo.getDataSet().getName()).append(" ");
|
||||||
List<String> metricNames = parseInfo.getMetrics().stream().map(SchemaElement::getName)
|
List<String> metricNames = parseInfo.getMetrics().stream().map(SchemaElement::getName)
|
||||||
@@ -60,4 +78,195 @@ public class ParseInfoFormatProcessor implements ParseResultProcessor {
|
|||||||
}
|
}
|
||||||
parseInfo.setTextInfo(textBuilder.toString());
|
parseInfo.setTextInfo(textBuilder.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void buildParseInfoFromSQL(SemanticParseInfo parseInfo) {
|
||||||
|
SqlInfo sqlInfo = parseInfo.getSqlInfo();
|
||||||
|
String s2SQL = sqlInfo.getCorrectedS2SQL();
|
||||||
|
if (StringUtils.isBlank(s2SQL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseQueryType(parseInfo);
|
||||||
|
List<FieldExpression> expressions = SqlSelectHelper.getFilterExpression(s2SQL);
|
||||||
|
Long dataSetId = parseInfo.getDataSetId();
|
||||||
|
SemanticLayerService semanticLayerService =
|
||||||
|
ContextUtils.getBean(SemanticLayerService.class);
|
||||||
|
DataSetSchema dsSchema = semanticLayerService.getDataSetSchema(dataSetId);
|
||||||
|
|
||||||
|
// extract date filter from S2SQL
|
||||||
|
try {
|
||||||
|
if (!CollectionUtils.isEmpty(expressions)) {
|
||||||
|
parseInfo.setDateInfo(extractDateFilter(expressions, dsSchema));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("failed to extract date range:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract dimension filters from S2SQL
|
||||||
|
try {
|
||||||
|
List<QueryFilter> queryFilters = extractDimensionFilter(dsSchema, expressions);
|
||||||
|
parseInfo.getDimensionFilters().addAll(queryFilters);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("failed to extract dimension filters:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract metrics from S2SQL
|
||||||
|
List<String> allFields =
|
||||||
|
filterDateField(dsSchema, SqlSelectHelper.getAllSelectFields(s2SQL));
|
||||||
|
Set<SchemaElement> metrics = matchSchemaElements(allFields, dsSchema.getMetrics());
|
||||||
|
parseInfo.setMetrics(metrics);
|
||||||
|
|
||||||
|
// extract dimensions from S2SQL
|
||||||
|
if (QueryType.AGGREGATE.equals(parseInfo.getQueryType())) {
|
||||||
|
List<String> groupByFields = SqlSelectHelper.getGroupByFields(s2SQL);
|
||||||
|
List<String> groupByDimensions = filterDateField(dsSchema, groupByFields);
|
||||||
|
parseInfo.setDimensions(
|
||||||
|
matchSchemaElements(groupByDimensions, dsSchema.getDimensions()));
|
||||||
|
} else if (QueryType.DETAIL.equals(parseInfo.getQueryType())) {
|
||||||
|
List<String> selectFields = SqlSelectHelper.getSelectFields(s2SQL);
|
||||||
|
List<String> selectDimensions = filterDateField(dsSchema, selectFields);
|
||||||
|
parseInfo
|
||||||
|
.setDimensions(matchSchemaElements(selectDimensions, dsSchema.getDimensions()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<SchemaElement> matchSchemaElements(List<String> allFields,
|
||||||
|
Set<SchemaElement> elements) {
|
||||||
|
return elements.stream().filter(schemaElement -> {
|
||||||
|
if (CollectionUtils.isEmpty(schemaElement.getAlias())) {
|
||||||
|
return allFields.contains(schemaElement.getName());
|
||||||
|
}
|
||||||
|
Set<String> allFieldsSet = new HashSet<>(allFields);
|
||||||
|
Set<String> aliasSet = new HashSet<>(schemaElement.getAlias());
|
||||||
|
List<String> intersection =
|
||||||
|
allFieldsSet.stream().filter(aliasSet::contains).collect(Collectors.toList());
|
||||||
|
return allFields.contains(schemaElement.getName())
|
||||||
|
|| !CollectionUtils.isEmpty(intersection);
|
||||||
|
}).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> filterDateField(DataSetSchema dataSetSchema, List<String> allFields) {
|
||||||
|
return allFields.stream().filter(entry -> !isPartitionDimension(dataSetSchema, entry))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<QueryFilter> extractDimensionFilter(DataSetSchema dsSchema,
|
||||||
|
List<FieldExpression> fieldExpressions) {
|
||||||
|
|
||||||
|
Map<String, SchemaElement> fieldNameToElement = getNameToElement(dsSchema);
|
||||||
|
List<QueryFilter> result = Lists.newArrayList();
|
||||||
|
for (FieldExpression expression : fieldExpressions) {
|
||||||
|
QueryFilter dimensionFilter = new QueryFilter();
|
||||||
|
dimensionFilter.setValue(expression.getFieldValue());
|
||||||
|
SchemaElement schemaElement = fieldNameToElement.get(expression.getFieldName());
|
||||||
|
if (Objects.isNull(schemaElement)
|
||||||
|
|| isPartitionDimension(dsSchema, schemaElement.getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dimensionFilter.setName(schemaElement.getName());
|
||||||
|
dimensionFilter.setBizName(schemaElement.getBizName());
|
||||||
|
dimensionFilter.setElementID(schemaElement.getId());
|
||||||
|
|
||||||
|
FilterOperatorEnum operatorEnum =
|
||||||
|
FilterOperatorEnum.getSqlOperator(expression.getOperator());
|
||||||
|
dimensionFilter.setOperator(operatorEnum);
|
||||||
|
dimensionFilter.setFunction(expression.getFunction());
|
||||||
|
result.add(dimensionFilter);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateConf extractDateFilter(List<FieldExpression> fieldExpressions,
|
||||||
|
DataSetSchema dataSetSchema) {
|
||||||
|
List<FieldExpression> dateExpressions = fieldExpressions.stream().filter(
|
||||||
|
expression -> isPartitionDimension(dataSetSchema, expression.getFieldName()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isEmpty(dateExpressions)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DateConf dateInfo = new DateConf();
|
||||||
|
dateInfo.setDateMode(DateConf.DateMode.BETWEEN);
|
||||||
|
FieldExpression firstExpression = dateExpressions.get(0);
|
||||||
|
|
||||||
|
FilterOperatorEnum firstOperator =
|
||||||
|
FilterOperatorEnum.getSqlOperator(firstExpression.getOperator());
|
||||||
|
if (FilterOperatorEnum.EQUALS.equals(firstOperator)
|
||||||
|
&& Objects.nonNull(firstExpression.getFieldValue())) {
|
||||||
|
dateInfo.setStartDate(firstExpression.getFieldValue().toString());
|
||||||
|
dateInfo.setEndDate(firstExpression.getFieldValue().toString());
|
||||||
|
dateInfo.setDateMode(DateConf.DateMode.BETWEEN);
|
||||||
|
return dateInfo;
|
||||||
|
}
|
||||||
|
if (containOperators(firstExpression, firstOperator, FilterOperatorEnum.GREATER_THAN,
|
||||||
|
FilterOperatorEnum.GREATER_THAN_EQUALS)) {
|
||||||
|
dateInfo.setStartDate(firstExpression.getFieldValue().toString());
|
||||||
|
if (hasSecondDate(dateExpressions)) {
|
||||||
|
dateInfo.setEndDate(dateExpressions.get(1).getFieldValue().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (containOperators(firstExpression, firstOperator, FilterOperatorEnum.MINOR_THAN,
|
||||||
|
FilterOperatorEnum.MINOR_THAN_EQUALS)) {
|
||||||
|
dateInfo.setEndDate(firstExpression.getFieldValue().toString());
|
||||||
|
if (hasSecondDate(dateExpressions)) {
|
||||||
|
dateInfo.setStartDate(dateExpressions.get(1).getFieldValue().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dateInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPartitionDimension(DataSetSchema dataSetSchema, String sqlFieldName) {
|
||||||
|
if (Objects.isNull(dataSetSchema) || Objects.isNull(dataSetSchema.getPartitionDimension())
|
||||||
|
|| Objects.isNull(dataSetSchema.getPartitionDimension().getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return sqlFieldName.equalsIgnoreCase(dataSetSchema.getPartitionDimension().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean containOperators(FieldExpression expression, FilterOperatorEnum firstOperator,
|
||||||
|
FilterOperatorEnum... operatorEnums) {
|
||||||
|
return (Arrays.asList(operatorEnums).contains(firstOperator)
|
||||||
|
&& Objects.nonNull(expression.getFieldValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasSecondDate(List<FieldExpression> dateExpressions) {
|
||||||
|
return dateExpressions.size() > 1
|
||||||
|
&& Objects.nonNull(dateExpressions.get(1).getFieldValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, SchemaElement> getNameToElement(DataSetSchema dsSchema) {
|
||||||
|
Set<SchemaElement> dimensions = dsSchema.getDimensions();
|
||||||
|
Set<SchemaElement> metrics = dsSchema.getMetrics();
|
||||||
|
|
||||||
|
List<SchemaElement> allElements = Lists.newArrayList();
|
||||||
|
allElements.addAll(dimensions);
|
||||||
|
allElements.addAll(metrics);
|
||||||
|
// support alias
|
||||||
|
return allElements.stream().flatMap(schemaElement -> {
|
||||||
|
Set<Pair<String, SchemaElement>> result = new HashSet<>();
|
||||||
|
result.add(Pair.of(schemaElement.getName(), schemaElement));
|
||||||
|
List<String> aliasList = schemaElement.getAlias();
|
||||||
|
if (!org.springframework.util.CollectionUtils.isEmpty(aliasList)) {
|
||||||
|
for (String alias : aliasList) {
|
||||||
|
result.add(Pair.of(alias, schemaElement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.stream();
|
||||||
|
}).collect(Collectors.toMap(Pair::getLeft, Pair::getRight, (value1, value2) -> value2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseQueryType(SemanticParseInfo parseInfo) {
|
||||||
|
parseInfo.setQueryType(QueryType.DETAIL);
|
||||||
|
SqlInfo sqlInfo = parseInfo.getSqlInfo();
|
||||||
|
if (Objects.isNull(sqlInfo) || StringUtils.isBlank(sqlInfo.getCorrectedS2SQL())) {
|
||||||
|
parseInfo.setQueryType(QueryType.DETAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. AGG queryType
|
||||||
|
if (Objects.nonNull(sqlInfo) && StringUtils.isNotBlank(sqlInfo.getParsedS2SQL())
|
||||||
|
&& SqlSelectFunctionHelper.hasAggregateFunction(sqlInfo.getCorrectedS2SQL())) {
|
||||||
|
parseInfo.setQueryType(QueryType.AGGREGATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,5 +6,7 @@ import com.tencent.supersonic.chat.server.processor.ResultProcessor;
|
|||||||
/** A ParseResultProcessor wraps things up before returning parsing results to the users. */
|
/** A ParseResultProcessor wraps things up before returning parsing results to the users. */
|
||||||
public interface ParseResultProcessor extends ResultProcessor {
|
public interface ParseResultProcessor extends ResultProcessor {
|
||||||
|
|
||||||
|
boolean accept(ParseContext parseContext);
|
||||||
|
|
||||||
void process(ParseContext parseContext);
|
void process(ParseContext parseContext);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ import java.util.stream.Collectors;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class QueryRecommendProcessor implements ParseResultProcessor {
|
public class QueryRecommendProcessor implements ParseResultProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(ParseContext parseContext) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(ParseContext parseContext) {
|
public void process(ParseContext parseContext) {
|
||||||
CompletableFuture.runAsync(() -> doProcess(parseContext));
|
CompletableFuture.runAsync(() -> doProcess(parseContext));
|
||||||
@@ -56,8 +61,7 @@ public class QueryRecommendProcessor implements ParseResultProcessor {
|
|||||||
private void updateChatQuery(ChatQueryDO chatQueryDO) {
|
private void updateChatQuery(ChatQueryDO chatQueryDO) {
|
||||||
ChatQueryRepository chatQueryRepository = ContextUtils.getBean(ChatQueryRepository.class);
|
ChatQueryRepository chatQueryRepository = ContextUtils.getBean(ChatQueryRepository.class);
|
||||||
UpdateWrapper<ChatQueryDO> updateWrapper = new UpdateWrapper<>();
|
UpdateWrapper<ChatQueryDO> updateWrapper = new UpdateWrapper<>();
|
||||||
updateWrapper.eq("question_id", chatQueryDO.getQuestionId());
|
updateWrapper.lambda().eq(ChatQueryDO::getQuestionId, chatQueryDO.getQuestionId());
|
||||||
updateWrapper.set("similar_queries", chatQueryDO.getSimilarQueries());
|
|
||||||
chatQueryRepository.updateChatQuery(chatQueryDO, updateWrapper);
|
chatQueryRepository.updateChatQuery(chatQueryDO, updateWrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user