mirror of
https://github.com/tencentmusic/supersonic.git
synced 2026-04-21 14:14:19 +08:00
Compare commits
2 Commits
master
...
f4be6f65ec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4be6f65ec | ||
|
|
5b45cfbad7 |
69
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
69
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -11,28 +11,59 @@ 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: input
|
- type: checkboxes
|
||||||
id: version
|
|
||||||
attributes:
|
attributes:
|
||||||
label: SuperSonic version
|
label: Search before asking
|
||||||
description: Please tell us which version you are using.
|
description: >
|
||||||
placeholder: "0.9.8"
|
Please make sure to search in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) first to see
|
||||||
validations:
|
whether the same issue was reported already.
|
||||||
required: true
|
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: input
|
- type: textarea
|
||||||
id: organization
|
|
||||||
attributes:
|
attributes:
|
||||||
label: Your organization
|
label: Version
|
||||||
description: Please tell us your organization so that we can provide you better support and advice.
|
description: What is the current version
|
||||||
placeholder: "TME..."
|
placeholder: >
|
||||||
|
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: Description
|
label: What's Wrong?
|
||||||
description: Describe the bug you met.
|
description: Describe the bug.
|
||||||
|
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:
|
||||||
@@ -43,6 +74,16 @@ 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,20 +8,30 @@ 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: input
|
- type: textarea
|
||||||
id: organization
|
|
||||||
attributes:
|
attributes:
|
||||||
label: Your organization
|
label: Solution
|
||||||
description: Please tell us your organization so that we can provide you better support and advice.
|
placeholder: >
|
||||||
placeholder: "TME..."
|
Add overview of proposed solution.
|
||||||
validations:
|
|
||||||
required: true
|
Add related materials like links if they exist.
|
||||||
|
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
@@ -32,6 +42,16 @@ 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,19 +8,33 @@ 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: input
|
- type: textarea
|
||||||
id: organization
|
|
||||||
attributes:
|
attributes:
|
||||||
label: Your organization
|
label: Use case
|
||||||
description: Please tell us your organization so that we can provide you better support and advice.
|
placeholder: >
|
||||||
placeholder: "TME..."
|
What problem does this feature mainly solve, or what scenarios it is suitable for.
|
||||||
validations:
|
|
||||||
required: true
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Related issues
|
||||||
|
description: Is there currently another issue associated with this?
|
||||||
|
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
@@ -31,4 +45,16 @@ 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,7 +8,6 @@ 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:
|
||||||
@@ -17,12 +16,43 @@ body:
|
|||||||
placeholder: "Type your question here..."
|
placeholder: "Type your question here..."
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
- type: textarea
|
||||||
- type: input
|
id: additional-context
|
||||||
id: organization
|
|
||||||
attributes:
|
attributes:
|
||||||
label: Your organization
|
label: Provide any additional context or information
|
||||||
description: Please tell us your organization so that we can provide you better support and advice.
|
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.
|
||||||
placeholder: "TME..."
|
placeholder: "Add context here..."
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: false
|
||||||
|
- 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
|
||||||
11
.github/workflows/centos-ci.yml
vendored
11
.github/workflows/centos-ci.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: almalinux:9 # maven >=3.6.3
|
image: quay.io/centos/centos:stream8 # 使用 CentOS Stream 8 容器
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -28,10 +28,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Reset DNF repositories
|
- name: Reset DNF repositories
|
||||||
run: |
|
run: |
|
||||||
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
|
cd /etc/yum.repos.d/
|
||||||
-e 's|^# baseurl=https://repo.almalinux.org|baseurl=https://mirrors.aliyun.com|g' \
|
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
|
||||||
/etc/yum.repos.d/almalinux*.repo
|
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
|
||||||
|
|
||||||
|
|
||||||
- name: Update DNF package index
|
- name: Update DNF package index
|
||||||
run: dnf makecache
|
run: dnf makecache
|
||||||
@@ -48,7 +47,7 @@ jobs:
|
|||||||
mvn -version
|
mvn -version
|
||||||
|
|
||||||
- name: Cache Maven packages
|
- name: Cache Maven packages
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: ~/.m2
|
path: ~/.m2
|
||||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||||
|
|||||||
6
.github/workflows/docker-publish.yml
vendored
6
.github/workflows/docker-publish.yml
vendored
@@ -28,5 +28,7 @@ jobs:
|
|||||||
- name: Build and publish Docker image
|
- name: Build and publish Docker image
|
||||||
run: |
|
run: |
|
||||||
VERSION=${{ github.event.inputs.version }}
|
VERSION=${{ github.event.inputs.version }}
|
||||||
chmod +x docker/docker-build-publish.sh
|
chmod +x docker/docker-build.sh
|
||||||
sh docker/docker-build-publish.sh $VERSION
|
chmod +x docker/docker-publish.sh
|
||||||
|
sh docker/docker-build.sh $VERSION
|
||||||
|
sh docker/docker-publish.sh $VERSION
|
||||||
14
.github/workflows/mac-ci.yml
vendored
14
.github/workflows/mac-ci.yml
vendored
@@ -17,27 +17,21 @@ jobs:
|
|||||||
java-version: [21] # Define the JDK versions to test
|
java-version: [21] # Define the JDK versions to test
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up JDK ${{ matrix.java-version }}
|
- name: Set up JDK ${{ matrix.java-version }}
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: ${{ matrix.java-version }}
|
java-version: ${{ matrix.java-version }}
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
|
|
||||||
- name: Cache Maven packages
|
- name: Cache Maven packages
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/ubuntu-ci.yml
vendored
2
.github/workflows/ubuntu-ci.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
|||||||
distribution: 'adopt'
|
distribution: 'adopt'
|
||||||
|
|
||||||
- name: Cache Maven packages
|
- name: Cache Maven packages
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: ~/.m2
|
path: ~/.m2
|
||||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||||
|
|||||||
2
.github/workflows/windows-ci.yml
vendored
2
.github/workflows/windows-ci.yml
vendored
@@ -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@v4
|
uses: actions/cache@v2
|
||||||
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') }}
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -19,6 +19,4 @@ assembly/runtime/*
|
|||||||
chm_db/
|
chm_db/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
/dict
|
/dict
|
||||||
assembly/build/*-SNAPSHOT
|
assembly/build/*-SNAPSHOT
|
||||||
**/node_modules/
|
|
||||||
benchmark/res/
|
|
||||||
199
CHANGELOG.md
199
CHANGELOG.md
@@ -3,205 +3,6 @@
|
|||||||
- All notable changes to this project will be documented in this file.
|
- All notable changes to this project will be documented in this file.
|
||||||
- "Breaking Changes" describes any changes that may break existing functionality or cause
|
- "Breaking Changes" describes any changes that may break existing functionality or cause
|
||||||
compatibility issues with previous versions.
|
compatibility issues with previous versions.
|
||||||
## SuperSonic [1.0.0] - 2025-08-05
|
|
||||||
|
|
||||||
### 重大特性变更 / Major Features
|
|
||||||
|
|
||||||
#### 多数据库支持扩展 / Multi-Database Support
|
|
||||||
- **Oracle数据库支持**: 新增Oracle数据库引擎类型及适配器 ([8eeed87ba](https://github.com/tencentmusic/supersonic/commit/8eeed87ba) by supersonicbi)
|
|
||||||
- **StarRocks支持**: 支持StarRocks和多catalog功能 ([33268bf3d](https://github.com/tencentmusic/supersonic/commit/33268bf3d) by zyclove)
|
|
||||||
- **SAP HANA支持**: 新增SAP HANA数据库适配支持 ([2e28a4c7a](https://github.com/tencentmusic/supersonic/commit/2e28a4c7a) by wwsheng009)
|
|
||||||
- **DuckDB支持**: 支持DuckDB数据库 ([a058dc8b6](https://github.com/tencentmusic/supersonic/commit/a058dc8b6) by jerryjzhang)
|
|
||||||
- **Kyuubi支持**: 支持Kyuubi Presto Trino ([5e3bafb95](https://github.com/tencentmusic/supersonic/commit/5e3bafb95) by zyclove)
|
|
||||||
- **OpenSearch支持**: 新增OpenSearch支持 ([d942d35c9](https://github.com/tencentmusic/supersonic/commit/d942d35c9) by zyclove)
|
|
||||||
|
|
||||||
#### 智能问答增强 / AI-Enhanced Query Processing
|
|
||||||
- **LLM纠错器**: 新增LLM物理SQL纠错器 ([f899d23b6](https://github.com/tencentmusic/supersonic/commit/f899d23b6) by 柯慕灵)
|
|
||||||
- **记忆管理**: Agent记忆管理启用few-shot优先机制 ([fae9118c2](https://github.com/tencentmusic/supersonic/commit/fae9118c2) by feelshana)
|
|
||||||
- **结构化查询**: 支持struct查询中的offset子句 ([d2a43a99c](https://github.com/tencentmusic/supersonic/commit/d2a43a99c) by jerryjzhang)
|
|
||||||
- **向量召回优化**: 优化嵌入向量召回机制 ([8c6ae6252](https://github.com/tencentmusic/supersonic/commit/8c6ae6252) by lexluo09)
|
|
||||||
|
|
||||||
#### 权限管理系统 / Permission Management
|
|
||||||
- **Agent权限**: 支持agent级别的权限管理 ([b5aa6e046](https://github.com/tencentmusic/supersonic/commit/b5aa6e046) by jerryjzhang)
|
|
||||||
- **用户管理**: 支持用户删除功能 ([1c9cf788c](https://github.com/tencentmusic/supersonic/commit/1c9cf788c) by supersonicbi)
|
|
||||||
- **鉴权优化**: 全面优化鉴权与召回机制 ([1faf84e37](https://github.com/tencentmusic/supersonic/commit/1faf84e37), [7e6639df8](https://github.com/tencentmusic/supersonic/commit/7e6639df8) by guilinlewis)
|
|
||||||
|
|
||||||
### 架构升级 / Architecture Upgrades
|
|
||||||
|
|
||||||
#### 核心框架升级 / Core Framework Upgrades
|
|
||||||
- **SpringBoot 3升级**: 完成SpringBoot 3.x升级 ([07f6be51c](https://github.com/tencentmusic/supersonic/commit/07f6be51c) by mislayming)
|
|
||||||
- **依赖升级**: 升级依赖包并修复安全漏洞 ([232a20227](https://github.com/tencentmusic/supersonic/commit/232a20227) by beat4ocean)
|
|
||||||
- **LangChain4j更新**: 替换已废弃的LangChain4j APIs ([acffc03c7](https://github.com/tencentmusic/supersonic/commit/acffc03c7) by beat4ocean)
|
|
||||||
- **Swagger升级**: 使用SpringDoc支持Swagger在Spring 3.x ([758d170bb](https://github.com/tencentmusic/supersonic/commit/758d170bb) by jerryjzhang)
|
|
||||||
|
|
||||||
#### 许可证变更 / License Changes
|
|
||||||
- **Apache 2.0**: 从MIT更改为Apache 2.0许可证 ([0aa002882](https://github.com/tencentmusic/supersonic/commit/0aa002882) by jerryjzhang)
|
|
||||||
|
|
||||||
### 性能优化 / Performance Improvements
|
|
||||||
|
|
||||||
#### 系统性能 / System Performance
|
|
||||||
- **GC优化**: 实现Generational ZGC ([3fc1ec42b](https://github.com/tencentmusic/supersonic/commit/3fc1ec42b) by beat4ocean)
|
|
||||||
- **Docker优化**: 减少Docker镜像体积 ([614917ba7](https://github.com/tencentmusic/supersonic/commit/614917ba7) by kino)
|
|
||||||
- **并行处理**: 嵌入向量并行执行优化 ([8c6ae6252](https://github.com/tencentmusic/supersonic/commit/8c6ae6252) by lexluo09)
|
|
||||||
- **记忆评估**: 记忆评估性能优化 ([524ec38ed](https://github.com/tencentmusic/supersonic/commit/524ec38ed) by yudong)
|
|
||||||
- **多平台构建**: 支持Docker多平台构建 ([da6d28c18](https://github.com/tencentmusic/supersonic/commit/da6d28c18) by jerryjzhang)
|
|
||||||
|
|
||||||
#### 数据处理优化 / Data Processing Optimization
|
|
||||||
- **日期格式**: 支持更多日期字符串格式 ([2b13866c0](https://github.com/tencentmusic/supersonic/commit/2b13866c0) by supersonicbi)
|
|
||||||
- **SQL优化**: 优化SQL生成和执行性能 ([0ab764329](https://github.com/tencentmusic/supersonic/commit/0ab764329) by jerryjzhang)
|
|
||||||
- **模型关联**: 优化模型关联查询性能 ([47c2595fb](https://github.com/tencentmusic/supersonic/commit/47c2595fb) by Willy-J)
|
|
||||||
|
|
||||||
### 功能增强 / Feature Enhancements
|
|
||||||
|
|
||||||
#### 前端界面优化 / Frontend Improvements
|
|
||||||
- **图表导出**: 消息支持导出图表图片 ([ce9ae1c0c](https://github.com/tencentmusic/supersonic/commit/ce9ae1c0c) by pisces)
|
|
||||||
- **路由重构**: 重构语义建模路由交互 ([82c63a7f2](https://github.com/tencentmusic/supersonic/commit/82c63a7f2) by tristanliu)
|
|
||||||
- **权限界面**: 统一助理权限设置交互界面 ([46d64d78f](https://github.com/tencentmusic/supersonic/commit/46d64d78f) by tristanliu)
|
|
||||||
- **图表优化**: 优化ChatMsg图表条件 ([06fb6ba74](https://github.com/tencentmusic/supersonic/commit/06fb6ba74) by FredTsang)
|
|
||||||
- **数据格式**: 提取formatByDataFormatType()方法 ([9ffdba956](https://github.com/tencentmusic/supersonic/commit/9ffdba956) by FredTsang)
|
|
||||||
|
|
||||||
#### 开发体验 / Developer Experience
|
|
||||||
- **构建脚本**: 优化Web应用构建脚本 ([baae7f74b](https://github.com/tencentmusic/supersonic/commit/baae7f74b) by zyclove)
|
|
||||||
- **GitHub Actions**: 优化GitHub Actions镜像推送 ([6a4458a57](https://github.com/tencentmusic/supersonic/commit/6a4458a57) by lexluo09)
|
|
||||||
- **基准测试**: 改进基准测试,增加解析结果分析 ([97710a90c](https://github.com/tencentmusic/supersonic/commit/97710a90c) by Antgeek)
|
|
||||||
|
|
||||||
### Bug修复 / Bug Fixes
|
|
||||||
|
|
||||||
#### 核心功能修复 / Core Function Fixes
|
|
||||||
- **插件功能**: 修复插件功能无法调用/结果被NL2SQL覆盖问题 ([c75233e37](https://github.com/tencentmusic/supersonic/commit/c75233e37) by QJ_wonder)
|
|
||||||
- **维度别名**: 修复映射阶段维度值别名不生效问题 ([785bda6cd](https://github.com/tencentmusic/supersonic/commit/785bda6cd) by feelshana)
|
|
||||||
- **模型字段**: 修复模型字段更新问题 ([6bd897084](https://github.com/tencentmusic/supersonic/commit/6bd897084) by WDEP)
|
|
||||||
- **多轮对话**: 修复headless中字段查询及多轮对话使用问题 ([be0447ae1](https://github.com/tencentmusic/supersonic/commit/be0447ae1) by QJ_wonder)
|
|
||||||
|
|
||||||
#### NPE异常修复 / NPE Exception Fixes
|
|
||||||
- **聊天查询**: 修复EmbeddingMatchStrategy.detectByBatch() NPE异常 ([6d907b6ad](https://github.com/tencentmusic/supersonic/commit/6d907b6ad) by wangyong)
|
|
||||||
- **文件处理**: 修复FileHandlerImpl.convert2Resp() 维度值数据行首字符为空格异常 ([da172a030](https://github.com/tencentmusic/supersonic/commit/da172a030) by wangyong)
|
|
||||||
- **头部服务**: 修复多处headless NPE问题 ([79a44b27e](https://github.com/tencentmusic/supersonic/commit/79a44b27e) by jerryjzhang)
|
|
||||||
- **解析信息**: 修复getParseInfo中的NPE ([dce9a8a58](https://github.com/tencentmusic/supersonic/commit/dce9a8a58) by supersonicbi)
|
|
||||||
|
|
||||||
#### SQL兼容性修复 / SQL Compatibility Fixes
|
|
||||||
- **SQL处理**: 修复SQL前后换行符导致的语句结尾";"删除问题 ([55ac3d1aa](https://github.com/tencentmusic/supersonic/commit/55ac3d1aa) by wangyong)
|
|
||||||
- **查询别名**: DictUtils.constructQuerySqlReq针对sql query增加别名 ([042791762](https://github.com/tencentmusic/supersonic/commit/042791762) by andybj0228)
|
|
||||||
- **SQL变量**: 支持SQL脚本变量替换 ([0709575cd](https://github.com/tencentmusic/supersonic/commit/0709575cd) by wanglongqiang)
|
|
||||||
|
|
||||||
#### 前端Bug修复 / Frontend Bug Fixes
|
|
||||||
- **UI样式**: 修复问答对话右侧历史对话模块样式异常 ([c33a85b58](https://github.com/tencentmusic/supersonic/commit/c33a85b58) by wangyong)
|
|
||||||
- **推荐维度**: 修复页面不显示推荐下钻维度问题 ([62b9db679](https://github.com/tencentmusic/supersonic/commit/62b9db679) by WDEP)
|
|
||||||
- **图表显示**: 修复饼图显示条件问题 ([1b8cd7f0d](https://github.com/tencentmusic/supersonic/commit/1b8cd7f0d) by WDEP)
|
|
||||||
- **负数支持**: 支持负数显示 ([2552e2ae4](https://github.com/tencentmusic/supersonic/commit/2552e2ae4) by FredTsang)
|
|
||||||
- **百分比显示**: 支持bar图needMultiply100显示正确百分比值 ([8abfc923a](https://github.com/tencentmusic/supersonic/commit/8abfc923a) by coosir)
|
|
||||||
- **TypeScript错误**: 修复前端TypeScript错误 ([5585b9e22](https://github.com/tencentmusic/supersonic/commit/5585b9e22) by poncheen)
|
|
||||||
|
|
||||||
#### 系统兼容性修复 / System Compatibility Fixes
|
|
||||||
- **Windows脚本**: 修复Windows daemon.bat路径配置问题 ([e5a41765b](https://github.com/tencentmusic/supersonic/commit/e5a41765b) by 柯慕灵)
|
|
||||||
- **字符编码**: 将utf8编码修改为utf8mb4,解决字符问题 ([2e81b190a](https://github.com/tencentmusic/supersonic/commit/2e81b190a) by Kun Gu)
|
|
||||||
- **记忆缓存**: 修复记忆管理中因缓存无法存储的问题 ([81cd60d2d](https://github.com/tencentmusic/supersonic/commit/81cd60d2d) by guilinlewis)
|
|
||||||
- **Mac兼容**: 降级djl库以支持Mac Intel机器 ([bf3213e8f](https://github.com/tencentmusic/supersonic/commit/bf3213e8f) by jerryjzhang)
|
|
||||||
|
|
||||||
### 数据管理优化 / Data Management Improvements
|
|
||||||
|
|
||||||
#### 维度指标管理 / Dimension & Metric Management
|
|
||||||
- **维度检索**: 修复维度和指标检索及百分比显示问题 ([d8fe2ed2b](https://github.com/tencentmusic/supersonic/commit/d8fe2ed2b) by 木鱼和尚)
|
|
||||||
- **查询导出**: 基于queryColumns导出数据 ([11d1264d3](https://github.com/tencentmusic/supersonic/commit/11d1264d3) by FredTsang)
|
|
||||||
- **表格排序**: 移除表格defaultSortOrder ([32675387d](https://github.com/tencentmusic/supersonic/commit/32675387d) by FredTsang)
|
|
||||||
- **维度搜索**: 修复维度搜索带key查询范围超出问题 ([269f146c1](https://github.com/tencentmusic/supersonic/commit/269f146c1) by wangyong)
|
|
||||||
|
|
||||||
### 测试和质量保证 / Testing & Quality Assurance
|
|
||||||
|
|
||||||
#### 单元测试 / Unit Testing
|
|
||||||
- **测试修复**: 修复单元测试用例 ([91e4b51ef](https://github.com/tencentmusic/supersonic/commit/91e4b51ef) by jerryjzhang)
|
|
||||||
- **模型测试**: 修复ModelCreateForm.tsx错误 ([d2aa73b85](https://github.com/tencentmusic/supersonic/commit/d2aa73b85) by Antgeek)
|
|
||||||
|
|
||||||
### 重要变更说明 / Breaking Changes
|
|
||||||
|
|
||||||
#### 升级注意事项 / Upgrade Notes
|
|
||||||
1. **SpringBoot 3升级**: 可能需要更新依赖配置和代码适配
|
|
||||||
2. **许可证变更**: 从MIT变更为Apache 2.0,请注意法律合规
|
|
||||||
3. **API接口调整**: 部分API接口为支持新功能进行了调整
|
|
||||||
4. **数据库兼容**: 新增多种数据库支持,配置方式有所变化
|
|
||||||
|
|
||||||
### 完整提交统计 / Commit Statistics
|
|
||||||
- **总提交数**: 419个提交
|
|
||||||
- **主要贡献者**:
|
|
||||||
- jerryjzhang: 158次提交
|
|
||||||
- supersonicbi: 22次提交
|
|
||||||
- zyclove: 20次提交
|
|
||||||
- beat4ocean: 15次提交
|
|
||||||
- guilinlewis: 11次提交
|
|
||||||
- wangyong: 11次提交
|
|
||||||
- 其他贡献者: 182次提交
|
|
||||||
- **涉及模块**: headless, chat, auth, common, webapp, launcher, docker
|
|
||||||
- **时间跨度**: 2024年11月1日 - 2025年8月5日
|
|
||||||
|
|
||||||
### 致谢 / Acknowledgments
|
|
||||||
|
|
||||||
感谢所有为SuperSonic 1.0.0版本贡献代码、文档、测试和建议的开发者们!🎉
|
|
||||||
|
|
||||||
#### 核心贡献者 / Core Contributors
|
|
||||||
- **jerryjzhang** - 项目维护者,核心架构设计与实现
|
|
||||||
- **supersonicbi** - 核心功能开发,多数据库支持
|
|
||||||
- **beat4ocean** - 架构升级,依赖管理,安全优化
|
|
||||||
- **zyclove** - 数据库适配,构建优化
|
|
||||||
- **guilinlewis** - 鉴权系统,召回优化
|
|
||||||
- **wangyong** - Bug修复,NPE异常处理
|
|
||||||
|
|
||||||
#### 活跃贡献者 / Active Contributors
|
|
||||||
- **WDEP** - 前端优化,图表功能
|
|
||||||
- **FredTsang** - Chat SDK优化,数据导出
|
|
||||||
- **feelshana** - 记忆管理,向量召回
|
|
||||||
- **QJ_wonder** - 插件功能,多轮对话
|
|
||||||
- **Willy-J** - 模型关联,数据库兼容
|
|
||||||
- **iridescentpeo** - 查询优化,模型管理
|
|
||||||
- **tristanliu** - 前端路由,权限界面
|
|
||||||
- **mislayming** - SpringBoot 3升级
|
|
||||||
- **Antgeek** - 基准测试,模型修复
|
|
||||||
- **柯慕灵** - LLM纠错器,Windows脚本
|
|
||||||
- **superhero** - 项目管理,代码审查
|
|
||||||
|
|
||||||
#### 其他重要贡献者 / Other Important Contributors
|
|
||||||
- **木鱼和尚** - 维度指标检索优化
|
|
||||||
- **pisces** - 图表导出功能
|
|
||||||
- **lexluo09** - 并行处理,GitHub Actions
|
|
||||||
- **andybj0228** - SQL查询优化
|
|
||||||
- **wanglongqiang** - SQL变量支持
|
|
||||||
- **Hyman_bz** - StarRocks支持
|
|
||||||
- **wwsheng009** - SAP HANA适配
|
|
||||||
- **poncheen** - TypeScript错误修复
|
|
||||||
- **kino** - Docker镜像优化
|
|
||||||
- **coosir** - 前端百分比显示
|
|
||||||
- **Kun Gu** - 字符编码优化
|
|
||||||
- **chixiaopao** - NPE异常修复
|
|
||||||
- **naimehao** - 核心功能修复
|
|
||||||
- **yudong** - 记忆评估优化
|
|
||||||
- **mroldx** - 数据库脚本更新
|
|
||||||
- **ChPi** - 解析器性能优化
|
|
||||||
- **Hwting** - Docker配置优化
|
|
||||||
|
|
||||||
#### 特别感谢 / Special Thanks
|
|
||||||
感谢所有提交Issue、参与讨论、提供反馈的社区用户,你们的每一个建议都让SuperSonic变得更好!
|
|
||||||
|
|
||||||
#### 社区支持 / Community Support
|
|
||||||
SuperSonic是一个开源项目,我们欢迎更多开发者加入:
|
|
||||||
- 🔗 **GitHub**: https://github.com/tencentmusic/supersonic
|
|
||||||
- 📖 **文档**: 详见项目README和Wiki
|
|
||||||
- 🐛 **Issue报告**: 欢迎提交Bug和功能请求
|
|
||||||
- 🚀 **贡献代码**: 欢迎提交Pull Request
|
|
||||||
- 💬 **社区讨论**: 加入我们的技术交流群
|
|
||||||
|
|
||||||
#### 未来展望 / Future Vision
|
|
||||||
SuperSonic 1.0.0是一个重要的里程碑,但这只是开始。我们将继续:
|
|
||||||
- 🌟 **持续优化性能和稳定性**
|
|
||||||
- 🔧 **扩展更多数据库和AI模型支持**
|
|
||||||
- 🎨 **改善用户体验和界面设计**
|
|
||||||
- 📚 **完善文档和最佳实践**
|
|
||||||
- 🤝 **建设更活跃的开源社区**
|
|
||||||
|
|
||||||
**让我们一起把SuperSonic做得更好!** ✨
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*如果您在使用过程中遇到问题或有改进建议,欢迎随时与我们交流。每一份贡献都让SuperSonic更加强大!*
|
|
||||||
|
|
||||||
|
|
||||||
## 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.
|
||||||
|
|||||||
113
CLAUDE.md
113
CLAUDE.md
@@ -1,113 +0,0 @@
|
|||||||
# CLAUDE.md
|
|
||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
||||||
|
|
||||||
## Build Commands
|
|
||||||
|
|
||||||
### Backend (Java/Maven)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Clean build (skip tests)
|
|
||||||
mvn clean package -DskipTests -Dspotless.skip=true
|
|
||||||
|
|
||||||
# Run all tests
|
|
||||||
mvn test
|
|
||||||
|
|
||||||
# Run single test class
|
|
||||||
mvn test -Dtest=ClassName
|
|
||||||
|
|
||||||
# Full CI build
|
|
||||||
mvn -B package --file pom.xml
|
|
||||||
```
|
|
||||||
|
|
||||||
**Requirements:** Java 21, Maven
|
|
||||||
|
|
||||||
### Frontend (pnpm/React)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd webapp
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
pnpm install
|
|
||||||
|
|
||||||
# Start dev server (port 9000)
|
|
||||||
pnpm dev
|
|
||||||
|
|
||||||
# Production build
|
|
||||||
pnpm build
|
|
||||||
|
|
||||||
# Run tests
|
|
||||||
pnpm test
|
|
||||||
```
|
|
||||||
|
|
||||||
**Requirements:** Node.js >=16, pnpm 9.12.3+
|
|
||||||
|
|
||||||
### Quick Start
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build full release
|
|
||||||
./assembly/bin/supersonic-build.sh standalone
|
|
||||||
|
|
||||||
# Start service
|
|
||||||
./assembly/bin/supersonic-daemon.sh start
|
|
||||||
|
|
||||||
# Stop service
|
|
||||||
./assembly/bin/supersonic-daemon.sh stop
|
|
||||||
```
|
|
||||||
|
|
||||||
Visit http://localhost:9080 after startup.
|
|
||||||
|
|
||||||
## Architecture Overview
|
|
||||||
|
|
||||||
SuperSonic unifies **Chat BI** (LLM-powered) and **Headless BI** (semantic layer) paradigms.
|
|
||||||
|
|
||||||
### Core Modules
|
|
||||||
|
|
||||||
```
|
|
||||||
supersonic/
|
|
||||||
├── auth/ # Authentication & authorization (SPI-based)
|
|
||||||
├── chat/ # Chat BI module - LLM-powered Q&A interface
|
|
||||||
├── common/ # Shared utilities
|
|
||||||
├── headless/ # Headless BI - semantic layer with open API
|
|
||||||
├── launchers/ # Application entry points
|
|
||||||
│ ├── standalone/ # Combined Chat + Headless (default)
|
|
||||||
│ ├── chat/ # Chat-only service
|
|
||||||
│ └── headless/ # Headless-only service
|
|
||||||
└── webapp/ # Frontend React app (UmiJS 4 + Ant Design)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Data Flow
|
|
||||||
|
|
||||||
1. **Knowledge Base**: Extracts schema from semantic models, builds dictionary/index for schema mapping
|
|
||||||
2. **Schema Mapper**: Identifies metrics/dimensions/entities/values in user queries
|
|
||||||
3. **Semantic Parser**: Generates S2SQL (semantic SQL) using rule-based and LLM-based parsers
|
|
||||||
4. **Semantic Corrector**: Validates and corrects semantic queries
|
|
||||||
5. **Semantic Translator**: Converts S2SQL to executable SQL
|
|
||||||
|
|
||||||
### Key Entry Points
|
|
||||||
|
|
||||||
- `StandaloneLauncher.java` - Combined service with `scanBasePackages: ["com.tencent.supersonic", "dev.langchain4j"]`
|
|
||||||
- `ChatLauncher.java` - Chat BI only
|
|
||||||
- `HeadlessLauncher.java` - Headless BI only
|
|
||||||
|
|
||||||
## Key Technologies
|
|
||||||
|
|
||||||
**Backend:** Spring Boot 3.3.9, MyBatis-Plus 3.5.10.1, LangChain4j 0.36.2, JSqlParser 4.9, Calcite 1.38.0
|
|
||||||
|
|
||||||
**Frontend:** React 18, UmiJS 4, Ant Design 5.17.4, ECharts 5.0.2, AntV G6/X6
|
|
||||||
|
|
||||||
**Databases:** MySQL, PostgreSQL (with pgvector), H2, ClickHouse, StarRocks, Presto, Trino, DuckDB
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
**Java tests:** JUnit 5, Mockito. Located in `src/test/java/` of each module.
|
|
||||||
|
|
||||||
**Frontend tests:** Jest with Puppeteer environment in `webapp/packages/supersonic-fe/`
|
|
||||||
|
|
||||||
**Evaluation scripts:** Python scripts in `evaluation/` directory for Text2SQL accuracy testing.
|
|
||||||
|
|
||||||
## Related Documentation
|
|
||||||
|
|
||||||
- [README.md](README.md) - English documentation
|
|
||||||
- [README_CN.md](README_CN.md) - Chinese documentation
|
|
||||||
- [Evaluation Guide](evaluation/README.md) - Text2SQL evaluation process
|
|
||||||
490
LICENSE
490
LICENSE
@@ -1,41 +1,489 @@
|
|||||||
Apache License Version 2.0
|
SuperSonic is licensed under the MIT License, with the following additional conditions:
|
||||||
|
|
||||||
Copyright (2025) The SuperSonic Project Authors. All rights reserved.
|
1. You may provide SuperSonic to third parties as a commercial software or service. However,
|
||||||
|
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.
|
||||||
SuperSonic is licensed under the Apache License 2.0, with the following additional conditions:
|
b. LOGO and copyright information: In the process of using SuperSonic, you may not remove or modify
|
||||||
|
the LOGO or copyright information on the SuperSonic UI. This restriction is inapplicable to uses of
|
||||||
1. The commercial usage of SuperSonic:
|
SuperSonic that do not involve its frontend components.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
b. Your contributed code may be used for commercial purposes, including but not limited to its cloud edition.
|
Terms of the MIT License:
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
MIT License
|
||||||
|
|
||||||
Apart from the specific conditions mentioned above, all other rights and restrictions follow the Apache License 2.0.
|
Copyright (c) 2023 Tencent Music Entertainment
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E9%83%A8%E7%BD%B2/).
|
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/).
|
||||||
|
|
||||||
## 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/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E9%83%A8%E7%BD%B2/)。
|
请参考项目[文档](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/)。
|
||||||
|
|
||||||
## 微信联系方式
|
## 微信联系方式
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ SuperSonicには、サンプルのセマンティックモデルとチャット
|
|||||||
|
|
||||||
## ビルドと開発
|
## ビルドと開発
|
||||||
|
|
||||||
プロジェクト[ドキュメント](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/)を参照してください。
|
プロジェクト[ドキュメント](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/)を参照してください。
|
||||||
|
|
||||||
## WeChat連絡先
|
## WeChat連絡先
|
||||||
|
|
||||||
|
|||||||
@@ -43,26 +43,10 @@ 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
|
||||||
|
|
||||||
|
|
||||||
@@ -88,55 +72,22 @@ 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 check if release directory already exists from buildJavaService
|
|
||||||
if exist %release_dir% (
|
|
||||||
echo "Release directory already prepared by buildJavaService"
|
|
||||||
) else (
|
|
||||||
mkdir %release_dir%
|
|
||||||
|
|
||||||
rem package java service
|
|
||||||
tar xvf %service_name%-bin.tar.gz 2>nul
|
|
||||||
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
|
rem package webapp
|
||||||
if exist supersonic-webapp.tar.gz (
|
tar xvf supersonic-webapp.tar.gz
|
||||||
tar xvf supersonic-webapp.tar.gz 2>nul
|
move /y supersonic-webapp webapp
|
||||||
if errorlevel 1 (
|
echo {"env": ""} > webapp\supersonic.config.json
|
||||||
echo "Warning: tar command failed, trying PowerShell extraction..."
|
move /y webapp %release_dir%
|
||||||
powershell -Command "Expand-Archive -Path 'supersonic-webapp.tar.gz' -DestinationPath '.' -Force"
|
rem package java service
|
||||||
)
|
tar xvf %service_name%-bin.tar.gz
|
||||||
move /y supersonic-webapp webapp
|
for /d %%D in ("%service_name%\*") do (
|
||||||
echo {"env": ""} > webapp\supersonic.config.json
|
move "%%D" "%release_dir%"
|
||||||
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 -Command "Compress-Archive -Path '%release_dir%' -DestinationPath '%release_dir%.zip' -Force"
|
powershell Compress-Archive -Path %release_dir% -DestinationPath %release_dir%.zip
|
||||||
if errorlevel 1 (
|
del %service_name%-bin.tar.gz
|
||||||
echo "Warning: PowerShell compression failed, release directory still available: %release_dir%"
|
del supersonic-webapp.tar.gz
|
||||||
) else (
|
rmdir /s /q %service_name%
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
@@ -35,15 +35,10 @@ 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
|
||||||
# check build result
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "Failed to build frontend webapp."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
cp -fr ./supersonic-webapp.tar.gz ${buildDir}/
|
cp -fr ./supersonic-webapp.tar.gz ${buildDir}/
|
||||||
# check build result
|
# check build result
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Failed to get supersonic webapp package."
|
echo "Failed to build frontend webapp."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "finished building supersonic webapp"
|
echo "finished building supersonic webapp"
|
||||||
@@ -61,11 +56,6 @@ 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,7 +4,6 @@ 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"
|
||||||
@@ -15,14 +14,12 @@ if "%service%"=="" (
|
|||||||
)
|
)
|
||||||
|
|
||||||
if "%profile%"=="" (
|
if "%profile%"=="" (
|
||||||
set "profile=%S2_DB_TYPE%"
|
set "profile=local"
|
||||||
)
|
)
|
||||||
|
|
||||||
set "model_name=%service%"
|
set "model_name=%service%"
|
||||||
|
|
||||||
REM fix path configuration - point to the correct release package directory
|
cd %baseDir%
|
||||||
set "releaseDir=%buildDir%\supersonic-%service%-1.0.0-SNAPSHOT"
|
|
||||||
cd %releaseDir%
|
|
||||||
|
|
||||||
if "%command%"=="restart" (
|
if "%command%"=="restart" (
|
||||||
call :stop
|
call :stop
|
||||||
@@ -52,58 +49,19 @@ if "%command%"=="restart" (
|
|||||||
|
|
||||||
:runJavaService
|
:runJavaService
|
||||||
echo 'java service starting, see logs in logs/'
|
echo 'java service starting, see logs in logs/'
|
||||||
echo 'Using release directory: %releaseDir%'
|
set "libDir=%baseDir%\lib"
|
||||||
|
set "confDir=%baseDir%\conf"
|
||||||
REM use release package directory as base path
|
set "webDir=%baseDir%\webapp"
|
||||||
set "libDir=%releaseDir%\lib"
|
set "logDir=%baseDir%\logs"
|
||||||
set "confDir=%releaseDir%\conf"
|
set "classpath=%baseDir%;%webDir%;%libDir%\*;%confDir%"
|
||||||
set "webDir=%releaseDir%\webapp"
|
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 "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
|
||||||
REM check if the main jar file exists
|
timeout /t 10 >nul
|
||||||
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,7 +2,6 @@
|
|||||||
|
|
||||||
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
|
||||||
@@ -13,7 +12,7 @@ if [ -z "$service" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$profile" ]; then
|
if [ -z "$profile" ]; then
|
||||||
profile=${S2_DB_TYPE}
|
profile="local"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
model_name=$service
|
model_name=$service
|
||||||
@@ -60,8 +59,7 @@ 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
|
command="-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dapp_name=${local_app_name} -Xms1024m -Xmx1024m $main_class"
|
||||||
-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 &
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
export SUPERSONIC_VERSION=latest
|
|
||||||
|
|
||||||
docker-compose -f docker-compose.yml -p supersonic up
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#!/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}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
:: 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="
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#!/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>21</maven.compiler.source>
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -21,8 +21,6 @@ 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);
|
||||||
|
|||||||
@@ -24,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, null);
|
super(id, name, displayName, email, isAdmin);
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,4 @@ 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;
|
|
||||||
|
|
||||||
private String role;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ 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);
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ 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;
|
||||||
@@ -92,12 +90,6 @@ 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);
|
||||||
@@ -110,9 +102,7 @@ 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);
|
||||||
String token = tokenService.generateToken(UserWithPassword.convert(user), appKey);
|
return 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");
|
||||||
@@ -223,9 +213,8 @@ 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());
|
||||||
|
|
||||||
// 使用令牌名称作为生成key ,这样可以区分正常请求和api 请求,api 的令牌失效时间很长,需考虑令牌泄露的情况
|
String token =
|
||||||
String token = tokenService.generateToken(UserWithPassword.convert(userWithPassword),
|
tokenService.generateToken(UserWithPassword.convert(userWithPassword), expireTime);
|
||||||
"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);
|
||||||
}
|
}
|
||||||
@@ -278,11 +267,4 @@ 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,13 +1,20 @@
|
|||||||
package com.tencent.supersonic.auth.authentication.interceptor;
|
package com.tencent.supersonic.auth.authentication.interceptor;
|
||||||
|
|
||||||
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.UserService;
|
import com.tencent.supersonic.auth.api.authentication.constant.UserConstants;
|
||||||
|
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 jakarta.servlet.http.HttpServletRequest;
|
||||||
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;
|
||||||
|
|
||||||
@@ -16,10 +23,12 @@ public abstract class AuthenticationInterceptor implements HandlerInterceptor {
|
|||||||
|
|
||||||
protected AuthenticationConfig authenticationConfig;
|
protected AuthenticationConfig authenticationConfig;
|
||||||
|
|
||||||
protected UserService userService;
|
protected UserServiceImpl userServiceImpl;
|
||||||
|
|
||||||
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)) {
|
||||||
@@ -44,4 +53,52 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,13 @@ package com.tencent.supersonic.auth.authentication.interceptor;
|
|||||||
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.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.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.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@@ -16,7 +19,12 @@ 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.*;
|
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_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 {
|
||||||
@@ -25,12 +33,21 @@ 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);
|
||||||
userService = ContextUtils.getBean(UserService.class);
|
userServiceImpl = ContextUtils.getBean(UserServiceImpl.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();
|
||||||
@@ -51,11 +68,35 @@ 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,17 +1,7 @@
|
|||||||
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;
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@@ -31,25 +21,71 @@ public class UserDO {
|
|||||||
/** */
|
/** */
|
||||||
private Integer isAdmin;
|
private Integer isAdmin;
|
||||||
|
|
||||||
private Timestamp lastLogin;
|
/** @return id */
|
||||||
|
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,7 +1,5 @@
|
|||||||
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;
|
||||||
@@ -9,8 +7,12 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface UserDOMapper extends BaseMapper<UserDO> {
|
public interface UserDOMapper {
|
||||||
|
|
||||||
|
/** @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,11 +21,7 @@ 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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,13 +65,6 @@ 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<>();
|
||||||
@@ -83,9 +76,4 @@ 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,13 @@ import com.tencent.supersonic.common.pojo.User;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
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;
|
||||||
@@ -61,28 +67,11 @@ 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) {
|
||||||
|
|||||||
@@ -70,11 +70,6 @@ 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);
|
||||||
|
|||||||
@@ -6,10 +6,7 @@ import javax.crypto.spec.SecretKeySpec;
|
|||||||
|
|
||||||
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;
|
||||||
@@ -74,7 +71,6 @@ 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);
|
||||||
@@ -94,14 +90,6 @@ 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))
|
||||||
@@ -134,16 +122,6 @@ 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,7 +9,6 @@
|
|||||||
<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>
|
||||||
@@ -41,7 +40,7 @@
|
|||||||
</where>
|
</where>
|
||||||
</sql>
|
</sql>
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, name, password, salt, display_name, email, is_admin, last_login
|
id, name, password, salt, display_name, email, is_admin
|
||||||
</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
|
||||||
@@ -60,6 +59,14 @@
|
|||||||
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=",">
|
||||||
@@ -137,9 +144,6 @@
|
|||||||
<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>
|
||||||
|
|||||||
@@ -15,68 +15,6 @@ 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):
|
||||||
@@ -132,35 +70,18 @@ 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)
|
||||||
parse_status = '解析失败'
|
batch_test.execute(agentId, question, parse_resp['data']['queryId'])
|
||||||
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__':
|
||||||
|
|
||||||
|
|||||||
@@ -18,5 +18,4 @@ public class ChatExecuteReq {
|
|||||||
private int parseId;
|
private int parseId;
|
||||||
private String queryText;
|
private String queryText;
|
||||||
private boolean saveAnswer;
|
private boolean saveAnswer;
|
||||||
private boolean streamingResult;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.api.pojo.request;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class ChatMemoryDeleteReq {
|
|
||||||
|
|
||||||
private List<Long> ids;
|
|
||||||
|
|
||||||
private Integer agentId;
|
|
||||||
}
|
|
||||||
@@ -17,8 +17,6 @@ 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;
|
||||||
|
|||||||
@@ -26,8 +26,4 @@ public class ChatMemoryUpdateReq {
|
|||||||
private MemoryReviewResult humanReviewRet;
|
private MemoryReviewResult humanReviewRet;
|
||||||
|
|
||||||
private String humanReviewCmt;
|
private String humanReviewCmt;
|
||||||
|
|
||||||
private MemoryReviewResult llmReviewRet;
|
|
||||||
|
|
||||||
private String llmReviewCmt;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ public class QueryResp {
|
|||||||
private Long questionId;
|
private Long questionId;
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
private Long chatId;
|
private Long chatId;
|
||||||
private Integer agentId;
|
|
||||||
private Integer score;
|
private Integer score;
|
||||||
private String feedback;
|
private String feedback;
|
||||||
private String queryText;
|
private String queryText;
|
||||||
|
|||||||
@@ -38,9 +38,6 @@ public class Agent extends RecordInfo {
|
|||||||
private VisualConfig visualConfig;
|
private VisualConfig visualConfig;
|
||||||
private List<String> admins = Lists.newArrayList();
|
private List<String> admins = Lists.newArrayList();
|
||||||
private List<String> viewers = 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);
|
||||||
@@ -118,8 +115,4 @@ public class Agent extends RecordInfo {
|
|||||||
return list.apply(this).contains(user.getName());
|
return list.apply(this).contains(user.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean openToAll() {
|
|
||||||
return isOpen != null && isOpen == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,5 @@ 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,13 +36,12 @@ public class PlainTextExecutor implements ChatQueryExecutor {
|
|||||||
.appModule(AppModule.CHAT).description("直接将原始输入透传大模型").enable(false).build());
|
.appModule(AppModule.CHAT).description("直接将原始输入透传大模型").enable(false).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean accept(ExecuteContext executeContext) {
|
|
||||||
return "PLAIN_TEXT".equals(executeContext.getParseInfo().getQueryMode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryResult execute(ExecuteContext executeContext) {
|
public QueryResult execute(ExecuteContext executeContext) {
|
||||||
|
if (!"PLAIN_TEXT".equals(executeContext.getParseInfo().getQueryMode())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
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,11 +8,6 @@ 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();
|
||||||
|
|||||||
@@ -25,11 +25,6 @@ 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) {
|
||||||
@@ -49,7 +44,7 @@ public class SqlExecutor implements ChatQueryExecutor {
|
|||||||
Text2SQLExemplar.class);
|
Text2SQLExemplar.class);
|
||||||
|
|
||||||
MemoryService memoryService = ContextUtils.getBean(MemoryService.class);
|
MemoryService memoryService = ContextUtils.getBean(MemoryService.class);
|
||||||
memoryService.createMemory(ChatMemory.builder().queryId(queryResult.getQueryId())
|
memoryService.createMemory(ChatMemory.builder()
|
||||||
.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())
|
||||||
@@ -75,26 +70,21 @@ public class SqlExecutor implements ChatQueryExecutor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用querySQL,它已经包含了所有修正(包括物理SQL修正)
|
QuerySqlReq sqlReq =
|
||||||
String finalSql = StringUtils.isNotBlank(parseInfo.getSqlInfo().getQuerySQL())
|
QuerySqlReq.builder().sql(parseInfo.getSqlInfo().getCorrectedS2SQL()).build();
|
||||||
? 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(finalSql);
|
queryResult.setQuerySql(queryResp.getSql());
|
||||||
queryResult.setQueryResults(queryResp.getResultList());
|
queryResult.setQueryResults(queryResp.getResultList());
|
||||||
queryResult.setQueryColumns(queryResp.getColumns());
|
queryResult.setQueryColumns(queryResp.getColumns());
|
||||||
queryResult.setQueryState(QueryState.SUCCESS);
|
queryResult.setQueryState(QueryState.SUCCESS);
|
||||||
|
|||||||
@@ -3,13 +3,11 @@ 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.enums.MemoryStatus;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryFilter;
|
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.pojo.ChatMemory;
|
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;
|
||||||
@@ -125,10 +123,7 @@ public class MemoryReviewTask {
|
|||||||
if (MemoryReviewResult.POSITIVE.equals(m.getLlmReviewRet())) {
|
if (MemoryReviewResult.POSITIVE.equals(m.getLlmReviewRet())) {
|
||||||
m.setStatus(MemoryStatus.ENABLED);
|
m.setStatus(MemoryStatus.ENABLED);
|
||||||
}
|
}
|
||||||
ChatMemoryUpdateReq memoryUpdateReq = ChatMemoryUpdateReq.builder().id(m.getId())
|
memoryService.updateMemory(m);
|
||||||
.status(m.getStatus()).llmReviewRet(m.getLlmReviewRet())
|
|
||||||
.llmReviewCmt(m.getLlmReviewCmt()).build();
|
|
||||||
memoryService.updateMemory(memoryUpdateReq, User.getDefaultUser());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,5 @@ 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(),
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import dev.langchain4j.model.input.PromptTemplate;
|
|||||||
import dev.langchain4j.model.output.Response;
|
import dev.langchain4j.model.output.Response;
|
||||||
import dev.langchain4j.provider.ModelProvider;
|
import dev.langchain4j.provider.ModelProvider;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -74,12 +73,12 @@ 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);
|
||||||
@@ -101,12 +100,10 @@ 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()) {
|
if (parseResp.getSelectedParses().isEmpty()) {
|
||||||
errMsg.append(parseResp.getErrorMsg());
|
errMsg.append(parseResp.getErrorMsg());
|
||||||
continue;
|
continue;
|
||||||
@@ -140,18 +137,11 @@ 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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,6 +162,10 @@ public class NL2SQLParser implements ChatQueryParser {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// derive mapping result of current question and parsing result of last question.
|
||||||
|
ChatLayerService chatLayerService = ContextUtils.getBean(ChatLayerService.class);
|
||||||
|
MapResp currentMapResult = chatLayerService.map(queryNLReq);
|
||||||
|
|
||||||
List<QueryResp> historyQueries =
|
List<QueryResp> historyQueries =
|
||||||
getHistoryQueries(parseContext.getRequest().getChatId(), 1);
|
getHistoryQueries(parseContext.getRequest().getChatId(), 1);
|
||||||
if (historyQueries.isEmpty()) {
|
if (historyQueries.isEmpty()) {
|
||||||
@@ -179,18 +173,12 @@ public class NL2SQLParser implements ChatQueryParser {
|
|||||||
}
|
}
|
||||||
QueryResp lastQuery = historyQueries.get(0);
|
QueryResp lastQuery = historyQueries.get(0);
|
||||||
SemanticParseInfo lastParseInfo = lastQuery.getParseInfos().get(0);
|
SemanticParseInfo lastParseInfo = lastQuery.getParseInfos().get(0);
|
||||||
String histSQL = lastParseInfo.getSqlInfo().getCorrectedS2SQL();
|
|
||||||
if (StringUtils.isBlank(histSQL)) // 优化性能,如果问答不是chat bi 则无需重写,因为数据都不全
|
|
||||||
return;
|
|
||||||
|
|
||||||
// derive mapping result of current question and parsing result of last question.
|
|
||||||
ChatLayerService chatLayerService = ContextUtils.getBean(ChatLayerService.class);
|
|
||||||
MapResp currentMapResult = chatLayerService.map(queryNLReq); // 优化性能 ,只有满足条件才mapping
|
|
||||||
|
|
||||||
Long dataId = lastParseInfo.getDataSetId();
|
Long dataId = lastParseInfo.getDataSetId();
|
||||||
|
|
||||||
String curtMapStr =
|
String curtMapStr =
|
||||||
generateSchemaPrompt(currentMapResult.getMapInfo().getMatchedElements(dataId));
|
generateSchemaPrompt(currentMapResult.getMapInfo().getMatchedElements(dataId));
|
||||||
String histMapStr = generateSchemaPrompt(lastParseInfo.getElementMatches());
|
String histMapStr = generateSchemaPrompt(lastParseInfo.getElementMatches());
|
||||||
|
String histSQL = lastParseInfo.getSqlInfo().getCorrectedS2SQL();
|
||||||
|
|
||||||
Map<String, Object> variables = new HashMap<>();
|
Map<String, Object> variables = new HashMap<>();
|
||||||
variables.put("current_question", currentMapResult.getQueryText());
|
variables.put("current_question", currentMapResult.getQueryText());
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -44,10 +44,4 @@ public class AgentDO {
|
|||||||
private String admin;
|
private String admin;
|
||||||
|
|
||||||
private String viewer;
|
private String viewer;
|
||||||
|
|
||||||
private String adminOrg;
|
|
||||||
|
|
||||||
private String viewOrg;
|
|
||||||
|
|
||||||
private Integer isOpen;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
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 {
|
||||||
|
|
||||||
@TableId(type = IdType.AUTO)
|
private long chatId;
|
||||||
private Long chatId;
|
|
||||||
private Integer agentId;
|
private Integer agentId;
|
||||||
private String chatName;
|
private String chatName;
|
||||||
private String createTime;
|
private String createTime;
|
||||||
|
|||||||
@@ -23,9 +23,6 @@ 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;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,9 @@ public class ChatMemoryRepositoryImpl implements ChatMemoryRepository {
|
|||||||
if (CollectionUtils.isEmpty(ids)) {
|
if (CollectionUtils.isEmpty(ids)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
chatMemoryMapper.deleteByIds(ids);
|
for (Long id : ids) {
|
||||||
|
chatMemoryMapper.deleteById(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ 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;
|
||||||
@@ -117,20 +116,6 @@ 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(),
|
||||||
@@ -148,7 +133,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);
|
||||||
|
|||||||
@@ -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, String.class);
|
restTemplate.exchange(requestUrl, HttpMethod.POST, entity, Object.class);
|
||||||
objectResponse = responseEntity.getBody();
|
objectResponse = responseEntity.getBody();
|
||||||
log.info("objectResponse:{}", objectResponse);
|
log.info("objectResponse:{}", objectResponse);
|
||||||
Map<String, Object> response = JSON.parseObject(objectResponse.toString());
|
Map<String, Object> response = JsonUtil.objectToMap(objectResponse);
|
||||||
webServiceResponse.setResult(response);
|
webServiceResponse.setResult(response);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.info("Exception:{}", e.getMessage());
|
log.info("Exception:{}", e.getMessage());
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ package com.tencent.supersonic.chat.server.pojo;
|
|||||||
|
|
||||||
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 lombok.*;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@@ -16,8 +20,6 @@ public class ChatMemory {
|
|||||||
|
|
||||||
private Integer agentId;
|
private Integer agentId;
|
||||||
|
|
||||||
private Long queryId;
|
|
||||||
|
|
||||||
private String question;
|
private String question;
|
||||||
|
|
||||||
private String sideInfo;
|
private String sideInfo;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
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;
|
||||||
@@ -9,7 +8,6 @@ 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,8 +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() {
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
package com.tencent.supersonic.chat.server.processor.execute;
|
package com.tencent.supersonic.chat.server.processor.execute;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
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.chat.server.persistence.dataobject.ChatQueryDO;
|
|
||||||
import com.tencent.supersonic.chat.server.persistence.repository.ChatQueryRepository;
|
|
||||||
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
||||||
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.common.util.ContextUtils;
|
|
||||||
import dev.langchain4j.data.message.AiMessage;
|
import dev.langchain4j.data.message.AiMessage;
|
||||||
import dev.langchain4j.model.StreamingResponseHandler;
|
|
||||||
import dev.langchain4j.model.chat.ChatLanguageModel;
|
import dev.langchain4j.model.chat.ChatLanguageModel;
|
||||||
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
|
|
||||||
import dev.langchain4j.model.input.Prompt;
|
import dev.langchain4j.model.input.Prompt;
|
||||||
import dev.langchain4j.model.input.PromptTemplate;
|
import dev.langchain4j.model.input.PromptTemplate;
|
||||||
import dev.langchain4j.model.output.Response;
|
import dev.langchain4j.model.output.Response;
|
||||||
@@ -31,10 +24,8 @@ import java.util.Objects;
|
|||||||
* DataInterpretProcessor interprets query result to make it more readable to the users.
|
* DataInterpretProcessor interprets query result to make it more readable to the users.
|
||||||
*/
|
*/
|
||||||
public class DataInterpretProcessor implements ExecuteResultProcessor {
|
public class DataInterpretProcessor implements ExecuteResultProcessor {
|
||||||
public static String tip = "AI 回答中...\r\n";
|
|
||||||
private static final Logger keyPipelineLog = LoggerFactory.getLogger("keyPipeline");
|
|
||||||
|
|
||||||
private static Map<Long, StringBuffer> resultCache = new HashMap<>();
|
private static final Logger keyPipelineLog = LoggerFactory.getLogger("keyPipeline");
|
||||||
|
|
||||||
public static final String APP_KEY = "DATA_INTERPRETER";
|
public static final String APP_KEY = "DATA_INTERPRETER";
|
||||||
private static final String INSTRUCTION = ""
|
private static final String INSTRUCTION = ""
|
||||||
@@ -50,89 +41,28 @@ public class DataInterpretProcessor implements ExecuteResultProcessor {
|
|||||||
.appModule(AppModule.CHAT).description("通过大模型对结果数据做提炼总结").enable(false).build());
|
.appModule(AppModule.CHAT).description("通过大模型对结果数据做提炼总结").enable(false).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getTextSummary(Long queryId) {
|
|
||||||
if (resultCache.get(queryId) != null) {
|
@Override
|
||||||
return resultCache.get(queryId).toString();
|
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
||||||
|
Agent agent = executeContext.getAgent();
|
||||||
|
ChatApp chatApp = agent.getChatAppConfig().get(APP_KEY);
|
||||||
|
if (Objects.isNull(chatApp) || !chatApp.isEnable()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<Long, StringBuffer> getResultCache() {
|
|
||||||
return resultCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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();
|
|
||||||
ChatApp chatApp = agent.getChatAppConfig().get(APP_KEY);
|
|
||||||
|
|
||||||
Map<String, Object> variable = new HashMap<>();
|
Map<String, Object> variable = new HashMap<>();
|
||||||
String question = executeContext.getResponse().getTextResult();// 结果解析应该用改写的问题,因为改写的内容信息量更大
|
variable.put("question", executeContext.getRequest().getQueryText());
|
||||||
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);
|
||||||
if (executeContext.getRequest().isStreamingResult()) {
|
ChatLanguageModel chatLanguageModel =
|
||||||
StreamingChatLanguageModel chatLanguageModel =
|
ModelProvider.getChatModel(chatApp.getChatModelConfig());
|
||||||
ModelProvider.getChatStreamingModel(chatApp.getChatModelConfig());
|
Response<AiMessage> response = chatLanguageModel.generate(prompt.toUserMessage());
|
||||||
final Long queryId = executeContext.getRequest().getQueryId();
|
String anwser = response.content().text();
|
||||||
resultCache.put(queryId, new StringBuffer(tip));
|
keyPipelineLog.info("DataInterpretProcessor modelReq:\n{} \nmodelResp:\n{}", prompt.text(),
|
||||||
chatLanguageModel.generate(prompt.toUserMessage(),
|
anwser);
|
||||||
new StreamingResponseHandler<AiMessage>() {
|
if (StringUtils.isNotBlank(anwser)) {
|
||||||
@Override
|
queryResult.setTextSummary(anwser);
|
||||||
public void onNext(String token) {
|
|
||||||
resultCache.get(queryId).append(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onComplete(Response<AiMessage> response) {
|
|
||||||
ChatQueryRepository chatQueryRepository =
|
|
||||||
ContextUtils.getBean(ChatQueryRepository.class);
|
|
||||||
ChatQueryDO chatQueryDO = chatQueryRepository.getChatQueryDO(queryId);
|
|
||||||
JSONObject queryResult = JSON.parseObject(chatQueryDO.getQueryResult());
|
|
||||||
queryResult.put("textSummary",
|
|
||||||
resultCache.get(queryId).toString().substring(tip.length()));
|
|
||||||
chatQueryDO.setQueryResult(queryResult.toJSONString());
|
|
||||||
chatQueryRepository.updateChatQuery(chatQueryDO);
|
|
||||||
resultCache.remove(queryId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable error) {
|
|
||||||
error.printStackTrace();
|
|
||||||
resultCache.remove(queryId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
ChatLanguageModel chatLanguageModel =
|
|
||||||
ModelProvider.getChatModel(chatApp.getChatModelConfig());
|
|
||||||
Response<AiMessage> response = chatLanguageModel.generate(prompt.toUserMessage());
|
|
||||||
String anwser = response.content().text();
|
|
||||||
keyPipelineLog.info("DataInterpretProcessor modelReq:\n{} \nmodelResp:\n{}",
|
|
||||||
prompt.text(), anwser);
|
|
||||||
if (StringUtils.isNotBlank(anwser)) {
|
|
||||||
queryResult.setTextSummary(anwser);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,18 +27,17 @@ public class DimensionRecommendProcessor implements ExecuteResultProcessor {
|
|||||||
private static final int recommend_dimension_size = 5;
|
private static final int recommend_dimension_size = 5;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(ExecuteContext executeContext) {
|
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
||||||
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,12 +1,11 @@
|
|||||||
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 {
|
||||||
|
|
||||||
boolean accept(ExecuteContext executeContext);
|
void process(ExecuteContext executeContext, QueryResult queryResult);
|
||||||
|
|
||||||
void process(ExecuteContext executeContext);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,18 +59,14 @@ import static com.tencent.supersonic.common.pojo.Constants.TIME_FORMAT;
|
|||||||
public class MetricRatioCalcProcessor implements ExecuteResultProcessor {
|
public class MetricRatioCalcProcessor implements ExecuteResultProcessor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(ExecuteContext executeContext) {
|
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
||||||
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
||||||
AggregatorConfig aggregatorConfig = ContextUtils.getBean(AggregatorConfig.class);
|
AggregatorConfig aggregatorConfig = ContextUtils.getBean(AggregatorConfig.class);
|
||||||
return !CollectionUtils.isEmpty(semanticParseInfo.getMetrics())
|
if (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);
|
||||||
@@ -142,7 +138,7 @@ public class MetricRatioCalcProcessor implements ExecuteResultProcessor {
|
|||||||
return new HashSet<>();
|
return new HashSet<>();
|
||||||
}
|
}
|
||||||
return queryResult.getQueryColumns().stream()
|
return queryResult.getQueryColumns().stream()
|
||||||
.flatMap(c -> SqlSelectHelper.getFieldsFromExpr(c.getBizName()).stream())
|
.flatMap(c -> SqlSelectHelper.getColumnFromExpr(c.getNameEn()).stream())
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,16 +163,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.getBizName().equals(metric.getBizName())).findFirst();
|
.filter(c -> c.getNameEn().equals(metric.getBizName())).findFirst();
|
||||||
|
|
||||||
if (!valueColumn.isPresent()) {
|
if (!valueColumn.isPresent()) {
|
||||||
return metricInfo;
|
return metricInfo;
|
||||||
}
|
}
|
||||||
String valueField = String.format("%s_%s", valueColumn.get().getBizName(),
|
String valueField = String.format("%s_%s", valueColumn.get().getNameEn(),
|
||||||
aggOperatorEnum.getOperator());
|
aggOperatorEnum.getOperator());
|
||||||
if (result.containsKey(valueColumn.get().getBizName())) {
|
if (result.containsKey(valueColumn.get().getNameEn())) {
|
||||||
DecimalFormat df = new DecimalFormat("#.####");
|
DecimalFormat df = new DecimalFormat("#.####");
|
||||||
metricInfo.setValue(df.format(result.get(valueColumn.get().getBizName())));
|
metricInfo.setValue(df.format(result.get(valueColumn.get().getNameEn())));
|
||||||
}
|
}
|
||||||
String ratio = "";
|
String ratio = "";
|
||||||
if (Objects.nonNull(result.get(valueField))) {
|
if (Objects.nonNull(result.get(valueField))) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
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;
|
||||||
@@ -15,7 +16,14 @@ 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.*;
|
import java.util.Collections;
|
||||||
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,20 +34,17 @@ public class MetricRecommendProcessor implements ExecuteResultProcessor {
|
|||||||
private static final int METRIC_RECOMMEND_SIZE = 5;
|
private static final int METRIC_RECOMMEND_SIZE = 5;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(ExecuteContext executeContext) {
|
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
||||||
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 (Objects.isNull(parseInfo.getQueryType())
|
||||||
|
|| !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,7 +4,6 @@ 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;
|
||||||
@@ -27,7 +26,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 = "REWRITE_ERROR_MESSAGE";
|
public static final String APP_KEY_ERROR_MESSAGE = "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, "
|
||||||
@@ -38,36 +37,29 @@ public class ErrorMsgRewriteProcessor implements ParseResultProcessor {
|
|||||||
+ "#Examples: {{examples}}\n" + "#Response: ";
|
+ "#Examples: {{examples}}\n" + "#Response: ";
|
||||||
|
|
||||||
public ErrorMsgRewriteProcessor() {
|
public ErrorMsgRewriteProcessor() {
|
||||||
ChatAppManager.register(APP_KEY,
|
ChatAppManager.register(APP_KEY_ERROR_MESSAGE,
|
||||||
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(true).build());
|
.enable(false).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);
|
ChatApp chatApp = parseContext.getAgent().getChatAppConfig().get(APP_KEY_ERROR_MESSAGE);
|
||||||
|
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();
|
||||||
if (parseContext.getResponse().getUsedExemplars() != null) {
|
parseContext.getResponse().getUsedExemplars().forEach(e -> exampleStr.append(
|
||||||
parseContext.getResponse().getUsedExemplars().forEach(e -> exampleStr.append(String
|
String.format("<Question:{%s},Schema:{%s}> ", e.getQuestion(), e.getDbSchema())));
|
||||||
.format("<Question:{%s},Schema:{%s}> ", e.getQuestion(), e.getDbSchema())));
|
parseContext.getAgent().getExamples()
|
||||||
}
|
.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);
|
||||||
@@ -76,7 +68,6 @@ 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.tencent.supersonic.common.jsqlparser.SqlSelectHelper;
|
|||||||
import com.tencent.supersonic.common.pojo.DateConf;
|
import com.tencent.supersonic.common.pojo.DateConf;
|
||||||
import com.tencent.supersonic.common.pojo.enums.FilterOperatorEnum;
|
import com.tencent.supersonic.common.pojo.enums.FilterOperatorEnum;
|
||||||
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
||||||
|
import com.tencent.supersonic.common.pojo.enums.TimeDimensionEnum;
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
import com.tencent.supersonic.headless.api.pojo.DataSetSchema;
|
import com.tencent.supersonic.headless.api.pojo.DataSetSchema;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
||||||
@@ -20,7 +21,12 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,12 +34,6 @@ import java.util.stream.Collectors;
|
|||||||
**/
|
**/
|
||||||
@Slf4j
|
@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 -> {
|
||||||
@@ -96,7 +96,7 @@ public class ParseInfoFormatProcessor implements ParseResultProcessor {
|
|||||||
|
|
||||||
// extract date filter from S2SQL
|
// extract date filter from S2SQL
|
||||||
try {
|
try {
|
||||||
if (!CollectionUtils.isEmpty(expressions)) {
|
if (parseInfo.getDateInfo() == null && !CollectionUtils.isEmpty(expressions)) {
|
||||||
parseInfo.setDateInfo(extractDateFilter(expressions, dsSchema));
|
parseInfo.setDateInfo(extractDateFilter(expressions, dsSchema));
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -216,6 +216,9 @@ public class ParseInfoFormatProcessor implements ParseResultProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isPartitionDimension(DataSetSchema dataSetSchema, String sqlFieldName) {
|
private static boolean isPartitionDimension(DataSetSchema dataSetSchema, String sqlFieldName) {
|
||||||
|
if (TimeDimensionEnum.containsTimeDimension(sqlFieldName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (Objects.isNull(dataSetSchema) || Objects.isNull(dataSetSchema.getPartitionDimension())
|
if (Objects.isNull(dataSetSchema) || Objects.isNull(dataSetSchema.getPartitionDimension())
|
||||||
|| Objects.isNull(dataSetSchema.getPartitionDimension().getName())) {
|
|| Objects.isNull(dataSetSchema.getPartitionDimension().getName())) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -6,7 +6,5 @@ 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,11 +23,6 @@ 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));
|
||||||
|
|||||||
@@ -10,11 +10,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class TimeCostCalcProcessor implements ParseResultProcessor {
|
public class TimeCostCalcProcessor implements ParseResultProcessor {
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean accept(ParseContext parseContext) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(ParseContext parseContext) {
|
public void process(ParseContext parseContext) {
|
||||||
ChatParseResp parseResp = parseContext.getResponse();
|
ChatParseResp parseResp = parseContext.getResponse();
|
||||||
|
|||||||
@@ -66,10 +66,8 @@ public class ChatConfigController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/getDomainDataSetTree")
|
@GetMapping("/getDomainDataSetTree")
|
||||||
public List<ItemResp> getDomainDataSetTree(HttpServletRequest request,
|
public List<ItemResp> getDomainDataSetTree() {
|
||||||
HttpServletResponse response) {
|
return semanticLayerService.getDomainDataSetTree();
|
||||||
User user = UserHolder.findUser(request, response);
|
|
||||||
return semanticLayerService.getDomainDataSetTree(user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/getDataSetSchema/{id}")
|
@GetMapping("/getDataSetSchema/{id}")
|
||||||
|
|||||||
@@ -22,10 +22,11 @@ public class ChatController {
|
|||||||
private ChatManageService chatService;
|
private ChatManageService chatService;
|
||||||
|
|
||||||
@PostMapping("/save")
|
@PostMapping("/save")
|
||||||
public Long save(@RequestParam(value = "chatName") String chatName,
|
public Boolean save(@RequestParam(value = "chatName") String chatName,
|
||||||
@RequestParam(value = "agentId", required = false) Integer agentId,
|
@RequestParam(value = "agentId", required = false) Integer agentId,
|
||||||
HttpServletRequest request, HttpServletResponse response) {
|
HttpServletRequest request, HttpServletResponse response) {
|
||||||
return chatService.addChat(UserHolder.findUser(request, response), chatName, agentId);
|
chatService.addChat(UserHolder.findUser(request, response), chatName, agentId);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/getAll")
|
@GetMapping("/getAll")
|
||||||
@@ -52,7 +53,7 @@ public class ChatController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/updateQAFeedback")
|
@PostMapping("/updateQAFeedback")
|
||||||
public Boolean updateQAFeedback(@RequestParam(value = "id") Long id,
|
public Boolean updateQAFeedback(@RequestParam(value = "id") Integer id,
|
||||||
@RequestParam(value = "score") Integer score,
|
@RequestParam(value = "score") Integer score,
|
||||||
@RequestParam(value = "feedback", required = false) String feedback) {
|
@RequestParam(value = "feedback", required = false) String feedback) {
|
||||||
return chatService.updateFeedback(id, score, feedback);
|
return chatService.updateFeedback(id, score, feedback);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import com.tencent.supersonic.chat.api.pojo.request.ChatExecuteReq;
|
|||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatParseReq;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatParseReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatQueryDataReq;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatQueryDataReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.ChatParseResp;
|
import com.tencent.supersonic.chat.api.pojo.response.ChatParseResp;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
|
||||||
import com.tencent.supersonic.chat.server.service.ChatQueryService;
|
import com.tencent.supersonic.chat.server.service.ChatQueryService;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
import com.tencent.supersonic.common.pojo.exception.InvalidArgumentException;
|
import com.tencent.supersonic.common.pojo.exception.InvalidArgumentException;
|
||||||
@@ -51,14 +50,6 @@ public class ChatQueryController {
|
|||||||
return chatQueryService.execute(chatExecuteReq);
|
return chatQueryService.execute(chatExecuteReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("getExecuteSummary")
|
|
||||||
public Object getExecuteSummary(@RequestBody ChatExecuteReq chatExecuteReq,
|
|
||||||
HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
chatExecuteReq.setUser(UserHolder.findUser(request, response));
|
|
||||||
QueryResult res = chatQueryService.getTextSummary(chatExecuteReq);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/")
|
@PostMapping("/")
|
||||||
public Object query(@RequestBody ChatParseReq chatParseReq, HttpServletRequest request,
|
public Object query(@RequestBody ChatParseReq chatParseReq, HttpServletRequest request,
|
||||||
HttpServletResponse response) throws Exception {
|
HttpServletResponse response) throws Exception {
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import com.github.pagehelper.PageInfo;
|
|||||||
import com.tencent.supersonic.auth.api.authentication.utils.UserHolder;
|
import com.tencent.supersonic.auth.api.authentication.utils.UserHolder;
|
||||||
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.request.ChatMemoryCreateReq;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryCreateReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryDeleteReq;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryUpdateReq;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryUpdateReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.PageMemoryReq;
|
import com.tencent.supersonic.chat.api.pojo.request.PageMemoryReq;
|
||||||
import com.tencent.supersonic.chat.server.pojo.ChatMemory;
|
import com.tencent.supersonic.chat.server.pojo.ChatMemory;
|
||||||
import com.tencent.supersonic.chat.server.service.MemoryService;
|
import com.tencent.supersonic.chat.server.service.MemoryService;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.request.MetaBatchReq;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -53,10 +53,8 @@ public class MemoryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("batchDelete")
|
@PostMapping("batchDelete")
|
||||||
public Boolean deleteMemory(@RequestBody ChatMemoryDeleteReq chatMemoryDeleteReq,
|
public Boolean batchDelete(@RequestBody MetaBatchReq metaBatchReq) {
|
||||||
HttpServletRequest request, HttpServletResponse response) {
|
memoryService.batchDelete(metaBatchReq.getIds());
|
||||||
User user = UserHolder.findUser(request, response);
|
|
||||||
memoryService.batchDelete(chatMemoryDeleteReq, user);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import com.tencent.supersonic.chat.server.persistence.dataobject.ChatParseDO;
|
|||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatQueryDO;
|
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatQueryDO;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
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 java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ public interface ChatManageService {
|
|||||||
|
|
||||||
boolean updateChatName(Long chatId, String chatName, String userName);
|
boolean updateChatName(Long chatId, String chatName, String userName);
|
||||||
|
|
||||||
boolean updateFeedback(Long id, Integer score, String feedback);
|
boolean updateFeedback(Integer id, Integer score, String feedback);
|
||||||
|
|
||||||
boolean updateChatIsTop(Long chatId, int isTop);
|
boolean updateChatIsTop(Long chatId, int isTop);
|
||||||
|
|
||||||
@@ -35,8 +36,6 @@ public interface ChatManageService {
|
|||||||
|
|
||||||
QueryResp getChatQuery(Long queryId);
|
QueryResp getChatQuery(Long queryId);
|
||||||
|
|
||||||
ChatQueryDO getChatQueryDO(Long queryId);
|
|
||||||
|
|
||||||
List<QueryResp> getChatQueries(Integer chatId);
|
List<QueryResp> getChatQueries(Integer chatId);
|
||||||
|
|
||||||
ShowCaseResp queryShowCase(PageQueryInfoReq pageQueryInfoReq, int agentId);
|
ShowCaseResp queryShowCase(PageQueryInfoReq pageQueryInfoReq, int agentId);
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ public interface ChatQueryService {
|
|||||||
|
|
||||||
QueryResult execute(ChatExecuteReq chatExecuteReq) throws Exception;
|
QueryResult execute(ChatExecuteReq chatExecuteReq) throws Exception;
|
||||||
|
|
||||||
QueryResult getTextSummary(ChatExecuteReq chatExecuteReq);
|
|
||||||
|
|
||||||
QueryResult parseAndExecute(ChatParseReq chatParseReq);
|
QueryResult parseAndExecute(ChatParseReq chatParseReq);
|
||||||
|
|
||||||
Object queryData(ChatQueryDataReq chatQueryDataReq, User user) throws Exception;
|
Object queryData(ChatQueryDataReq chatQueryDataReq, User user) throws Exception;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.tencent.supersonic.chat.server.service;
|
package com.tencent.supersonic.chat.server.service;
|
||||||
|
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryDeleteReq;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryFilter;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryFilter;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryUpdateReq;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryUpdateReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.PageMemoryReq;
|
import com.tencent.supersonic.chat.api.pojo.request.PageMemoryReq;
|
||||||
@@ -15,7 +14,9 @@ public interface MemoryService {
|
|||||||
|
|
||||||
void updateMemory(ChatMemoryUpdateReq chatMemoryUpdateReq, User user);
|
void updateMemory(ChatMemoryUpdateReq chatMemoryUpdateReq, User user);
|
||||||
|
|
||||||
void batchDelete(ChatMemoryDeleteReq chatMemoryDeleteReq, User user);
|
void updateMemory(ChatMemory memory);
|
||||||
|
|
||||||
|
void batchDelete(List<Long> ids);
|
||||||
|
|
||||||
PageInfo<ChatMemory> pageMemories(PageMemoryReq pageMemoryReq);
|
PageInfo<ChatMemory> pageMemories(PageMemoryReq pageMemoryReq);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.tencent.supersonic.chat.server.service.impl;
|
package com.tencent.supersonic.chat.server.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.tencent.supersonic.auth.api.authentication.service.UserService;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryFilter;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryFilter;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatParseReq;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatParseReq;
|
||||||
import com.tencent.supersonic.chat.server.agent.Agent;
|
import com.tencent.supersonic.chat.server.agent.Agent;
|
||||||
@@ -21,15 +20,13 @@ import com.tencent.supersonic.common.util.JsonUtil;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -40,18 +37,12 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
|
|||||||
private MemoryService memoryService;
|
private MemoryService memoryService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Lazy
|
|
||||||
private ChatQueryService chatQueryService;
|
private ChatQueryService chatQueryService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ChatModelService chatModelService;
|
private ChatModelService chatModelService;
|
||||||
|
|
||||||
@Autowired
|
private ExecutorService executorService = Executors.newFixedThreadPool(1);
|
||||||
private UserService userService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("chatExecutor")
|
|
||||||
private ThreadPoolExecutor executor;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Agent> getAgents(User user, AuthType authType) {
|
public List<Agent> getAgents(User user, AuthType authType) {
|
||||||
@@ -60,19 +51,17 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean filterByAuth(Agent agent, User user, AuthType authType) {
|
private boolean filterByAuth(Agent agent, User user, AuthType authType) {
|
||||||
Set<String> orgIds = userService.getUserAllOrgId(user.getName());
|
if (user.isSuperAdmin() || user.getName().equals(agent.getCreatedBy())) {
|
||||||
|
|
||||||
if (user.isSuperAdmin() || agent.openToAll()
|
|
||||||
|| user.getName().equals(agent.getCreatedBy())) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
authType = authType == null ? AuthType.VIEWER : authType;
|
authType = authType == null ? AuthType.VIEWER : authType;
|
||||||
switch (authType) {
|
switch (authType) {
|
||||||
case ADMIN:
|
case ADMIN:
|
||||||
return checkAdminPermission(orgIds, user, agent);
|
return agent.contains(user, Agent::getAdmins);
|
||||||
case VIEWER:
|
case VIEWER:
|
||||||
default:
|
default:
|
||||||
return checkViewPermission(orgIds, user, agent);
|
return agent.contains(user, Agent::getAdmins)
|
||||||
|
|| agent.contains(user, Agent::getViewers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +108,7 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
|
|||||||
* @param agent
|
* @param agent
|
||||||
*/
|
*/
|
||||||
private void executeAgentExamplesAsync(Agent agent) {
|
private void executeAgentExamplesAsync(Agent agent) {
|
||||||
executor.execute(() -> doExecuteAgentExamples(agent));
|
executorService.execute(() -> doExecuteAgentExamples(agent));
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void doExecuteAgentExamples(Agent agent) {
|
private synchronized void doExecuteAgentExamples(Agent agent) {
|
||||||
@@ -163,18 +152,13 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
|
|||||||
JsonUtil.toMap(agentDO.getChatModelConfig(), String.class, ChatApp.class));
|
JsonUtil.toMap(agentDO.getChatModelConfig(), String.class, ChatApp.class));
|
||||||
agent.setVisualConfig(JsonUtil.toObject(agentDO.getVisualConfig(), VisualConfig.class));
|
agent.setVisualConfig(JsonUtil.toObject(agentDO.getVisualConfig(), VisualConfig.class));
|
||||||
agent.getChatAppConfig().values().forEach(c -> {
|
agent.getChatAppConfig().values().forEach(c -> {
|
||||||
if (c.isEnable()) {// 优化,减少访问数据库的次数
|
ChatModel chatModel = chatModelService.getChatModel(c.getChatModelId());
|
||||||
ChatModel chatModel = chatModelService.getChatModel(c.getChatModelId());
|
if (Objects.nonNull(chatModel)) {
|
||||||
if (Objects.nonNull(chatModel)) {
|
c.setChatModelConfig(chatModelService.getChatModel(c.getChatModelId()).getConfig());
|
||||||
c.setChatModelConfig(chatModel.getConfig());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
agent.setAdmins(JsonUtil.toList(agentDO.getAdmin(), String.class));
|
agent.setAdmins(JsonUtil.toList(agentDO.getAdmin(), String.class));
|
||||||
agent.setViewers(JsonUtil.toList(agentDO.getViewer(), String.class));
|
agent.setViewers(JsonUtil.toList(agentDO.getViewer(), String.class));
|
||||||
agent.setAdminOrgs(JsonUtil.toList(agentDO.getAdminOrg(), String.class));
|
|
||||||
agent.setViewOrgs(JsonUtil.toList(agentDO.getViewOrg(), String.class));
|
|
||||||
agent.setIsOpen(agentDO.getIsOpen());
|
|
||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,56 +171,9 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
|
|||||||
agentDO.setVisualConfig(JsonUtil.toString(agent.getVisualConfig()));
|
agentDO.setVisualConfig(JsonUtil.toString(agent.getVisualConfig()));
|
||||||
agentDO.setAdmin(JsonUtil.toString(agent.getAdmins()));
|
agentDO.setAdmin(JsonUtil.toString(agent.getAdmins()));
|
||||||
agentDO.setViewer(JsonUtil.toString(agent.getViewers()));
|
agentDO.setViewer(JsonUtil.toString(agent.getViewers()));
|
||||||
agentDO.setAdminOrg(JsonUtil.toString(agent.getAdminOrgs()));
|
|
||||||
agentDO.setViewOrg(JsonUtil.toString(agent.getViewOrgs()));
|
|
||||||
agentDO.setIsOpen(agent.getIsOpen());
|
|
||||||
if (agentDO.getStatus() == null) {
|
if (agentDO.getStatus() == null) {
|
||||||
agentDO.setStatus(1);
|
agentDO.setStatus(1);
|
||||||
}
|
}
|
||||||
return agentDO;
|
return agentDO;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkAdminPermission(Set<String> orgIds, User user, Agent agent) {
|
|
||||||
List<String> admins = agent.getAdmins();
|
|
||||||
List<String> adminOrgs = agent.getAdminOrgs();
|
|
||||||
if (user.isSuperAdmin()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (admins.contains(user.getName()) || agent.getCreatedBy().equals(user.getName())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isEmpty(adminOrgs)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (String orgId : orgIds) {
|
|
||||||
if (adminOrgs.contains(orgId)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean checkViewPermission(Set<String> orgIds, User user, Agent agent) {
|
|
||||||
if (checkAdminPermission(orgIds, user, agent)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
List<String> viewers = agent.getViewers();
|
|
||||||
List<String> viewOrgs = agent.getViewOrgs();
|
|
||||||
if (agent.openToAll()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (viewers.contains(user.getName())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isEmpty(viewOrgs)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (String orgId : orgIds) {
|
|
||||||
if (viewOrgs.contains(orgId)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package com.tencent.supersonic.chat.server.service.impl;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryReviewResult;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatExecuteReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryStatus;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatParseReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.*;
|
import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.ChatParseResp;
|
import com.tencent.supersonic.chat.api.pojo.response.ChatParseResp;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResp;
|
import com.tencent.supersonic.chat.api.pojo.response.QueryResp;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
||||||
@@ -15,12 +15,11 @@ import com.tencent.supersonic.chat.server.persistence.dataobject.ChatQueryDO;
|
|||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.QueryDO;
|
import com.tencent.supersonic.chat.server.persistence.dataobject.QueryDO;
|
||||||
import com.tencent.supersonic.chat.server.persistence.repository.ChatQueryRepository;
|
import com.tencent.supersonic.chat.server.persistence.repository.ChatQueryRepository;
|
||||||
import com.tencent.supersonic.chat.server.persistence.repository.ChatRepository;
|
import com.tencent.supersonic.chat.server.persistence.repository.ChatRepository;
|
||||||
import com.tencent.supersonic.chat.server.pojo.ChatMemory;
|
|
||||||
import com.tencent.supersonic.chat.server.service.ChatManageService;
|
import com.tencent.supersonic.chat.server.service.ChatManageService;
|
||||||
import com.tencent.supersonic.chat.server.service.MemoryService;
|
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
import com.tencent.supersonic.common.util.JsonUtil;
|
import com.tencent.supersonic.common.util.JsonUtil;
|
||||||
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 lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -39,8 +38,6 @@ public class ChatManageServiceImpl implements ChatManageService {
|
|||||||
private ChatRepository chatRepository;
|
private ChatRepository chatRepository;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ChatQueryRepository chatQueryRepository;
|
private ChatQueryRepository chatQueryRepository;
|
||||||
@Autowired
|
|
||||||
private MemoryService memoryService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long addChat(User user, String chatName, Integer agentId) {
|
public Long addChat(User user, String chatName, Integer agentId) {
|
||||||
@@ -67,28 +64,11 @@ public class ChatManageServiceImpl implements ChatManageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateFeedback(Long id, Integer score, String feedback) {
|
public boolean updateFeedback(Integer id, Integer score, String feedback) {
|
||||||
QueryDO intelligentQueryDO = new QueryDO();
|
QueryDO intelligentQueryDO = new QueryDO();
|
||||||
intelligentQueryDO.setId(id);
|
intelligentQueryDO.setId(id);
|
||||||
intelligentQueryDO.setQuestionId(id);
|
|
||||||
intelligentQueryDO.setScore(score);
|
intelligentQueryDO.setScore(score);
|
||||||
intelligentQueryDO.setFeedback(feedback);
|
intelligentQueryDO.setFeedback(feedback);
|
||||||
|
|
||||||
// enable or disable memory based on user feedback
|
|
||||||
if (score >= 5 || score <= 1) {
|
|
||||||
ChatMemoryFilter memoryFilter = ChatMemoryFilter.builder().queryId(id).build();
|
|
||||||
List<ChatMemory> memories = memoryService.getMemories(memoryFilter);
|
|
||||||
memories.forEach(m -> {
|
|
||||||
MemoryStatus status = score >= 5 ? MemoryStatus.ENABLED : MemoryStatus.DISABLED;
|
|
||||||
MemoryReviewResult reviewResult =
|
|
||||||
score >= 5 ? MemoryReviewResult.POSITIVE : MemoryReviewResult.NEGATIVE;
|
|
||||||
ChatMemoryUpdateReq memoryUpdateReq = ChatMemoryUpdateReq.builder().id(m.getId())
|
|
||||||
.status(status).humanReviewRet(reviewResult)
|
|
||||||
.humanReviewCmt("Reviewed as per user feedback").build();
|
|
||||||
memoryService.updateMemory(memoryUpdateReq, User.getDefaultUser());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return chatRepository.updateFeedback(intelligentQueryDO);
|
return chatRepository.updateFeedback(intelligentQueryDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,11 +103,6 @@ public class ChatManageServiceImpl implements ChatManageService {
|
|||||||
return chatQueryRepository.getChatQuery(queryId);
|
return chatQueryRepository.getChatQuery(queryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ChatQueryDO getChatQueryDO(Long queryId) {
|
|
||||||
return chatQueryRepository.getChatQueryDO(queryId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<QueryResp> getChatQueries(Integer chatId) {
|
public List<QueryResp> getChatQueries(Integer chatId) {
|
||||||
List<QueryResp> queries = chatQueryRepository.getChatQueries(chatId);
|
List<QueryResp> queries = chatQueryRepository.getChatQueries(chatId);
|
||||||
@@ -238,10 +213,6 @@ public class ChatManageServiceImpl implements ChatManageService {
|
|||||||
@Override
|
@Override
|
||||||
public SemanticParseInfo getParseInfo(Long questionId, int parseId) {
|
public SemanticParseInfo getParseInfo(Long questionId, int parseId) {
|
||||||
ChatParseDO chatParseDO = chatQueryRepository.getParseInfo(questionId, parseId);
|
ChatParseDO chatParseDO = chatQueryRepository.getParseInfo(questionId, parseId);
|
||||||
if (chatParseDO == null) {
|
return JSONObject.parseObject(chatParseDO.getParseInfo(), SemanticParseInfo.class);
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return JSONObject.parseObject(chatParseDO.getParseInfo(), SemanticParseInfo.class);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.tencent.supersonic.chat.server.service.impl;
|
package com.tencent.supersonic.chat.server.service.impl;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
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.request.ChatParseReq;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatParseReq;
|
||||||
@@ -10,10 +9,8 @@ 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.chat.server.executor.ChatQueryExecutor;
|
import com.tencent.supersonic.chat.server.executor.ChatQueryExecutor;
|
||||||
import com.tencent.supersonic.chat.server.parser.ChatQueryParser;
|
import com.tencent.supersonic.chat.server.parser.ChatQueryParser;
|
||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatQueryDO;
|
|
||||||
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
||||||
import com.tencent.supersonic.chat.server.pojo.ParseContext;
|
import com.tencent.supersonic.chat.server.pojo.ParseContext;
|
||||||
import com.tencent.supersonic.chat.server.processor.execute.DataInterpretProcessor;
|
|
||||||
import com.tencent.supersonic.chat.server.processor.execute.ExecuteResultProcessor;
|
import com.tencent.supersonic.chat.server.processor.execute.ExecuteResultProcessor;
|
||||||
import com.tencent.supersonic.chat.server.processor.parse.ParseResultProcessor;
|
import com.tencent.supersonic.chat.server.processor.parse.ParseResultProcessor;
|
||||||
import com.tencent.supersonic.chat.server.service.AgentService;
|
import com.tencent.supersonic.chat.server.service.AgentService;
|
||||||
@@ -21,11 +18,7 @@ import com.tencent.supersonic.chat.server.service.ChatManageService;
|
|||||||
import com.tencent.supersonic.chat.server.service.ChatQueryService;
|
import com.tencent.supersonic.chat.server.service.ChatQueryService;
|
||||||
import com.tencent.supersonic.chat.server.util.ComponentFactory;
|
import com.tencent.supersonic.chat.server.util.ComponentFactory;
|
||||||
import com.tencent.supersonic.chat.server.util.QueryReqConverter;
|
import com.tencent.supersonic.chat.server.util.QueryReqConverter;
|
||||||
import com.tencent.supersonic.common.jsqlparser.FieldExpression;
|
import com.tencent.supersonic.common.jsqlparser.*;
|
||||||
import com.tencent.supersonic.common.jsqlparser.SqlAddHelper;
|
|
||||||
import com.tencent.supersonic.common.jsqlparser.SqlRemoveHelper;
|
|
||||||
import com.tencent.supersonic.common.jsqlparser.SqlReplaceHelper;
|
|
||||||
import com.tencent.supersonic.common.jsqlparser.SqlSelectHelper;
|
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
import com.tencent.supersonic.common.pojo.enums.FilterOperatorEnum;
|
import com.tencent.supersonic.common.pojo.enums.FilterOperatorEnum;
|
||||||
import com.tencent.supersonic.common.util.DateUtils;
|
import com.tencent.supersonic.common.util.DateUtils;
|
||||||
@@ -51,27 +44,15 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import net.sf.jsqlparser.expression.Expression;
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
import net.sf.jsqlparser.expression.LongValue;
|
import net.sf.jsqlparser.expression.LongValue;
|
||||||
import net.sf.jsqlparser.expression.StringValue;
|
import net.sf.jsqlparser.expression.StringValue;
|
||||||
import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
|
import net.sf.jsqlparser.expression.operators.relational.*;
|
||||||
import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals;
|
|
||||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
|
||||||
import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals;
|
|
||||||
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
|
|
||||||
import net.sf.jsqlparser.schema.Column;
|
import net.sf.jsqlparser.schema.Column;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
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;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -85,7 +66,6 @@ public class ChatQueryServiceImpl implements ChatQueryService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SemanticLayerService semanticLayerService;
|
private SemanticLayerService semanticLayerService;
|
||||||
@Autowired
|
@Autowired
|
||||||
@Lazy
|
|
||||||
private AgentService agentService;
|
private AgentService agentService;
|
||||||
|
|
||||||
private final List<ChatQueryParser> chatQueryParsers = ComponentFactory.getChatParsers();
|
private final List<ChatQueryParser> chatQueryParsers = ComponentFactory.getChatParsers();
|
||||||
@@ -111,25 +91,13 @@ public class ChatQueryServiceImpl implements ChatQueryService {
|
|||||||
Long queryId = chatParseReq.getQueryId();
|
Long queryId = chatParseReq.getQueryId();
|
||||||
if (Objects.isNull(queryId)) {
|
if (Objects.isNull(queryId)) {
|
||||||
queryId = chatManageService.createChatQuery(chatParseReq);
|
queryId = chatManageService.createChatQuery(chatParseReq);
|
||||||
chatParseReq.setQueryId(queryId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseContext parseContext = buildParseContext(chatParseReq, new ChatParseResp(queryId));
|
ParseContext parseContext = buildParseContext(chatParseReq, new ChatParseResp(queryId));
|
||||||
for (ChatQueryParser parser : chatQueryParsers) {
|
chatQueryParsers.forEach(p -> p.parse(parseContext));
|
||||||
if (parser.accept(parseContext)) {
|
parseResultProcessors.forEach(p -> p.process(parseContext));
|
||||||
parser.parse(parseContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ParseResultProcessor processor : parseResultProcessors) {
|
|
||||||
if (processor.accept(parseContext)) {
|
|
||||||
processor.process(parseContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parseContext.needFeedback()) {
|
if (!parseContext.needFeedback()) {
|
||||||
parseContext.getResponse().getParseTimeCost().setParseTime(System.currentTimeMillis()
|
|
||||||
- parseContext.getResponse().getParseTimeCost().getParseStartTime());
|
|
||||||
chatManageService.batchAddParse(chatParseReq, parseContext.getResponse());
|
chatManageService.batchAddParse(chatParseReq, parseContext.getResponse());
|
||||||
chatManageService.updateParseCostTime(parseContext.getResponse());
|
chatManageService.updateParseCostTime(parseContext.getResponse());
|
||||||
}
|
}
|
||||||
@@ -142,20 +110,15 @@ public class ChatQueryServiceImpl implements ChatQueryService {
|
|||||||
QueryResult queryResult = new QueryResult();
|
QueryResult queryResult = new QueryResult();
|
||||||
ExecuteContext executeContext = buildExecuteContext(chatExecuteReq);
|
ExecuteContext executeContext = buildExecuteContext(chatExecuteReq);
|
||||||
for (ChatQueryExecutor chatQueryExecutor : chatQueryExecutors) {
|
for (ChatQueryExecutor chatQueryExecutor : chatQueryExecutors) {
|
||||||
if (chatQueryExecutor.accept(executeContext)) {
|
queryResult = chatQueryExecutor.execute(executeContext);
|
||||||
queryResult = chatQueryExecutor.execute(executeContext);
|
if (queryResult != null) {
|
||||||
if (queryResult != null) {
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
executeContext.setResponse(queryResult);
|
|
||||||
if (queryResult != null) {
|
if (queryResult != null) {
|
||||||
for (ExecuteResultProcessor processor : executeResultProcessors) {
|
for (ExecuteResultProcessor processor : executeResultProcessors) {
|
||||||
if (processor.accept(executeContext)) {
|
processor.process(executeContext, queryResult);
|
||||||
processor.process(executeContext);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
saveQueryResult(chatExecuteReq, queryResult);
|
saveQueryResult(chatExecuteReq, queryResult);
|
||||||
}
|
}
|
||||||
@@ -163,21 +126,6 @@ public class ChatQueryServiceImpl implements ChatQueryService {
|
|||||||
return queryResult;
|
return queryResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public QueryResult getTextSummary(ChatExecuteReq chatExecuteReq) {
|
|
||||||
String text = DataInterpretProcessor.getTextSummary(chatExecuteReq.getQueryId());
|
|
||||||
if (StringUtils.isNotBlank(text)) {
|
|
||||||
QueryResult res = new QueryResult();
|
|
||||||
res.setTextSummary(text);
|
|
||||||
res.setQueryId(chatExecuteReq.getQueryId());
|
|
||||||
return res;
|
|
||||||
} else {
|
|
||||||
ChatQueryDO chatQueryDo = chatManageService.getChatQueryDO(chatExecuteReq.getQueryId());
|
|
||||||
QueryResult res = JSON.parseObject(chatQueryDo.getQueryResult(), QueryResult.class);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryResult parseAndExecute(ChatParseReq chatParseReq) {
|
public QueryResult parseAndExecute(ChatParseReq chatParseReq) {
|
||||||
ChatParseResp parseResp = parse(chatParseReq);
|
ChatParseResp parseResp = parse(chatParseReq);
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
package com.tencent.supersonic.chat.server.service.impl;
|
package com.tencent.supersonic.chat.server.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
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 com.tencent.supersonic.chat.api.pojo.request.ChatMemoryDeleteReq;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryFilter;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryFilter;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryUpdateReq;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryUpdateReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.PageMemoryReq;
|
import com.tencent.supersonic.chat.api.pojo.request.PageMemoryReq;
|
||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatMemoryDO;
|
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatMemoryDO;
|
||||||
import com.tencent.supersonic.chat.server.persistence.mapper.ChatMemoryMapper;
|
|
||||||
import com.tencent.supersonic.chat.server.persistence.repository.ChatMemoryRepository;
|
import com.tencent.supersonic.chat.server.persistence.repository.ChatMemoryRepository;
|
||||||
import com.tencent.supersonic.chat.server.pojo.ChatMemory;
|
import com.tencent.supersonic.chat.server.pojo.ChatMemory;
|
||||||
import com.tencent.supersonic.chat.server.service.MemoryService;
|
import com.tencent.supersonic.chat.server.service.MemoryService;
|
||||||
@@ -19,30 +16,24 @@ import com.tencent.supersonic.common.config.EmbeddingConfig;
|
|||||||
import com.tencent.supersonic.common.pojo.Text2SQLExemplar;
|
import com.tencent.supersonic.common.pojo.Text2SQLExemplar;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
import com.tencent.supersonic.common.service.ExemplarService;
|
import com.tencent.supersonic.common.service.ExemplarService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import com.tencent.supersonic.common.util.BeanMapper;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.CommandLineRunner;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
public class MemoryServiceImpl implements MemoryService {
|
||||||
public class MemoryServiceImpl implements MemoryService, CommandLineRunner {
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ChatMemoryRepository chatMemoryRepository;
|
private ChatMemoryRepository chatMemoryRepository;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ChatMemoryMapper chatMemoryMapper;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ExemplarService exemplarService;
|
private ExemplarService exemplarService;
|
||||||
|
|
||||||
@@ -66,66 +57,24 @@ public class MemoryServiceImpl implements MemoryService, CommandLineRunner {
|
|||||||
ChatMemoryDO chatMemoryDO = chatMemoryRepository.getMemory(chatMemoryUpdateReq.getId());
|
ChatMemoryDO chatMemoryDO = chatMemoryRepository.getMemory(chatMemoryUpdateReq.getId());
|
||||||
boolean hadEnabled =
|
boolean hadEnabled =
|
||||||
MemoryStatus.ENABLED.toString().equals(chatMemoryDO.getStatus().trim());
|
MemoryStatus.ENABLED.toString().equals(chatMemoryDO.getStatus().trim());
|
||||||
|
chatMemoryDO.setUpdatedBy(user.getName());
|
||||||
if (MemoryStatus.ENABLED.equals(chatMemoryUpdateReq.getStatus())) {
|
chatMemoryDO.setUpdatedAt(new Date());
|
||||||
// Update the latest SQL/Schema to vector DB once memory is enabled
|
BeanMapper.mapper(chatMemoryUpdateReq, chatMemoryDO);
|
||||||
chatMemoryDO.setS2sql(chatMemoryUpdateReq.getS2sql());
|
if (MemoryStatus.ENABLED.equals(chatMemoryUpdateReq.getStatus()) && !hadEnabled) {
|
||||||
chatMemoryDO.setDbSchema(chatMemoryUpdateReq.getDbSchema());
|
|
||||||
enableMemory(chatMemoryDO);
|
enableMemory(chatMemoryDO);
|
||||||
} else if ((MemoryStatus.DISABLED.equals(chatMemoryUpdateReq.getStatus())
|
} else if (MemoryStatus.DISABLED.equals(chatMemoryUpdateReq.getStatus()) && hadEnabled) {
|
||||||
|| MemoryStatus.PENDING.equals(chatMemoryUpdateReq.getStatus())) && hadEnabled) {
|
|
||||||
// Remove from vector DB when transitioning: launched→disabled OR enabled→pending
|
|
||||||
disableMemory(chatMemoryDO);
|
disableMemory(chatMemoryDO);
|
||||||
}
|
}
|
||||||
LambdaUpdateWrapper<ChatMemoryDO> updateWrapper = new LambdaUpdateWrapper<>();
|
chatMemoryRepository.updateMemory(chatMemoryDO);
|
||||||
updateWrapper.eq(ChatMemoryDO::getId, chatMemoryDO.getId());
|
|
||||||
if (Objects.nonNull(chatMemoryUpdateReq.getStatus())) {
|
|
||||||
updateWrapper.set(ChatMemoryDO::getStatus, chatMemoryUpdateReq.getStatus());
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(chatMemoryUpdateReq.getLlmReviewRet())) {
|
|
||||||
updateWrapper.set(ChatMemoryDO::getLlmReviewRet,
|
|
||||||
chatMemoryUpdateReq.getLlmReviewRet().toString());
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(chatMemoryUpdateReq.getLlmReviewCmt())) {
|
|
||||||
updateWrapper.set(ChatMemoryDO::getLlmReviewCmt, chatMemoryUpdateReq.getLlmReviewCmt());
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(chatMemoryUpdateReq.getHumanReviewRet())) {
|
|
||||||
updateWrapper.set(ChatMemoryDO::getHumanReviewRet,
|
|
||||||
chatMemoryUpdateReq.getHumanReviewRet().toString());
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(chatMemoryUpdateReq.getHumanReviewCmt())) {
|
|
||||||
updateWrapper.set(ChatMemoryDO::getHumanReviewCmt,
|
|
||||||
chatMemoryUpdateReq.getHumanReviewCmt());
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(chatMemoryUpdateReq.getDbSchema())) {
|
|
||||||
updateWrapper.set(ChatMemoryDO::getDbSchema, chatMemoryUpdateReq.getDbSchema());
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(chatMemoryUpdateReq.getS2sql())) {
|
|
||||||
updateWrapper.set(ChatMemoryDO::getS2sql, chatMemoryUpdateReq.getS2sql());
|
|
||||||
}
|
|
||||||
updateWrapper.set(ChatMemoryDO::getUpdatedAt, new Date());
|
|
||||||
updateWrapper.set(ChatMemoryDO::getUpdatedBy, user.getName());
|
|
||||||
|
|
||||||
chatMemoryMapper.update(updateWrapper);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void batchDelete(ChatMemoryDeleteReq chatMemoryDeleteReq, User user) {
|
public void updateMemory(ChatMemory memory) {
|
||||||
QueryWrapper<ChatMemoryDO> queryWrapper = new QueryWrapper<>();
|
chatMemoryRepository.updateMemory(getMemoryDO(memory));
|
||||||
if (!CollectionUtils.isEmpty(chatMemoryDeleteReq.getIds())) {
|
}
|
||||||
queryWrapper.lambda().in(ChatMemoryDO::getId, chatMemoryDeleteReq.getIds());
|
|
||||||
}
|
@Override
|
||||||
if (chatMemoryDeleteReq.getAgentId() != null) {
|
public void batchDelete(List<Long> ids) {
|
||||||
queryWrapper.lambda().eq(ChatMemoryDO::getAgentId, chatMemoryDeleteReq.getAgentId());
|
|
||||||
}
|
|
||||||
List<ChatMemoryDO> chatMemoryDOS = chatMemoryRepository.getMemories(queryWrapper);
|
|
||||||
List<Long> ids = new ArrayList<>();
|
|
||||||
chatMemoryDOS.forEach(chatMemoryDO -> {
|
|
||||||
if (MemoryStatus.ENABLED.toString().equals(chatMemoryDO.getStatus().trim())) {
|
|
||||||
disableMemory(chatMemoryDO);
|
|
||||||
}
|
|
||||||
ids.add(chatMemoryDO.getId());
|
|
||||||
});
|
|
||||||
chatMemoryRepository.batchDelete(ids);
|
chatMemoryRepository.batchDelete(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,9 +93,6 @@ public class MemoryServiceImpl implements MemoryService, CommandLineRunner {
|
|||||||
if (chatMemoryFilter.getAgentId() != null) {
|
if (chatMemoryFilter.getAgentId() != null) {
|
||||||
queryWrapper.lambda().eq(ChatMemoryDO::getAgentId, chatMemoryFilter.getAgentId());
|
queryWrapper.lambda().eq(ChatMemoryDO::getAgentId, chatMemoryFilter.getAgentId());
|
||||||
}
|
}
|
||||||
if (chatMemoryFilter.getQueryId() != null) {
|
|
||||||
queryWrapper.lambda().eq(ChatMemoryDO::getQueryId, chatMemoryFilter.getQueryId());
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotBlank(chatMemoryFilter.getQuestion())) {
|
if (StringUtils.isNotBlank(chatMemoryFilter.getQuestion())) {
|
||||||
queryWrapper.lambda().like(ChatMemoryDO::getQuestion, chatMemoryFilter.getQuestion());
|
queryWrapper.lambda().like(ChatMemoryDO::getQuestion, chatMemoryFilter.getQuestion());
|
||||||
}
|
}
|
||||||
@@ -174,7 +120,7 @@ public class MemoryServiceImpl implements MemoryService, CommandLineRunner {
|
|||||||
return chatMemoryDOS.stream().map(this::getMemory).collect(Collectors.toList());
|
return chatMemoryDOS.stream().map(this::getMemory).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableMemory(ChatMemoryDO memory) {
|
private void enableMemory(ChatMemoryDO memory) {
|
||||||
memory.setStatus(MemoryStatus.ENABLED.toString());
|
memory.setStatus(MemoryStatus.ENABLED.toString());
|
||||||
exemplarService.storeExemplar(embeddingConfig.getMemoryCollectionName(memory.getAgentId()),
|
exemplarService.storeExemplar(embeddingConfig.getMemoryCollectionName(memory.getAgentId()),
|
||||||
Text2SQLExemplar.builder().question(memory.getQuestion())
|
Text2SQLExemplar.builder().question(memory.getQuestion())
|
||||||
@@ -182,7 +128,7 @@ public class MemoryServiceImpl implements MemoryService, CommandLineRunner {
|
|||||||
.sql(memory.getS2sql()).build());
|
.sql(memory.getS2sql()).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disableMemory(ChatMemoryDO memory) {
|
private void disableMemory(ChatMemoryDO memory) {
|
||||||
memory.setStatus(MemoryStatus.DISABLED.toString());
|
memory.setStatus(MemoryStatus.DISABLED.toString());
|
||||||
exemplarService.removeExemplar(embeddingConfig.getMemoryCollectionName(memory.getAgentId()),
|
exemplarService.removeExemplar(embeddingConfig.getMemoryCollectionName(memory.getAgentId()),
|
||||||
Text2SQLExemplar.builder().question(memory.getQuestion())
|
Text2SQLExemplar.builder().question(memory.getQuestion())
|
||||||
@@ -218,25 +164,4 @@ public class MemoryServiceImpl implements MemoryService, CommandLineRunner {
|
|||||||
return memory;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(String... args) { // 优化,启动时检查,向量数据,将记忆放到向量数据库
|
|
||||||
loadSysExemplars();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadSysExemplars() {
|
|
||||||
try {
|
|
||||||
List<ChatMemory> memories = this
|
|
||||||
.getMemories(ChatMemoryFilter.builder().status(MemoryStatus.ENABLED).build());
|
|
||||||
for (ChatMemory memory : memories) {
|
|
||||||
exemplarService.storeExemplar(
|
|
||||||
embeddingConfig.getMemoryCollectionName(memory.getAgentId()),
|
|
||||||
Text2SQLExemplar.builder().question(memory.getQuestion())
|
|
||||||
.sideInfo(memory.getSideInfo()).dbSchema(memory.getDbSchema())
|
|
||||||
.sql(memory.getS2sql()).build());
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Failed to load system exemplars", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ public class PluginServiceImpl implements PluginService {
|
|||||||
if (StringUtils.isNotBlank(pluginQueryReq.getCreatedBy())) {
|
if (StringUtils.isNotBlank(pluginQueryReq.getCreatedBy())) {
|
||||||
queryWrapper.lambda().eq(PluginDO::getCreatedBy, pluginQueryReq.getCreatedBy());
|
queryWrapper.lambda().eq(PluginDO::getCreatedBy, pluginQueryReq.getCreatedBy());
|
||||||
}
|
}
|
||||||
queryWrapper.orderByAsc("name");
|
|
||||||
List<PluginDO> pluginDOS = pluginRepository.query(queryWrapper);
|
List<PluginDO> pluginDOS = pluginRepository.query(queryWrapper);
|
||||||
if (StringUtils.isNotBlank(pluginQueryReq.getPattern())) {
|
if (StringUtils.isNotBlank(pluginQueryReq.getPattern())) {
|
||||||
pluginDOS = pluginDOS.stream()
|
pluginDOS = pluginDOS.stream()
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class ResultFormatter {
|
|||||||
}
|
}
|
||||||
for (Map<String, Object> row : queryResults) {
|
for (Map<String, Object> row : queryResults) {
|
||||||
for (QueryColumn column : queryColumns) {
|
for (QueryColumn column : queryColumns) {
|
||||||
String columnKey = column.getBizName();
|
String columnKey = column.getNameEn();
|
||||||
Object value = row.get(columnKey);
|
Object value = row.get(columnKey);
|
||||||
table.append("| ").append(value != null ? value.toString() : "").append(" ");
|
table.append("| ").append(value != null ? value.toString() : "").append(" ");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,7 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-autoconfigure-processor</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
@@ -36,7 +33,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||||
<artifactId>httpclient5</artifactId>
|
<artifactId>httpclient5</artifactId>
|
||||||
<version>${httpclient5.version}</version>
|
<version>${httpclient5.version}</version> <!-- 请确认使用最新稳定版本 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
<!-- <groupId>org.apache.httpcomponents</groupId>-->
|
<!-- <groupId>org.apache.httpcomponents</groupId>-->
|
||||||
@@ -179,11 +176,11 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>dev.langchain4j</groupId>
|
<groupId>dev.langchain4j</groupId>
|
||||||
<artifactId>langchain4j-opensearch</artifactId>
|
<artifactId>langchain4j-pgvector</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>dev.langchain4j</groupId>
|
<groupId>dev.langchain4j</groupId>
|
||||||
<artifactId>langchain4j-pgvector</artifactId>
|
<artifactId>langchain4j-azure-open-ai</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>dev.langchain4j</groupId>
|
<groupId>dev.langchain4j</groupId>
|
||||||
@@ -197,6 +194,34 @@
|
|||||||
<groupId>dev.langchain4j</groupId>
|
<groupId>dev.langchain4j</groupId>
|
||||||
<artifactId>langchain4j-embeddings-all-minilm-l6-v2-q</artifactId>
|
<artifactId>langchain4j-embeddings-all-minilm-l6-v2-q</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>dev.langchain4j</groupId>
|
||||||
|
<artifactId>langchain4j-qianfan</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>dev.langchain4j</groupId>
|
||||||
|
<artifactId>langchain4j-zhipu-ai</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>dev.langchain4j</groupId>
|
||||||
|
<artifactId>langchain4j-dashscope</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>dev.langchain4j</groupId>
|
||||||
|
<artifactId>langchain4j-chatglm</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>dev.langchain4j</groupId>
|
<groupId>dev.langchain4j</groupId>
|
||||||
<artifactId>langchain4j-ollama</artifactId>
|
<artifactId>langchain4j-ollama</artifactId>
|
||||||
@@ -208,14 +233,15 @@
|
|||||||
<version>${hanlp.version}</version>
|
<version>${hanlp.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-autoconfigure-processor</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.amazonaws</groupId>
|
|
||||||
<artifactId>aws-java-sdk</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.codehaus.woodstox</groupId>
|
<groupId>org.codehaus.woodstox</groupId>
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ public class LoadRemoveService {
|
|||||||
List<String> resultList = new ArrayList<>(value);
|
List<String> resultList = new ArrayList<>(value);
|
||||||
if (!CollectionUtils.isEmpty(modelIdOrDataSetIds)) {
|
if (!CollectionUtils.isEmpty(modelIdOrDataSetIds)) {
|
||||||
resultList.removeIf(nature -> {
|
resultList.removeIf(nature -> {
|
||||||
if (Objects.isNull(nature) || !nature.startsWith("_")) { // 系统的字典是以 _ 开头的,
|
if (Objects.isNull(nature)) {
|
||||||
// 过滤因引用外部字典导致的异常
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Long id = getId(nature);
|
Long id = getId(nature);
|
||||||
|
|||||||
@@ -80,9 +80,6 @@ public class Configuration {
|
|||||||
.setQuoting(Quoting.SINGLE_QUOTE).setQuotedCasing(Casing.TO_UPPER)
|
.setQuoting(Quoting.SINGLE_QUOTE).setQuotedCasing(Casing.TO_UPPER)
|
||||||
.setUnquotedCasing(Casing.TO_UPPER).setConformance(sqlDialect.getConformance())
|
.setUnquotedCasing(Casing.TO_UPPER).setConformance(sqlDialect.getConformance())
|
||||||
.setLex(Lex.BIG_QUERY);
|
.setLex(Lex.BIG_QUERY);
|
||||||
if (EngineType.HANADB.equals(engineType)) {
|
|
||||||
parserConfig = parserConfig.setQuoting(Quoting.DOUBLE_QUOTE);
|
|
||||||
}
|
|
||||||
parserConfig = parserConfig.setQuotedCasing(Casing.UNCHANGED);
|
parserConfig = parserConfig.setQuotedCasing(Casing.UNCHANGED);
|
||||||
parserConfig = parserConfig.setUnquotedCasing(Casing.UNCHANGED);
|
parserConfig = parserConfig.setUnquotedCasing(Casing.UNCHANGED);
|
||||||
return parserConfig.build();
|
return parserConfig.build();
|
||||||
|
|||||||
@@ -77,6 +77,11 @@ public class SemanticSqlConformance implements SqlConformance {
|
|||||||
return SqlConformanceEnum.BIG_QUERY.isMinusAllowed();
|
return SqlConformanceEnum.BIG_QUERY.isMinusAllowed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRegexReplaceCaptureGroupDollarIndexed() {
|
||||||
|
return SqlConformanceEnum.BIG_QUERY.isRegexReplaceCaptureGroupDollarIndexed();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isApplyAllowed() {
|
public boolean isApplyAllowed() {
|
||||||
return SqlConformanceEnum.BIG_QUERY.isApplyAllowed();
|
return SqlConformanceEnum.BIG_QUERY.isApplyAllowed();
|
||||||
|
|||||||
@@ -21,21 +21,6 @@ public class SqlDialectFactory {
|
|||||||
.withDatabaseProduct(DatabaseProduct.BIG_QUERY).withLiteralQuoteString("'")
|
.withDatabaseProduct(DatabaseProduct.BIG_QUERY).withLiteralQuoteString("'")
|
||||||
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
||||||
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(false);
|
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(false);
|
||||||
public static final Context HANADB_CONTEXT =
|
|
||||||
SqlDialect.EMPTY_CONTEXT.withDatabaseProduct(DatabaseProduct.BIG_QUERY)
|
|
||||||
.withLiteralQuoteString("'").withIdentifierQuoteString("\"")
|
|
||||||
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
|
||||||
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(true);
|
|
||||||
public static final Context PRESTO_CONTEXT =
|
|
||||||
SqlDialect.EMPTY_CONTEXT.withDatabaseProduct(DatabaseProduct.PRESTO)
|
|
||||||
.withLiteralQuoteString("'").withIdentifierQuoteString("\"")
|
|
||||||
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
|
||||||
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(true);
|
|
||||||
public static final Context KYUUBI_CONTEXT =
|
|
||||||
SqlDialect.EMPTY_CONTEXT.withDatabaseProduct(DatabaseProduct.BIG_QUERY)
|
|
||||||
.withLiteralQuoteString("'").withIdentifierQuoteString("`")
|
|
||||||
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
|
||||||
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(false);
|
|
||||||
private static Map<EngineType, SemanticSqlDialect> sqlDialectMap;
|
private static Map<EngineType, SemanticSqlDialect> sqlDialectMap;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -44,11 +29,6 @@ public class SqlDialectFactory {
|
|||||||
sqlDialectMap.put(EngineType.MYSQL, new SemanticSqlDialect(DEFAULT_CONTEXT));
|
sqlDialectMap.put(EngineType.MYSQL, new SemanticSqlDialect(DEFAULT_CONTEXT));
|
||||||
sqlDialectMap.put(EngineType.H2, new SemanticSqlDialect(DEFAULT_CONTEXT));
|
sqlDialectMap.put(EngineType.H2, new SemanticSqlDialect(DEFAULT_CONTEXT));
|
||||||
sqlDialectMap.put(EngineType.POSTGRESQL, new SemanticSqlDialect(POSTGRESQL_CONTEXT));
|
sqlDialectMap.put(EngineType.POSTGRESQL, new SemanticSqlDialect(POSTGRESQL_CONTEXT));
|
||||||
sqlDialectMap.put(EngineType.HANADB, new SemanticSqlDialect(HANADB_CONTEXT));
|
|
||||||
sqlDialectMap.put(EngineType.STARROCKS, new SemanticSqlDialect(DEFAULT_CONTEXT));
|
|
||||||
sqlDialectMap.put(EngineType.KYUUBI, new SemanticSqlDialect(KYUUBI_CONTEXT));
|
|
||||||
sqlDialectMap.put(EngineType.PRESTO, new SemanticSqlDialect(PRESTO_CONTEXT));
|
|
||||||
sqlDialectMap.put(EngineType.TRINO, new SemanticSqlDialect(PRESTO_CONTEXT));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SemanticSqlDialect getSqlDialect(EngineType engineType) {
|
public static SemanticSqlDialect getSqlDialect(EngineType engineType) {
|
||||||
|
|||||||
@@ -2,11 +2,19 @@ package com.tencent.supersonic.common.calcite;
|
|||||||
|
|
||||||
import com.tencent.supersonic.common.pojo.enums.EngineType;
|
import com.tencent.supersonic.common.pojo.enums.EngineType;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.sf.jsqlparser.expression.Alias;
|
import org.apache.calcite.sql.SqlIdentifier;
|
||||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
import org.apache.calcite.sql.SqlLiteral;
|
||||||
import net.sf.jsqlparser.statement.select.ParenthesedSelect;
|
import org.apache.calcite.sql.SqlNode;
|
||||||
import net.sf.jsqlparser.statement.select.Select;
|
import org.apache.calcite.sql.SqlNodeList;
|
||||||
import net.sf.jsqlparser.statement.select.WithItem;
|
import org.apache.calcite.sql.SqlOrderBy;
|
||||||
|
import org.apache.calcite.sql.SqlSelect;
|
||||||
|
import org.apache.calcite.sql.SqlWith;
|
||||||
|
import org.apache.calcite.sql.SqlWithItem;
|
||||||
|
import org.apache.calcite.sql.SqlWriterConfig;
|
||||||
|
import org.apache.calcite.sql.parser.SqlParseException;
|
||||||
|
import org.apache.calcite.sql.parser.SqlParser;
|
||||||
|
import org.apache.calcite.sql.parser.SqlParserPos;
|
||||||
|
import org.apache.calcite.sql.pretty.SqlPrettyWriter;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -14,37 +22,85 @@ import java.util.List;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class SqlMergeWithUtils {
|
public class SqlMergeWithUtils {
|
||||||
public static String mergeWith(EngineType engineType, String sql, List<String> parentSqlList,
|
public static String mergeWith(EngineType engineType, String sql, List<String> parentSqlList,
|
||||||
List<String> parentWithNameList) throws Exception {
|
List<String> parentWithNameList) throws SqlParseException {
|
||||||
|
SqlParser.Config parserConfig = Configuration.getParserConfig(engineType);
|
||||||
|
|
||||||
Select selectStatement = (Select) CCJSqlParserUtil.parse(sql);
|
// Parse the main SQL statement
|
||||||
List<WithItem> withItemList = new ArrayList<>();
|
SqlParser parser = SqlParser.create(sql, parserConfig);
|
||||||
|
SqlNode sqlNode1 = parser.parseQuery();
|
||||||
|
|
||||||
|
// List to hold all WITH items
|
||||||
|
List<SqlNode> withItemList = new ArrayList<>();
|
||||||
|
|
||||||
|
// Iterate over each parentSql and parentWithName pair
|
||||||
for (int i = 0; i < parentSqlList.size(); i++) {
|
for (int i = 0; i < parentSqlList.size(); i++) {
|
||||||
String parentSql = parentSqlList.get(i);
|
String parentSql = parentSqlList.get(i);
|
||||||
String parentWithName = parentWithNameList.get(i);
|
String parentWithName = parentWithNameList.get(i);
|
||||||
|
|
||||||
Select parentSelect = (Select) CCJSqlParserUtil.parse(parentSql);
|
// Parse the parent SQL statement
|
||||||
ParenthesedSelect select = new ParenthesedSelect();
|
parser = SqlParser.create(parentSql, parserConfig);
|
||||||
select.setSelect(parentSelect);
|
SqlNode sqlNode2 = parser.parseQuery();
|
||||||
|
|
||||||
// Create a new WITH item for parentWithName without quotes
|
// Create a new WITH item for parentWithName without quotes
|
||||||
WithItem withItem = new WithItem();
|
SqlWithItem withItem = new SqlWithItem(SqlParserPos.ZERO,
|
||||||
withItem.setAlias(new Alias(parentWithName));
|
new SqlIdentifier(parentWithName, SqlParserPos.ZERO), null, sqlNode2,
|
||||||
withItem.setSelect(select);
|
SqlLiteral.createBoolean(false, SqlParserPos.ZERO));
|
||||||
|
|
||||||
// Add the new WITH item to the list
|
// Add the new WITH item to the list
|
||||||
withItemList.add(withItem);
|
withItemList.add(withItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract existing WITH items from mainSelectBody if it has any
|
// Check if the main SQL node contains an ORDER BY or LIMIT clause
|
||||||
if (selectStatement.getWithItemsList() != null) {
|
SqlNode limitNode = null;
|
||||||
withItemList.addAll(selectStatement.getWithItemsList());
|
SqlNodeList orderByList = null;
|
||||||
|
if (sqlNode1 instanceof SqlOrderBy) {
|
||||||
|
SqlOrderBy sqlOrderBy = (SqlOrderBy) sqlNode1;
|
||||||
|
limitNode = sqlOrderBy.fetch;
|
||||||
|
orderByList = sqlOrderBy.orderList;
|
||||||
|
sqlNode1 = sqlOrderBy.query;
|
||||||
|
} else if (sqlNode1 instanceof SqlSelect) {
|
||||||
|
SqlSelect sqlSelect = (SqlSelect) sqlNode1;
|
||||||
|
limitNode = sqlSelect.getFetch();
|
||||||
|
sqlSelect.setFetch(null);
|
||||||
|
sqlNode1 = sqlSelect;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the new WITH items list to the main select body
|
// Extract existing WITH items from sqlNode1 if it is a SqlWith
|
||||||
selectStatement.setWithItemsList(withItemList);
|
if (sqlNode1 instanceof SqlWith) {
|
||||||
|
SqlWith sqlWith = (SqlWith) sqlNode1;
|
||||||
|
withItemList.addAll(sqlWith.withList.getList());
|
||||||
|
sqlNode1 = sqlWith.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new SqlWith node
|
||||||
|
SqlWith finalSqlNode = new SqlWith(SqlParserPos.ZERO,
|
||||||
|
new SqlNodeList(withItemList, SqlParserPos.ZERO), sqlNode1);
|
||||||
|
|
||||||
|
// If there was an ORDER BY or LIMIT clause, wrap the finalSqlNode in a SqlOrderBy
|
||||||
|
SqlNode resultNode = finalSqlNode;
|
||||||
|
if (orderByList != null || limitNode != null) {
|
||||||
|
resultNode = new SqlOrderBy(SqlParserPos.ZERO, finalSqlNode,
|
||||||
|
orderByList != null ? orderByList : SqlNodeList.EMPTY, null, limitNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom SqlPrettyWriter configuration to avoid quoting identifiers
|
||||||
|
SqlWriterConfig config = Configuration.getSqlWriterConfig(engineType);
|
||||||
// Pretty print the final SQL
|
// Pretty print the final SQL
|
||||||
return selectStatement.toString();
|
SqlPrettyWriter writer = new SqlPrettyWriter(config);
|
||||||
|
return writer.format(resultNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasWith(EngineType engineType, String sql) throws SqlParseException {
|
||||||
|
SqlParser.Config parserConfig = Configuration.getParserConfig(engineType);
|
||||||
|
SqlParser parser = SqlParser.create(sql, parserConfig);
|
||||||
|
SqlNode sqlNode = parser.parseQuery();
|
||||||
|
SqlNode sqlSelect = sqlNode;
|
||||||
|
if (sqlNode instanceof SqlOrderBy) {
|
||||||
|
SqlOrderBy sqlOrderBy = (SqlOrderBy) sqlNode;
|
||||||
|
sqlSelect = sqlOrderBy.query;
|
||||||
|
} else if (sqlNode instanceof SqlSelect) {
|
||||||
|
sqlSelect = (SqlSelect) sqlNode;
|
||||||
|
}
|
||||||
|
return sqlSelect instanceof SqlWith;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package com.tencent.supersonic.common.config;
|
package com.tencent.supersonic.common.config;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.tencent.supersonic.common.pojo.ChatModelConfig;
|
import com.tencent.supersonic.common.pojo.ChatModelConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class ChatModel {
|
public class ChatModel {
|
||||||
@@ -27,11 +25,5 @@ public class ChatModel {
|
|||||||
|
|
||||||
private String admin;
|
private String admin;
|
||||||
|
|
||||||
private List<String> viewers = Lists.newArrayList();
|
private String viewer;
|
||||||
|
|
||||||
private Integer isOpen = 0;
|
|
||||||
|
|
||||||
public boolean isPublic() {
|
|
||||||
return isOpen != null && isOpen == 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,14 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.tencent.supersonic.common.pojo.EmbeddingModelConfig;
|
import com.tencent.supersonic.common.pojo.EmbeddingModelConfig;
|
||||||
import com.tencent.supersonic.common.pojo.Parameter;
|
import com.tencent.supersonic.common.pojo.Parameter;
|
||||||
|
import dev.langchain4j.provider.AzureModelFactory;
|
||||||
|
import dev.langchain4j.provider.DashscopeModelFactory;
|
||||||
import dev.langchain4j.provider.EmbeddingModelConstant;
|
import dev.langchain4j.provider.EmbeddingModelConstant;
|
||||||
import dev.langchain4j.provider.InMemoryModelFactory;
|
import dev.langchain4j.provider.InMemoryModelFactory;
|
||||||
import dev.langchain4j.provider.OllamaModelFactory;
|
import dev.langchain4j.provider.OllamaModelFactory;
|
||||||
import dev.langchain4j.provider.OpenAiModelFactory;
|
import dev.langchain4j.provider.OpenAiModelFactory;
|
||||||
|
import dev.langchain4j.provider.QianfanModelFactory;
|
||||||
|
import dev.langchain4j.provider.ZhipuModelFactory;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -66,31 +70,52 @@ public class EmbeddingModelParameterConfig extends ParameterConfig {
|
|||||||
|
|
||||||
private static ArrayList<String> getCandidateValues() {
|
private static ArrayList<String> getCandidateValues() {
|
||||||
return Lists.newArrayList(InMemoryModelFactory.PROVIDER, OpenAiModelFactory.PROVIDER,
|
return Lists.newArrayList(InMemoryModelFactory.PROVIDER, OpenAiModelFactory.PROVIDER,
|
||||||
OllamaModelFactory.PROVIDER);
|
OllamaModelFactory.PROVIDER, DashscopeModelFactory.PROVIDER,
|
||||||
|
QianfanModelFactory.PROVIDER, ZhipuModelFactory.PROVIDER,
|
||||||
|
AzureModelFactory.PROVIDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Parameter.Dependency> getBaseUrlDependency() {
|
private static List<Parameter.Dependency> getBaseUrlDependency() {
|
||||||
return getDependency(EMBEDDING_MODEL_PROVIDER.getName(),
|
return getDependency(EMBEDDING_MODEL_PROVIDER.getName(),
|
||||||
Lists.newArrayList(OpenAiModelFactory.PROVIDER, OllamaModelFactory.PROVIDER),
|
Lists.newArrayList(OpenAiModelFactory.PROVIDER, OllamaModelFactory.PROVIDER,
|
||||||
|
AzureModelFactory.PROVIDER, DashscopeModelFactory.PROVIDER,
|
||||||
|
QianfanModelFactory.PROVIDER, ZhipuModelFactory.PROVIDER),
|
||||||
ImmutableMap.of(OpenAiModelFactory.PROVIDER, OpenAiModelFactory.DEFAULT_BASE_URL,
|
ImmutableMap.of(OpenAiModelFactory.PROVIDER, OpenAiModelFactory.DEFAULT_BASE_URL,
|
||||||
OllamaModelFactory.PROVIDER, OllamaModelFactory.DEFAULT_BASE_URL));
|
OllamaModelFactory.PROVIDER, OllamaModelFactory.DEFAULT_BASE_URL,
|
||||||
|
AzureModelFactory.PROVIDER, AzureModelFactory.DEFAULT_BASE_URL,
|
||||||
|
DashscopeModelFactory.PROVIDER, DashscopeModelFactory.DEFAULT_BASE_URL,
|
||||||
|
QianfanModelFactory.PROVIDER, QianfanModelFactory.DEFAULT_BASE_URL,
|
||||||
|
ZhipuModelFactory.PROVIDER, ZhipuModelFactory.DEFAULT_BASE_URL));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Parameter.Dependency> getApiKeyDependency() {
|
private static List<Parameter.Dependency> getApiKeyDependency() {
|
||||||
return getDependency(EMBEDDING_MODEL_PROVIDER.getName(),
|
return getDependency(EMBEDDING_MODEL_PROVIDER.getName(),
|
||||||
Lists.newArrayList(OpenAiModelFactory.PROVIDER),
|
Lists.newArrayList(OpenAiModelFactory.PROVIDER, AzureModelFactory.PROVIDER,
|
||||||
ImmutableMap.of(OpenAiModelFactory.PROVIDER, DEMO));
|
DashscopeModelFactory.PROVIDER, QianfanModelFactory.PROVIDER,
|
||||||
|
ZhipuModelFactory.PROVIDER),
|
||||||
|
ImmutableMap.of(OpenAiModelFactory.PROVIDER, DEMO, AzureModelFactory.PROVIDER, DEMO,
|
||||||
|
DashscopeModelFactory.PROVIDER, DEMO, QianfanModelFactory.PROVIDER, DEMO,
|
||||||
|
ZhipuModelFactory.PROVIDER, DEMO));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Parameter.Dependency> getModelNameDependency() {
|
private static List<Parameter.Dependency> getModelNameDependency() {
|
||||||
return getDependency(EMBEDDING_MODEL_PROVIDER.getName(),
|
return getDependency(EMBEDDING_MODEL_PROVIDER.getName(),
|
||||||
Lists.newArrayList(InMemoryModelFactory.PROVIDER, OpenAiModelFactory.PROVIDER,
|
Lists.newArrayList(InMemoryModelFactory.PROVIDER, OpenAiModelFactory.PROVIDER,
|
||||||
OllamaModelFactory.PROVIDER),
|
OllamaModelFactory.PROVIDER, AzureModelFactory.PROVIDER,
|
||||||
|
DashscopeModelFactory.PROVIDER, QianfanModelFactory.PROVIDER,
|
||||||
|
ZhipuModelFactory.PROVIDER),
|
||||||
ImmutableMap.of(InMemoryModelFactory.PROVIDER, EmbeddingModelConstant.BGE_SMALL_ZH,
|
ImmutableMap.of(InMemoryModelFactory.PROVIDER, EmbeddingModelConstant.BGE_SMALL_ZH,
|
||||||
OpenAiModelFactory.PROVIDER,
|
OpenAiModelFactory.PROVIDER,
|
||||||
OpenAiModelFactory.DEFAULT_EMBEDDING_MODEL_NAME,
|
OpenAiModelFactory.DEFAULT_EMBEDDING_MODEL_NAME,
|
||||||
OllamaModelFactory.PROVIDER,
|
OllamaModelFactory.PROVIDER,
|
||||||
OllamaModelFactory.DEFAULT_EMBEDDING_MODEL_NAME));
|
OllamaModelFactory.DEFAULT_EMBEDDING_MODEL_NAME, AzureModelFactory.PROVIDER,
|
||||||
|
AzureModelFactory.DEFAULT_EMBEDDING_MODEL_NAME,
|
||||||
|
DashscopeModelFactory.PROVIDER,
|
||||||
|
DashscopeModelFactory.DEFAULT_EMBEDDING_MODEL_NAME,
|
||||||
|
QianfanModelFactory.PROVIDER,
|
||||||
|
QianfanModelFactory.DEFAULT_EMBEDDING_MODEL_NAME,
|
||||||
|
ZhipuModelFactory.PROVIDER,
|
||||||
|
ZhipuModelFactory.DEFAULT_EMBEDDING_MODEL_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Parameter.Dependency> getModelPathDependency() {
|
private static List<Parameter.Dependency> getModelPathDependency() {
|
||||||
@@ -101,7 +126,7 @@ public class EmbeddingModelParameterConfig extends ParameterConfig {
|
|||||||
|
|
||||||
private static List<Parameter.Dependency> getSecretKeyDependency() {
|
private static List<Parameter.Dependency> getSecretKeyDependency() {
|
||||||
return getDependency(EMBEDDING_MODEL_PROVIDER.getName(),
|
return getDependency(EMBEDDING_MODEL_PROVIDER.getName(),
|
||||||
Lists.newArrayList(OpenAiModelFactory.PROVIDER),
|
Lists.newArrayList(QianfanModelFactory.PROVIDER),
|
||||||
ImmutableMap.of(OpenAiModelFactory.PROVIDER, DEMO));
|
ImmutableMap.of(QianfanModelFactory.PROVIDER, DEMO));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,9 @@ import java.util.List;
|
|||||||
public class EmbeddingStoreParameterConfig extends ParameterConfig {
|
public class EmbeddingStoreParameterConfig extends ParameterConfig {
|
||||||
private static final String MODULE_NAME = "向量数据库配置";
|
private static final String MODULE_NAME = "向量数据库配置";
|
||||||
|
|
||||||
public static final Parameter EMBEDDING_STORE_PROVIDER =
|
public static final Parameter EMBEDDING_STORE_PROVIDER = new Parameter(
|
||||||
new Parameter("s2.embedding.store.provider", EmbeddingStoreType.IN_MEMORY.name(),
|
"s2.embedding.store.provider", EmbeddingStoreType.IN_MEMORY.name(), "向量库类型",
|
||||||
"向量库类型", "目前支持四种类型:IN_MEMORY、MILVUS、CHROMA、PGVECTOR、OPENSEARCH", "list",
|
"目前支持四种类型:IN_MEMORY、MILVUS、CHROMA、PGVECTOR", "list", MODULE_NAME, getCandidateValues());
|
||||||
MODULE_NAME, getCandidateValues());
|
|
||||||
|
|
||||||
public static final Parameter EMBEDDING_STORE_BASE_URL =
|
public static final Parameter EMBEDDING_STORE_BASE_URL =
|
||||||
new Parameter("s2.embedding.store.base.url", "", "BaseUrl", "", "string", MODULE_NAME,
|
new Parameter("s2.embedding.store.base.url", "", "BaseUrl", "", "string", MODULE_NAME,
|
||||||
@@ -88,18 +87,16 @@ public class EmbeddingStoreParameterConfig extends ParameterConfig {
|
|||||||
private static ArrayList<String> getCandidateValues() {
|
private static ArrayList<String> getCandidateValues() {
|
||||||
return Lists.newArrayList(EmbeddingStoreType.IN_MEMORY.name(),
|
return Lists.newArrayList(EmbeddingStoreType.IN_MEMORY.name(),
|
||||||
EmbeddingStoreType.MILVUS.name(), EmbeddingStoreType.CHROMA.name(),
|
EmbeddingStoreType.MILVUS.name(), EmbeddingStoreType.CHROMA.name(),
|
||||||
EmbeddingStoreType.PGVECTOR.name(), EmbeddingStoreType.OPENSEARCH.name());
|
EmbeddingStoreType.PGVECTOR.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Parameter.Dependency> getBaseUrlDependency() {
|
private static List<Parameter.Dependency> getBaseUrlDependency() {
|
||||||
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
||||||
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
||||||
EmbeddingStoreType.CHROMA.name(), EmbeddingStoreType.PGVECTOR.name(),
|
EmbeddingStoreType.CHROMA.name(), EmbeddingStoreType.PGVECTOR.name()),
|
||||||
EmbeddingStoreType.OPENSEARCH.name()),
|
|
||||||
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "http://localhost:19530",
|
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "http://localhost:19530",
|
||||||
EmbeddingStoreType.CHROMA.name(), "http://localhost:8000",
|
EmbeddingStoreType.CHROMA.name(), "http://localhost:8000",
|
||||||
EmbeddingStoreType.PGVECTOR.name(), "127.0.0.1",
|
EmbeddingStoreType.PGVECTOR.name(), "127.0.0.1"));
|
||||||
EmbeddingStoreType.OPENSEARCH.name(), "http://localhost:9200"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Parameter.Dependency> getApiKeyDependency() {
|
private static List<Parameter.Dependency> getApiKeyDependency() {
|
||||||
@@ -117,19 +114,17 @@ public class EmbeddingStoreParameterConfig extends ParameterConfig {
|
|||||||
private static List<Parameter.Dependency> getDimensionDependency() {
|
private static List<Parameter.Dependency> getDimensionDependency() {
|
||||||
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
||||||
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
||||||
EmbeddingStoreType.PGVECTOR.name(), EmbeddingStoreType.OPENSEARCH.name()),
|
EmbeddingStoreType.PGVECTOR.name()),
|
||||||
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "384",
|
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "384",
|
||||||
EmbeddingStoreType.PGVECTOR.name(), "512",
|
EmbeddingStoreType.PGVECTOR.name(), "512"));
|
||||||
EmbeddingStoreType.OPENSEARCH.name(), "512"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Parameter.Dependency> getDatabaseNameDependency() {
|
private static List<Parameter.Dependency> getDatabaseNameDependency() {
|
||||||
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
||||||
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
||||||
EmbeddingStoreType.PGVECTOR.name(), EmbeddingStoreType.OPENSEARCH.name()),
|
EmbeddingStoreType.PGVECTOR.name()),
|
||||||
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "",
|
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "",
|
||||||
EmbeddingStoreType.PGVECTOR.name(), "postgres",
|
EmbeddingStoreType.PGVECTOR.name(), "postgres"));
|
||||||
EmbeddingStoreType.OPENSEARCH.name(), "ai_sql"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Parameter.Dependency> getPortDependency() {
|
private static List<Parameter.Dependency> getPortDependency() {
|
||||||
@@ -141,18 +136,16 @@ public class EmbeddingStoreParameterConfig extends ParameterConfig {
|
|||||||
private static List<Parameter.Dependency> getUserDependency() {
|
private static List<Parameter.Dependency> getUserDependency() {
|
||||||
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
||||||
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
||||||
EmbeddingStoreType.PGVECTOR.name(), EmbeddingStoreType.OPENSEARCH.name()),
|
EmbeddingStoreType.PGVECTOR.name()),
|
||||||
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "milvus",
|
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "milvus",
|
||||||
EmbeddingStoreType.PGVECTOR.name(), "postgres",
|
EmbeddingStoreType.PGVECTOR.name(), "postgres"));
|
||||||
EmbeddingStoreType.OPENSEARCH.name(), "opensearch"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Parameter.Dependency> getPasswordDependency() {
|
private static List<Parameter.Dependency> getPasswordDependency() {
|
||||||
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
||||||
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
||||||
EmbeddingStoreType.PGVECTOR.name(), EmbeddingStoreType.OPENSEARCH.name()),
|
EmbeddingStoreType.PGVECTOR.name()),
|
||||||
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "milvus",
|
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "milvus",
|
||||||
EmbeddingStoreType.PGVECTOR.name(), "postgres",
|
EmbeddingStoreType.PGVECTOR.name(), "postgres"));
|
||||||
EmbeddingStoreType.OPENSEARCH.name(), "opensearch"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.tencent.supersonic.common.config;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.common.util.S2ThreadContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class ThreadContextConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public S2ThreadContext s2ThreadContext() {
|
||||||
|
return new S2ThreadContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user