mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-10 11:07:06 +00:00
Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b60bfe6bc | ||
|
|
ff56fd1e46 | ||
|
|
c1854d7a9b | ||
|
|
12c06c8ebe | ||
|
|
6996c4c12e | ||
|
|
f3730be156 | ||
|
|
fb7a4ce3c7 | ||
|
|
a64b60e6e2 | ||
|
|
73f7bd79e4 | ||
|
|
4dee8c6b8d | ||
|
|
ee4c5ca97c | ||
|
|
d33e8e0507 | ||
|
|
10501b2d86 | ||
|
|
3dcbdb28ad | ||
|
|
1ab88360ac | ||
|
|
8cdd0b001a | ||
|
|
9a4c8fec55 | ||
|
|
fd33266e8a | ||
|
|
1d3810b173 | ||
|
|
c429e5660b | ||
|
|
3e26340152 | ||
|
|
5bba9477f9 | ||
|
|
4fe0efcfee | ||
|
|
f944f15981 | ||
|
|
cf4f58c7e9 | ||
|
|
f6aefe2fb0 | ||
|
|
aa5f3c9a83 | ||
|
|
ac2b8cc049 | ||
|
|
da3623c0fa | ||
|
|
30db8b70b7 | ||
|
|
dfba275811 | ||
|
|
031b2bff5f | ||
|
|
449ad8b117 | ||
|
|
01bfb57149 | ||
|
|
754902a67e | ||
|
|
bc84fdaa3f | ||
|
|
0c8c085285 | ||
|
|
2f565ec12a | ||
|
|
416542e6dc | ||
|
|
bb6ee3ae83 | ||
|
|
5bad7c49ee | ||
|
|
ddbbd6d8bd | ||
|
|
7fccc8d414 | ||
|
|
ef298e8e85 | ||
|
|
69a76ffc04 | ||
|
|
6a403c6179 | ||
|
|
7a4c19f5b6 | ||
|
|
5929c2aa90 | ||
|
|
bd95552854 | ||
|
|
af53812d08 | ||
|
|
8994a6ddca | ||
|
|
8733231976 | ||
|
|
7f24c4c4e0 | ||
|
|
4291ec7bd7 | ||
|
|
7f3cb5812c | ||
|
|
36136e4c15 | ||
|
|
988a025cdf | ||
|
|
aad8bb4367 | ||
|
|
5519a507ae | ||
|
|
30ee64efec | ||
|
|
901770f02c | ||
|
|
4267aa2547 | ||
|
|
9dcf8c23f2 | ||
|
|
be1ebb8d8c | ||
|
|
a0a9dad854 | ||
|
|
82f56109ac | ||
|
|
dfd25f7983 | ||
|
|
6c3370b0d2 | ||
|
|
8a8370164f | ||
|
|
46910fbfcf | ||
|
|
f93bee81cb | ||
|
|
f152deeb81 | ||
|
|
26bef3d472 | ||
|
|
cd70096c31 | ||
|
|
bcc0f9caa9 | ||
|
|
c2316c944d | ||
|
|
ae7acb4817 | ||
|
|
1d91a972da | ||
|
|
c906eb02aa | ||
|
|
f6ff0d19da | ||
|
|
eeb54e0f73 | ||
|
|
3ad18b0ee0 | ||
|
|
9d27031543 | ||
|
|
276009f014 | ||
|
|
a6428f7dbf | ||
|
|
3cccac58a1 | ||
|
|
475e071341 | ||
|
|
a6ea762dc2 | ||
|
|
8f4754329e | ||
|
|
eaa4cc5a1b | ||
|
|
0b9bfebacc | ||
|
|
c97f567cd8 | ||
|
|
b8ecfc6a99 | ||
|
|
ba83c6ca81 | ||
|
|
a41da3f5fe | ||
|
|
b29e429271 | ||
|
|
32338070cc | ||
|
|
c332734c9b | ||
|
|
93534afc35 | ||
|
|
2052352611 | ||
|
|
532a00518c | ||
|
|
895f38b6f7 | ||
|
|
eba3a8ad34 | ||
|
|
6813582ea0 | ||
|
|
6b6e54e95f | ||
|
|
26260c79f1 | ||
|
|
0a42932db2 | ||
|
|
3b4678d682 | ||
|
|
c0458ccf0e | ||
|
|
c7c70208ff | ||
|
|
3a38200448 | ||
|
|
b72e280990 | ||
|
|
0541614dad | ||
|
|
0beb3cefd3 | ||
|
|
afdf18398c | ||
|
|
bdf7df933b |
35
.github/workflows/mac-ci.yml
vendored
Normal file
35
.github/workflows/mac-ci.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
name: supersonic mac CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: macos-latest # Specify a macOS runner
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up JDK 8
|
||||||
|
uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
java-version: '8'
|
||||||
|
distribution: 'adopt'
|
||||||
|
|
||||||
|
- name: Cache Maven packages
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/Library/Caches/Maven # macOS Maven cache path
|
||||||
|
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||||
|
restore-keys: ${{ runner.os }}-m2
|
||||||
|
|
||||||
|
- name: Build with Maven
|
||||||
|
run: mvn -B package --file pom.xml
|
||||||
|
|
||||||
|
- name: Test with Maven
|
||||||
|
run: mvn test
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: supersonic CI
|
name: supersonic ubuntu CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
35
.github/workflows/windows-ci.yml
vendored
Normal file
35
.github/workflows/windows-ci.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
name: supersonic windows CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: windows-latest # Specify a Windows runner
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up JDK 8
|
||||||
|
uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
java-version: '8'
|
||||||
|
distribution: 'adopt'
|
||||||
|
|
||||||
|
- name: Cache Maven packages
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~\.m2 # Windows uses a backslash for paths
|
||||||
|
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||||
|
restore-keys: ${{ runner.os }}-m2
|
||||||
|
|
||||||
|
- name: Build with Maven
|
||||||
|
run: mvn -B package --file pom.xml
|
||||||
|
|
||||||
|
- name: Test with Maven
|
||||||
|
run: mvn test
|
||||||
@@ -4,6 +4,15 @@
|
|||||||
- "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 [0.9.0] - 2024-04-03
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- add tag abstraction and enhance tag marketplace management.
|
||||||
|
- headless-server provides Chat API interface.
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- migrate chat-core core component to headless-core.
|
||||||
|
|
||||||
## SuperSonic [0.8.6] - 2024-02-23
|
## SuperSonic [0.8.6] - 2024-02-23
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
32
README.md
32
README.md
@@ -2,30 +2,38 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
# SuperSonic (超音数)
|
# SuperSonic
|
||||||
|
|
||||||
**SuperSonic is the next-generation LLM-powered data analytics platform that integrates ChatBI and HeadlessBI**. SuperSonic provides a chat interface that empowers users to query data using natural language and visualize the results with suitable charts. To enable such experience, the only thing necessary is to build logical semantic models (definition of entities/metrics/dimensions/tags, along with their meaning, context and relationships) on top of physical data models, and **no data modification or copying** is required. Meanwhile, SuperSonic is designed to be **highly extensible**, allowing custom functionalities to be added and configured with Java SPI.
|
SuperSonic is the next-generation BI platform that integrates **Chat BI** (powered by LLM) and **Headless BI** (powered by semantic layer) paradigms. This integration ensures that Chat BI has access to the same curated and governed semantic data models as traditional BI. Furthermore, the implementation of both paradigms benefits from the integration:
|
||||||
|
|
||||||
|
- Chat BI's Text2SQL gets augmented with context-retrieval from semantic models.
|
||||||
|
- Headless BI's query interface gets extended with natural language API.
|
||||||
|
|
||||||
|
<img src="./docs/images/supersonic_ideas.png" height="75%" width="75%" align="center"/>
|
||||||
|
|
||||||
|
SuperSonic provides a **Chat BI interface** that empowers users to query data using natural language and visualize the results with suitable charts. To enable such experience, the only thing necessary is to build logical semantic models (definition of metric/dimension/tag, along with their meaning and relationships) through a **Headless BI interface**. Meanwhile, SuperSonic is designed to be extensible and composable, allowing custom implementations to be added and configured with Java SPI.
|
||||||
|
|
||||||
<img src="./docs/images/supersonic_demo.gif" height="100%" width="100%" align="center"/>
|
<img src="./docs/images/supersonic_demo.gif" height="100%" width="100%" align="center"/>
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
The emergence of Large Language Model (LLM) like ChatGPT is reshaping the way information is retrieved. In the field of data analytics, both academia and industry are primarily focused on leveraging LLM to convert natural language into SQL (so called Text2SQL or NL2SQL). While some approaches exhibit promising results, their **reliability** and **efficiency** are insufficient for real-world applications.
|
The emergence of Large Language Model (LLM) like ChatGPT is reshaping the way information is retrieved, leading to a new paradigm in the field of data analytics known as Chat BI. To implement Chat BI, both academia and industry are primarily focused on harnessing the power of LLMs to convert natural language into SQL, commonly referred to as Text2SQL or NL2SQL. While some approaches show promising results, their **reliability** falls short for large-scale real-world applications.
|
||||||
|
|
||||||
From our perspective, the key to filling the real-world gap lies in three aspects:
|
Meanwhile, another emerging paradigm called Headless BI, which focuses on constructing unified semantic data models, has garnered significant attention. Headless BI is implemented through a universal semantic layer that exposes consistent data semantics via an open API.
|
||||||
1. Integrate ChatBI with HeadlessBI encapsulating underlying data context (joins, keys, formulas, etc) to **reduce complexity**.
|
|
||||||
2. Augment the LLM with schema mappers(as a kind of preprocessor) and semantic correctors(as a kind of postprocessor) to **mitigate hallucination**.
|
|
||||||
3. Utilize rule-based schema parsers when necessary to **improve efficiency**(in terms of latency and cost).
|
|
||||||
|
|
||||||
With these ideas in mind, we develop SuperSonic as a practical reference implementation and use it to power our real-world products. Additionally, to facilitate further development of ChatBI, we decide to open source SuperSonic as an extensible framework.
|
From our perspective, the integration of Chat BI and Headless BI has the potential to enhance the Text2SQL generation in two dimensions:
|
||||||
|
|
||||||
|
1. Incorporate data semantics (such as business terms, column values, etc.) into the prompt, enabling LLM to better understand the semantics and **reduce hallucination**.
|
||||||
|
2. Offload the generation of advanced SQL syntax (such as join, formula, etc.) from LLM to the semantic layer to **reduce complexity**.
|
||||||
|
|
||||||
|
With these ideas in mind, we develop SuperSonic as a practical reference implementation and use it to power our real-world products. Additionally, to facilitate further development we decide to open source SuperSonic as an extensible framework.
|
||||||
|
|
||||||
## Out-of-the-box Features
|
## Out-of-the-box Features
|
||||||
|
|
||||||
- Built-in ChatBI interface for *business users* to enter natural language queries
|
- Built-in Chat BI interface for *business users* to enter natural language queries
|
||||||
- Built-in HeadlessBI interface for *analytics engineers* to build semantic models
|
- Built-in Headless BI interface for *analytics engineers* to build semantic data models
|
||||||
- Built-in GUI for *system administrators* to manage chat agents and third-party plugins
|
- Built-in rule-based semantic parser to improve efficiency in certain scenarios
|
||||||
- Support input auto-completion as well as query recommendation
|
- Support input auto-completion as well as query recommendation
|
||||||
- Support multi-turn conversation and history context management
|
|
||||||
- Support four-level permission control: domain-level, model-level, column-level and row-level
|
- Support four-level permission control: domain-level, model-level, column-level and row-level
|
||||||
|
|
||||||
## Extensible Components
|
## Extensible Components
|
||||||
|
|||||||
30
README_CN.md
30
README_CN.md
@@ -1,27 +1,35 @@
|
|||||||
# SuperSonic (超音数)
|
# SuperSonic
|
||||||
|
|
||||||
**SuperSonic融合ChatBI和HeadlessBI打造新一代的数据分析平台**。通过SuperSonic的问答对话界面,用户能够使用自然语言查询数据,系统会选择合适的可视化图表呈现结果。SuperSonic不需要修改或复制数据,只需要在物理数据模型之上构建逻辑语义模型(指标/维度/实体的定义,以及他们的业务含义、相互间关系等),即可开启数据问答体验。与此同时,SuperSonic被设计为可插拔的框架,采用Java SPI机制来扩展定制功能。
|
**SuperSonic融合Chat BI(powered by LLM)和Headless BI(powered by 语义层)打造新一代的BI平台**。这种融合确保了Chat BI能够与传统BI一样访问统一化治理的语义数据模型。此外,两种BI新范式都从中获得收益:
|
||||||
|
|
||||||
|
- Chat BI的Text2SQL生成通过检索语义数据模型得到增强。
|
||||||
|
- Headless BI的查询接口通过支持自然语言API得到拓展。
|
||||||
|
|
||||||
|
<img src="./docs/images/supersonic_ideas.png" height="75%" width="75%" align="center"/>
|
||||||
|
|
||||||
|
通过SuperSonic的问答对话界面,用户能够使用自然语言查询数据,系统会选择合适的可视化图表呈现结果。SuperSonic不需要修改或复制数据,只需要在物理数据模型之上构建逻辑语义模型(定义指标/维度/实体/标签,以及它们的业务含义、相互关系等),即可开启数据问答体验。与此同时,SuperSonic被设计为可插拔的框架,采用Java SPI机制来扩展定制功能。
|
||||||
|
|
||||||
<img src="./docs/images/supersonic_demo.gif" height="100%" width="100%" align="center"/>
|
<img src="./docs/images/supersonic_demo.gif" height="100%" width="100%" align="center"/>
|
||||||
|
|
||||||
## 项目动机
|
## 项目动机
|
||||||
|
|
||||||
大型语言模型(LLMs)如ChatGPT的出现正在重塑信息检索的方式。在数据分析领域,学术界和工业界主要关注利用深度学习模型将自然语言查询转换为SQL查询。虽然一些工作显示出有前景的结果,但它们的可靠性还达不到生产可用的要求。
|
大型语言模型(LLM)如ChatGPT的出现正在重塑信息检索的方式,引领数据分析领域的一种新范式,被称为Chat BI。为了实现Chat BI,学术界和工业界主要关注利用LLM的能力将自然语言转换为SQL,通常称为Text2SQL或NL2SQL。尽管一些方法显示出有希望的结果,但它们在大规模实际应用中的可靠性还不足。
|
||||||
|
|
||||||
在我们看来,为了在实际场景发挥价值,有三个关键点:
|
与此同时,另一种新兴范式被称为Headless BI,它专注于构建统一的语义数据模型,并引起了广泛的关注。Headless BI通过一个通用的语义层来实现,通过开放的API公开一致的数据语义。
|
||||||
1. 融合HeadlessBI,通过统一语义层封装底层数据细节(关联、键值、公式等),降低SQL生成的**复杂度**。
|
|
||||||
2. 通过一前一后的模式映射器和语义修正器,来缓解LLM常见的**幻觉**现象。
|
从我们的角度来看,Chat BI和Headless BI的融合有潜力在两个方面增强Text2SQL的能力:
|
||||||
3. 设计启发式的规则,在一些特定场景提升语义解析的**效率**。
|
|
||||||
|
1. 将数据语义(如业务术语、列值等)纳入提示词中,使LLM能够更好地理解语义,以**减少幻觉**。
|
||||||
|
2. 将高级SQL语法(如连接、公式等)的生成从LLM卸载到语义层,以**减少复杂度**。
|
||||||
|
|
||||||
为了验证上述想法,我们开发了SuperSonic项目,并将其应用在实际的内部产品中。与此同时,我们将SuperSonic作为一个可扩展的框架开源,希望能够促进数据问答对话领域的进一步发展。
|
为了验证上述想法,我们开发了SuperSonic项目,并将其应用在实际的内部产品中。与此同时,我们将SuperSonic作为一个可扩展的框架开源,希望能够促进数据问答对话领域的进一步发展。
|
||||||
|
|
||||||
## 开箱即用的特性
|
## 开箱即用的特性
|
||||||
|
|
||||||
- 内置ChatBI界面以便*业务用户*输入数据查询。
|
- 内置Chat BI界面以便*业务用户*输入数据查询。
|
||||||
- 内置HeadlessBI界面以便*分析工程师*构建语义模型。
|
- 内置Headless BI界面以便*分析工程师*构建语义模型。
|
||||||
- 内置图形用户界面以便*系统管理员*管理第三方插件和对话助理。
|
- 内置基于规则的语义解析器,在特定场景可以提升运行效率。
|
||||||
- 支持文本输入的联想和查询问题的推荐。
|
- 支持文本输入的联想和查询问题的推荐。
|
||||||
- 支持多轮对话,根据语境自动切换上下文。
|
|
||||||
- 支持四级权限控制:主题域级、模型级、列级、行级。
|
- 支持四级权限控制:主题域级、模型级、列级、行级。
|
||||||
|
|
||||||
## 易于扩展的组件
|
## 易于扩展的组件
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ move webapp ..\..\launchers\standalone\target\classes
|
|||||||
rem 5. build backend python modules
|
rem 5. build backend python modules
|
||||||
if "%service%"=="pyllm" (
|
if "%service%"=="pyllm" (
|
||||||
echo "start installing python modules with pip: ${pip_path}"
|
echo "start installing python modules with pip: ${pip_path}"
|
||||||
set requirementPath="%baseDir%/../chat/python/requirements.txt"
|
set requirementPath="%baseDir%/../headless/python/requirements.txt"
|
||||||
%pip_path% install -r %requirementPath%
|
%pip_path% install -r %requirementPath%
|
||||||
echo "install python modules success"
|
echo "install python modules success"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ rm -fr ${buildDir}/webapp
|
|||||||
#5. build backend python modules
|
#5. build backend python modules
|
||||||
if [ "$service" == "pyllm" ]; then
|
if [ "$service" == "pyllm" ]; then
|
||||||
echo "start installing python modules with pip: ${pip_path}"
|
echo "start installing python modules with pip: ${pip_path}"
|
||||||
requirementPath=$baseDir/../chat/python/requirements.txt
|
requirementPath=$baseDir/../headless/python/requirements.txt
|
||||||
${pip_path} install -r ${requirementPath}
|
${pip_path} install -r ${requirementPath}
|
||||||
echo "install python modules success"
|
echo "install python modules success"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.api.pojo;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class SchemaMapInfo {
|
|
||||||
|
|
||||||
private Map<Long, List<SchemaElementMatch>> viewElementMatches = new HashMap<>();
|
|
||||||
|
|
||||||
public Set<Long> getMatchedViewInfos() {
|
|
||||||
return viewElementMatches.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<SchemaElementMatch> getMatchedElements(Long view) {
|
|
||||||
return viewElementMatches.getOrDefault(view, Lists.newArrayList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Long, List<SchemaElementMatch>> getViewElementMatches() {
|
|
||||||
return viewElementMatches;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setViewElementMatches(Map<Long, List<SchemaElementMatch>> viewElementMatches) {
|
|
||||||
this.viewElementMatches = viewElementMatches;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMatchedElements(Long view, List<SchemaElementMatch> elementMatches) {
|
|
||||||
viewElementMatches.put(view, elementMatches);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,16 +16,6 @@ public class ChatConfigBaseReq {
|
|||||||
|
|
||||||
private Long modelId;
|
private Long modelId;
|
||||||
|
|
||||||
/**
|
|
||||||
* the chatDetailConfig about the model
|
|
||||||
*/
|
|
||||||
private ChatDetailConfigReq chatDetailConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the chatAggConfig about the model
|
|
||||||
*/
|
|
||||||
private ChatAggConfigReq chatAggConfig;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the recommended questions about the model
|
* the recommended questions about the model
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.tencent.supersonic.chat.api.pojo.request;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ChatExecuteReq {
|
||||||
|
private User user;
|
||||||
|
private Long queryId;
|
||||||
|
private Integer chatId;
|
||||||
|
private int parseId;
|
||||||
|
private String queryText;
|
||||||
|
private boolean saveAnswer;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,15 +1,18 @@
|
|||||||
package com.tencent.supersonic.chat.api.pojo.request;
|
package com.tencent.supersonic.chat.api.pojo.request;
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaMapInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.request.QueryFilters;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class QueryReq {
|
public class ChatParseReq {
|
||||||
private String queryText;
|
private String queryText;
|
||||||
private Integer chatId;
|
private Integer chatId;
|
||||||
private Long modelId;
|
private Integer agentId;
|
||||||
private User user;
|
private User user;
|
||||||
private QueryFilters queryFilters;
|
private QueryFilters queryFilters;
|
||||||
private boolean saveAnswer = true;
|
private boolean saveAnswer = true;
|
||||||
private Integer agentId;
|
private SchemaMapInfo mapInfo = new SchemaMapInfo();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.tencent.supersonic.chat.api.pojo.request;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||||
|
import com.tencent.supersonic.common.pojo.DateConf;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.request.QueryFilter;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ChatQueryDataReq {
|
||||||
|
private User user;
|
||||||
|
private Set<SchemaElement> metrics = new HashSet<>();
|
||||||
|
private Set<SchemaElement> dimensions = new HashSet<>();
|
||||||
|
private Set<QueryFilter> dimensionFilters = new HashSet<>();
|
||||||
|
private Set<QueryFilter> metricFilters = new HashSet<>();
|
||||||
|
private DateConf dateInfo;
|
||||||
|
private Long queryId;
|
||||||
|
private Integer parseId;
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ public class PluginQueryReq {
|
|||||||
|
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
private String view;
|
private String dataSet;
|
||||||
|
|
||||||
private String pattern;
|
private String pattern;
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class SimilarQueryReq {
|
|||||||
|
|
||||||
private String queryText;
|
private String queryText;
|
||||||
|
|
||||||
private Long viewId;
|
private Long dataSetId;
|
||||||
|
|
||||||
private Integer agentId;
|
private Integer agentId;
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.api.pojo.response;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class ParseResp {
|
|
||||||
private Integer chatId;
|
|
||||||
private String queryText;
|
|
||||||
private Long queryId;
|
|
||||||
private ParseState state;
|
|
||||||
private List<SemanticParseInfo> selectedParses = Lists.newArrayList();
|
|
||||||
private ParseTimeCostDO parseTimeCost = new ParseTimeCostDO();
|
|
||||||
|
|
||||||
public enum ParseState {
|
|
||||||
COMPLETED,
|
|
||||||
PENDING,
|
|
||||||
FAILED
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package com.tencent.supersonic.chat.api.pojo.response;
|
package com.tencent.supersonic.chat.api.pojo.response;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo;
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class QueryResp {
|
public class QueryResp {
|
||||||
|
|
||||||
@@ -18,5 +20,4 @@ public class QueryResp {
|
|||||||
private List<SemanticParseInfo> parseInfos;
|
private List<SemanticParseInfo> parseInfos;
|
||||||
private List<SimilarQueryRecallResp> similarQueries;
|
private List<SimilarQueryRecallResp> similarQueries;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -10,8 +10,6 @@ public class SimilarQueryRecallResp {
|
|||||||
|
|
||||||
private Long queryId;
|
private Long queryId;
|
||||||
|
|
||||||
private Integer parseId;
|
|
||||||
|
|
||||||
private String queryText;
|
private String queryText;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>chat</artifactId>
|
|
||||||
<groupId>com.tencent.supersonic</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>chat-core</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<maven.compiler.source>8</maven.compiler.source>
|
|
||||||
<maven.compiler.target>8</maven.compiler.target>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-context</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.testng</groupId>
|
|
||||||
<artifactId>testng</artifactId>
|
|
||||||
<version>${org.testng.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-compress</artifactId>
|
|
||||||
<version>${commons.compress.version}</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba</groupId>
|
|
||||||
<artifactId>druid</artifactId>
|
|
||||||
<version>${alibaba.druid.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>mysql</groupId>
|
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
<version>${h2.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.tencent.supersonic</groupId>
|
|
||||||
<artifactId>headless-api</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.tencent.supersonic</groupId>
|
|
||||||
<artifactId>headless-core</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.tencent.supersonic</groupId>
|
|
||||||
<artifactId>chat-api</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.xkzhangsan</groupId>
|
|
||||||
<artifactId>xk-time</artifactId>
|
|
||||||
<version>${xk.time.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-inline</artifactId>
|
|
||||||
<version>${mockito-inline.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.tencent.supersonic</groupId>
|
|
||||||
<artifactId>headless-server</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.parser.plugin.function.FunctionPromptGenerator;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.plugin.function.FunctionReq;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.plugin.function.FunctionResp;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.sql.llm.OutputFormat;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.sql.llm.SqlGeneration;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.sql.llm.SqlGenerationFactory;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.s2sql.LLMReq;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.s2sql.LLMReq.SqlGenerationMode;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.s2sql.LLMResp;
|
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
|
||||||
import dev.langchain4j.model.chat.ChatLanguageModel;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LLMProxy based on langchain4j Java version.
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class JavaLLMProxy implements LLMProxy {
|
|
||||||
|
|
||||||
private static final Logger keyPipelineLog = LoggerFactory.getLogger("keyPipeline");
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSkip(QueryContext queryContext) {
|
|
||||||
ChatLanguageModel chatLanguageModel = ContextUtils.getBean(ChatLanguageModel.class);
|
|
||||||
if (Objects.isNull(chatLanguageModel)) {
|
|
||||||
log.warn("chatLanguageModel is null, skip :{}", JavaLLMProxy.class.getName());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LLMResp query2sql(LLMReq llmReq, Long viewId) {
|
|
||||||
|
|
||||||
SqlGeneration sqlGeneration = SqlGenerationFactory.get(
|
|
||||||
SqlGenerationMode.getMode(llmReq.getSqlGenerationMode()));
|
|
||||||
String modelName = llmReq.getSchema().getViewName();
|
|
||||||
LLMResp result = sqlGeneration.generation(llmReq, viewId);
|
|
||||||
result.setQuery(llmReq.getQueryText());
|
|
||||||
result.setModelName(modelName);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FunctionResp requestFunction(FunctionReq functionReq) {
|
|
||||||
|
|
||||||
FunctionPromptGenerator promptGenerator = ContextUtils.getBean(FunctionPromptGenerator.class);
|
|
||||||
|
|
||||||
ChatLanguageModel chatLanguageModel = ContextUtils.getBean(ChatLanguageModel.class);
|
|
||||||
String functionCallPrompt = promptGenerator.generateFunctionCallPrompt(functionReq.getQueryText(),
|
|
||||||
functionReq.getPluginConfigs());
|
|
||||||
keyPipelineLog.info("functionCallPrompt:{}", functionCallPrompt);
|
|
||||||
String response = chatLanguageModel.generate(functionCallPrompt);
|
|
||||||
keyPipelineLog.info("functionCall response:{}", response);
|
|
||||||
return OutputFormat.functionCallParse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.plugin.function.FunctionReq;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.plugin.function.FunctionResp;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.s2sql.LLMReq;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.s2sql.LLMResp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LLMProxy encapsulates functions performed by LLMs so that multiple
|
|
||||||
* orchestration frameworks (e.g. LangChain in python, LangChain4j in java)
|
|
||||||
* could be used.
|
|
||||||
*/
|
|
||||||
public interface LLMProxy {
|
|
||||||
|
|
||||||
boolean isSkip(QueryContext queryContext);
|
|
||||||
|
|
||||||
LLMResp query2sql(LLMReq llmReq, Long viewId);
|
|
||||||
|
|
||||||
FunctionResp requestFunction(FunctionReq functionReq);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.QueryFilter;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.QueryFilters;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.SemanticParser;
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.Plugin;
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginManager;
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginParseResult;
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginRecallResult;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.ChatContext;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
|
||||||
import com.tencent.supersonic.chat.core.query.QueryManager;
|
|
||||||
import com.tencent.supersonic.chat.core.query.SemanticQuery;
|
|
||||||
import com.tencent.supersonic.chat.core.query.plugin.PluginSemanticQuery;
|
|
||||||
import com.tencent.supersonic.common.pojo.Constants;
|
|
||||||
import com.tencent.supersonic.common.pojo.enums.FilterOperatorEnum;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PluginParser defines the basic process and common methods for recalling plugins.
|
|
||||||
*/
|
|
||||||
public abstract class PluginParser implements SemanticParser {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void parse(QueryContext queryContext, ChatContext chatContext) {
|
|
||||||
for (SemanticQuery semanticQuery : queryContext.getCandidateQueries()) {
|
|
||||||
if (queryContext.getQueryText().length() <= semanticQuery.getParseInfo().getScore()
|
|
||||||
&& (QueryManager.getPluginQueryModes().contains(semanticQuery.getQueryMode()))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!checkPreCondition(queryContext)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PluginRecallResult pluginRecallResult = recallPlugin(queryContext);
|
|
||||||
if (pluginRecallResult == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
buildQuery(queryContext, pluginRecallResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract boolean checkPreCondition(QueryContext queryContext);
|
|
||||||
|
|
||||||
public abstract PluginRecallResult recallPlugin(QueryContext queryContext);
|
|
||||||
|
|
||||||
public void buildQuery(QueryContext queryContext, PluginRecallResult pluginRecallResult) {
|
|
||||||
Plugin plugin = pluginRecallResult.getPlugin();
|
|
||||||
Set<Long> viewIds = pluginRecallResult.getViewIds();
|
|
||||||
if (plugin.isContainsAllModel()) {
|
|
||||||
viewIds = Sets.newHashSet(-1L);
|
|
||||||
}
|
|
||||||
for (Long viewId : viewIds) {
|
|
||||||
PluginSemanticQuery pluginQuery = QueryManager.createPluginQuery(plugin.getType());
|
|
||||||
SemanticParseInfo semanticParseInfo = buildSemanticParseInfo(viewId, plugin,
|
|
||||||
queryContext, pluginRecallResult.getDistance());
|
|
||||||
semanticParseInfo.setQueryMode(pluginQuery.getQueryMode());
|
|
||||||
semanticParseInfo.setScore(pluginRecallResult.getScore());
|
|
||||||
pluginQuery.setParseInfo(semanticParseInfo);
|
|
||||||
queryContext.getCandidateQueries().add(pluginQuery);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<Plugin> getPluginList(QueryContext queryContext) {
|
|
||||||
return PluginManager.getPluginAgentCanSupport(queryContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SemanticParseInfo buildSemanticParseInfo(Long viewId, Plugin plugin,
|
|
||||||
QueryContext queryContext, double distance) {
|
|
||||||
List<SchemaElementMatch> schemaElementMatches = queryContext.getMapInfo().getMatchedElements(viewId);
|
|
||||||
QueryFilters queryFilters = queryContext.getQueryFilters();
|
|
||||||
if (viewId == null && !CollectionUtils.isEmpty(plugin.getViewList())) {
|
|
||||||
viewId = plugin.getViewList().get(0);
|
|
||||||
}
|
|
||||||
if (schemaElementMatches == null) {
|
|
||||||
schemaElementMatches = Lists.newArrayList();
|
|
||||||
}
|
|
||||||
SemanticParseInfo semanticParseInfo = new SemanticParseInfo();
|
|
||||||
semanticParseInfo.setElementMatches(schemaElementMatches);
|
|
||||||
semanticParseInfo.setView(queryContext.getSemanticSchema().getView(viewId));
|
|
||||||
Map<String, Object> properties = new HashMap<>();
|
|
||||||
PluginParseResult pluginParseResult = new PluginParseResult();
|
|
||||||
pluginParseResult.setPlugin(plugin);
|
|
||||||
pluginParseResult.setQueryFilters(queryFilters);
|
|
||||||
pluginParseResult.setDistance(distance);
|
|
||||||
pluginParseResult.setQueryText(queryContext.getQueryText());
|
|
||||||
properties.put(Constants.CONTEXT, pluginParseResult);
|
|
||||||
properties.put("type", "plugin");
|
|
||||||
properties.put("name", plugin.getName());
|
|
||||||
semanticParseInfo.setProperties(properties);
|
|
||||||
semanticParseInfo.setScore(distance);
|
|
||||||
fillSemanticParseInfo(semanticParseInfo);
|
|
||||||
return semanticParseInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fillSemanticParseInfo(SemanticParseInfo semanticParseInfo) {
|
|
||||||
List<SchemaElementMatch> schemaElementMatches = semanticParseInfo.getElementMatches();
|
|
||||||
if (CollectionUtils.isEmpty(schemaElementMatches)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
schemaElementMatches.stream().filter(schemaElementMatch ->
|
|
||||||
SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType())
|
|
||||||
|| SchemaElementType.ID.equals(schemaElementMatch.getElement().getType()))
|
|
||||||
.forEach(schemaElementMatch -> {
|
|
||||||
QueryFilter queryFilter = new QueryFilter();
|
|
||||||
queryFilter.setValue(schemaElementMatch.getWord());
|
|
||||||
queryFilter.setElementID(schemaElementMatch.getElement().getId());
|
|
||||||
queryFilter.setName(schemaElementMatch.getElement().getName());
|
|
||||||
queryFilter.setOperator(FilterOperatorEnum.EQUALS);
|
|
||||||
queryFilter.setBizName(schemaElementMatch.getElement().getBizName());
|
|
||||||
semanticParseInfo.getDimensionFilters().add(queryFilter);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin.function;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@Data
|
|
||||||
public class FunctionCallConfig {
|
|
||||||
@Value("${functionCall.url:}")
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
@Value("${funtionCall.plugin.select.path:/plugin_selection}")
|
|
||||||
private String pluginSelectPath;
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin.function;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.parser.PythonLLMProxy;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.plugin.ParseMode;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.plugin.PluginParser;
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.Plugin;
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginManager;
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginParseConfig;
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginRecallResult;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.s2sql.LLMSqlQuery;
|
|
||||||
import com.tencent.supersonic.chat.core.utils.ComponentFactory;
|
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
|
||||||
import com.tencent.supersonic.common.util.JsonUtil;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FunctionCallParser is an implementation of a recall plugin based on FunctionCall
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class FunctionCallParser extends PluginParser {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkPreCondition(QueryContext queryContext) {
|
|
||||||
FunctionCallConfig functionCallConfig = ContextUtils.getBean(FunctionCallConfig.class);
|
|
||||||
String functionUrl = functionCallConfig.getUrl();
|
|
||||||
if (StringUtils.isBlank(functionUrl) && ComponentFactory.getLLMProxy() instanceof PythonLLMProxy) {
|
|
||||||
log.info("functionUrl:{}, skip function parser, queryText:{}", functionUrl,
|
|
||||||
queryContext.getQueryText());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
List<Plugin> plugins = getPluginList(queryContext);
|
|
||||||
return !CollectionUtils.isEmpty(plugins);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PluginRecallResult recallPlugin(QueryContext queryContext) {
|
|
||||||
FunctionResp functionResp = functionCall(queryContext);
|
|
||||||
if (skipFunction(functionResp)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
log.info("requestFunction result:{}", functionResp.getToolSelection());
|
|
||||||
String toolSelection = functionResp.getToolSelection();
|
|
||||||
Plugin plugin = queryContext.getNameToPlugin().get(toolSelection);
|
|
||||||
if (Objects.isNull(plugin)) {
|
|
||||||
log.info("pluginOptional is not exist:{}, skip the parse", toolSelection);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
plugin.setParseMode(ParseMode.FUNCTION_CALL);
|
|
||||||
Pair<Boolean, Set<Long>> pluginResolveResult = PluginManager.resolve(plugin, queryContext);
|
|
||||||
if (pluginResolveResult.getLeft()) {
|
|
||||||
Set<Long> viewList = pluginResolveResult.getRight();
|
|
||||||
if (CollectionUtils.isEmpty(viewList)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
double score = queryContext.getQueryText().length();
|
|
||||||
return PluginRecallResult.builder().plugin(plugin).viewIds(viewList).score(score).build();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FunctionResp functionCall(QueryContext queryContext) {
|
|
||||||
List<PluginParseConfig> pluginToFunctionCall =
|
|
||||||
getPluginToFunctionCall(queryContext.getViewId(), queryContext);
|
|
||||||
if (CollectionUtils.isEmpty(pluginToFunctionCall)) {
|
|
||||||
log.info("function call parser, plugin is empty, skip");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
FunctionResp functionResp = new FunctionResp();
|
|
||||||
if (pluginToFunctionCall.size() == 1) {
|
|
||||||
functionResp.setToolSelection(pluginToFunctionCall.iterator().next().getName());
|
|
||||||
} else {
|
|
||||||
FunctionReq functionReq = FunctionReq.builder()
|
|
||||||
.queryText(queryContext.getQueryText())
|
|
||||||
.pluginConfigs(pluginToFunctionCall).build();
|
|
||||||
functionResp = ComponentFactory.getLLMProxy().requestFunction(functionReq);
|
|
||||||
}
|
|
||||||
return functionResp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean skipFunction(FunctionResp functionResp) {
|
|
||||||
return Objects.isNull(functionResp) || StringUtils.isBlank(functionResp.getToolSelection());
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<PluginParseConfig> getPluginToFunctionCall(Long modelId, QueryContext queryContext) {
|
|
||||||
log.info("user decide Model:{}", modelId);
|
|
||||||
List<Plugin> plugins = getPluginList(queryContext);
|
|
||||||
List<PluginParseConfig> functionDOList = plugins.stream().filter(plugin -> {
|
|
||||||
if (LLMSqlQuery.QUERY_MODE.equalsIgnoreCase(plugin.getType())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (plugin.getParseModeConfig() == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
PluginParseConfig pluginParseConfig = JsonUtil.toObject(plugin.getParseModeConfig(),
|
|
||||||
PluginParseConfig.class);
|
|
||||||
if (StringUtils.isBlank(pluginParseConfig.getName())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Pair<Boolean, Set<Long>> pluginResolverResult = PluginManager.resolve(plugin, queryContext);
|
|
||||||
log.info("plugin [{}-{}] resolve: {}", plugin.getId(), plugin.getName(), pluginResolverResult);
|
|
||||||
if (!pluginResolverResult.getLeft()) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
Set<Long> resolveModel = pluginResolverResult.getRight();
|
|
||||||
if (modelId != null && modelId > 0) {
|
|
||||||
if (plugin.isContainsAllModel()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return resolveModel.contains(modelId);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}).map(o -> JsonUtil.toObject(o.getParseModeConfig(), PluginParseConfig.class)).collect(Collectors.toList());
|
|
||||||
log.info("PluginToFunctionCall: {}", JsonUtil.toString(functionDOList));
|
|
||||||
return functionDOList;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin.function;
|
|
||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class FunctionFiled {
|
|
||||||
|
|
||||||
private String type;
|
|
||||||
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin.function;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.parser.sql.llm.InputFormat;
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginParseConfig;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
|
||||||
public class FunctionPromptGenerator {
|
|
||||||
|
|
||||||
public String generateFunctionCallPrompt(String queryText, List<PluginParseConfig> toolConfigList) {
|
|
||||||
List<String> toolExplainList = toolConfigList.stream()
|
|
||||||
.map(this::constructPluginPrompt)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
String functionList = String.join(InputFormat.SEPERATOR, toolExplainList);
|
|
||||||
return constructTaskPrompt(queryText, functionList);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String constructPluginPrompt(PluginParseConfig parseConfig) {
|
|
||||||
String toolName = parseConfig.getName();
|
|
||||||
String toolDescription = parseConfig.getDescription();
|
|
||||||
List<String> toolExamples = parseConfig.getExamples();
|
|
||||||
|
|
||||||
StringBuilder prompt = new StringBuilder();
|
|
||||||
prompt.append("【工具名称】\n").append(toolName).append("\n");
|
|
||||||
prompt.append("【工具描述】\n").append(toolDescription).append("\n");
|
|
||||||
prompt.append("【工具适用问题示例】\n");
|
|
||||||
for (String example : toolExamples) {
|
|
||||||
prompt.append(example).append("\n");
|
|
||||||
}
|
|
||||||
return prompt.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String constructTaskPrompt(String queryText, String functionList) {
|
|
||||||
String instruction = String.format("问题为:%s\n请根据问题和工具的描述,选择对应的工具,完成任务。"
|
|
||||||
+ "请注意,只能选择1个工具。请一步一步地分析选择工具的原因(每个工具的【工具适用问题示例】是选择的重要参考依据),"
|
|
||||||
+ "并给出最终选择,输出格式为json,key为’分析过程‘, ’选择工具‘", queryText);
|
|
||||||
|
|
||||||
return String.format("工具选择如下:\n\n%s\n\n【任务说明】\n%s", functionList, instruction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin.function;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginParseConfig;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
public class FunctionReq {
|
|
||||||
|
|
||||||
private String queryText;
|
|
||||||
|
|
||||||
private List<PluginParseConfig> pluginConfigs;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin.function;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class FunctionResp {
|
|
||||||
|
|
||||||
private String toolSelection;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin.function;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class Parameters {
|
|
||||||
|
|
||||||
//default: object
|
|
||||||
private String type = "object";
|
|
||||||
|
|
||||||
private Map<String, FunctionFiled> properties;
|
|
||||||
|
|
||||||
private List<String> required;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.sql.llm;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
|
||||||
import com.tencent.supersonic.chat.core.query.SemanticQuery;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class HeuristicViewResolver implements ViewResolver {
|
|
||||||
|
|
||||||
protected static Long selectViewBySchemaElementMatchScore(Map<Long, SemanticQuery> viewQueryModes,
|
|
||||||
SchemaMapInfo schemaMap) {
|
|
||||||
//view count priority
|
|
||||||
Long viewIdByViewCount = getViewIdByMatchViewScore(schemaMap);
|
|
||||||
if (Objects.nonNull(viewIdByViewCount)) {
|
|
||||||
log.info("selectView by view count:{}", viewIdByViewCount);
|
|
||||||
return viewIdByViewCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<Long, ViewMatchResult> viewTypeMap = getViewTypeMap(schemaMap);
|
|
||||||
if (viewTypeMap.size() == 1) {
|
|
||||||
Long viewSelect = new ArrayList<>(viewTypeMap.entrySet()).get(0).getKey();
|
|
||||||
if (viewQueryModes.containsKey(viewSelect)) {
|
|
||||||
log.info("selectView with only one View [{}]", viewSelect);
|
|
||||||
return viewSelect;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Map.Entry<Long, ViewMatchResult> maxView = viewTypeMap.entrySet().stream()
|
|
||||||
.filter(entry -> viewQueryModes.containsKey(entry.getKey()))
|
|
||||||
.sorted((o1, o2) -> {
|
|
||||||
int difference = o2.getValue().getCount() - o1.getValue().getCount();
|
|
||||||
if (difference == 0) {
|
|
||||||
return (int) ((o2.getValue().getMaxSimilarity()
|
|
||||||
- o1.getValue().getMaxSimilarity()) * 100);
|
|
||||||
}
|
|
||||||
return difference;
|
|
||||||
}).findFirst().orElse(null);
|
|
||||||
if (maxView != null) {
|
|
||||||
log.info("selectView with multiple Views [{}]", maxView.getKey());
|
|
||||||
return maxView.getKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Long getViewIdByMatchViewScore(SchemaMapInfo schemaMap) {
|
|
||||||
Map<Long, List<SchemaElementMatch>> viewElementMatches = schemaMap.getViewElementMatches();
|
|
||||||
// calculate view match score, matched element gets 1.0 point, and inherit element gets 0.5 point
|
|
||||||
Map<Long, Double> viewIdToViewScore = new HashMap<>();
|
|
||||||
if (Objects.nonNull(viewElementMatches)) {
|
|
||||||
for (Entry<Long, List<SchemaElementMatch>> viewElementMatch : viewElementMatches.entrySet()) {
|
|
||||||
Long viewId = viewElementMatch.getKey();
|
|
||||||
List<Double> viewMatchesScore = viewElementMatch.getValue().stream()
|
|
||||||
.filter(elementMatch -> elementMatch.getSimilarity() >= 1)
|
|
||||||
.filter(elementMatch -> SchemaElementType.VIEW.equals(elementMatch.getElement().getType()))
|
|
||||||
.map(elementMatch -> elementMatch.isInherited() ? 0.5 : 1.0).collect(Collectors.toList());
|
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(viewMatchesScore)) {
|
|
||||||
// get sum of view match score
|
|
||||||
double score = viewMatchesScore.stream().mapToDouble(Double::doubleValue).sum();
|
|
||||||
viewIdToViewScore.put(viewId, score);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Entry<Long, Double> maxViewScore = viewIdToViewScore.entrySet().stream()
|
|
||||||
.max(Comparator.comparingDouble(Entry::getValue)).orElse(null);
|
|
||||||
log.info("maxViewCount:{},viewIdToViewCount:{}", maxViewScore, viewIdToViewScore);
|
|
||||||
if (Objects.nonNull(maxViewScore)) {
|
|
||||||
return maxViewScore.getKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<Long, ViewMatchResult> getViewTypeMap(SchemaMapInfo schemaMap) {
|
|
||||||
Map<Long, ViewMatchResult> viewCount = new HashMap<>();
|
|
||||||
for (Map.Entry<Long, List<SchemaElementMatch>> entry : schemaMap.getViewElementMatches().entrySet()) {
|
|
||||||
List<SchemaElementMatch> schemaElementMatches = schemaMap.getMatchedElements(entry.getKey());
|
|
||||||
if (schemaElementMatches != null && schemaElementMatches.size() > 0) {
|
|
||||||
if (!viewCount.containsKey(entry.getKey())) {
|
|
||||||
viewCount.put(entry.getKey(), new ViewMatchResult());
|
|
||||||
}
|
|
||||||
ViewMatchResult viewMatchResult = viewCount.get(entry.getKey());
|
|
||||||
Set<SchemaElementType> schemaElementTypes = new HashSet<>();
|
|
||||||
schemaElementMatches.stream()
|
|
||||||
.forEach(schemaElementMatch -> schemaElementTypes.add(
|
|
||||||
schemaElementMatch.getElement().getType()));
|
|
||||||
SchemaElementMatch schemaElementMatchMax = schemaElementMatches.stream()
|
|
||||||
.sorted((o1, o2) ->
|
|
||||||
((int) ((o2.getSimilarity() - o1.getSimilarity()) * 100))
|
|
||||||
).findFirst().orElse(null);
|
|
||||||
if (schemaElementMatchMax != null) {
|
|
||||||
viewMatchResult.setMaxSimilarity(schemaElementMatchMax.getSimilarity());
|
|
||||||
}
|
|
||||||
viewMatchResult.setCount(schemaElementTypes.size());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return viewCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long resolve(QueryContext queryContext, Set<Long> agentViewIds) {
|
|
||||||
SchemaMapInfo mapInfo = queryContext.getMapInfo();
|
|
||||||
Set<Long> matchedViews = mapInfo.getMatchedViewInfos();
|
|
||||||
Long viewId = queryContext.getViewId();
|
|
||||||
if (Objects.nonNull(viewId) && viewId > 0) {
|
|
||||||
if (CollectionUtils.isEmpty(agentViewIds) || agentViewIds.contains(viewId)) {
|
|
||||||
return viewId;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isNotEmpty(agentViewIds)) {
|
|
||||||
matchedViews.retainAll(agentViewIds);
|
|
||||||
}
|
|
||||||
Map<Long, SemanticQuery> viewQueryModes = new HashMap<>();
|
|
||||||
for (Long viewIds : matchedViews) {
|
|
||||||
viewQueryModes.put(viewIds, null);
|
|
||||||
}
|
|
||||||
if (viewQueryModes.size() == 1) {
|
|
||||||
return viewQueryModes.keySet().stream().findFirst().get();
|
|
||||||
}
|
|
||||||
return selectViewBySchemaElementMatchScore(viewQueryModes, mapInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.sql.llm;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.agent.NL2SQLTool;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.QueryReq;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.s2sql.LLMReq;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.s2sql.LLMReq.ElementValue;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.s2sql.LLMResp;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class ParseResult {
|
|
||||||
|
|
||||||
private Long viewId;
|
|
||||||
|
|
||||||
private LLMReq llmReq;
|
|
||||||
|
|
||||||
private LLMResp llmResp;
|
|
||||||
|
|
||||||
private QueryReq request;
|
|
||||||
|
|
||||||
private NL2SQLTool commonAgentTool;
|
|
||||||
|
|
||||||
private List<ElementValue> linkingValues;
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.sql.llm;
|
|
||||||
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.s2sql.LLMReq;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.s2sql.LLMResp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sql Generation interface, generating SQL using a large model.
|
|
||||||
*/
|
|
||||||
public interface SqlGeneration {
|
|
||||||
|
|
||||||
/***
|
|
||||||
* generate llmResp (sql, schemaLink, prompt, etc.) through LLMReq.
|
|
||||||
* @param llmReq
|
|
||||||
* @param viewId
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
LLMResp generation(LLMReq llmReq, Long viewId);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.sql.llm;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class ViewMatchResult {
|
|
||||||
private Integer count = 0;
|
|
||||||
private double maxSimilarity;
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.sql.llm;
|
|
||||||
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public interface ViewResolver {
|
|
||||||
|
|
||||||
Long resolve(QueryContext queryContext, Set<Long> restrictiveModels);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.sql.rule;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.tencent.supersonic.chat.core.agent.Agent;
|
|
||||||
import com.tencent.supersonic.chat.core.agent.AgentToolType;
|
|
||||||
import com.tencent.supersonic.chat.core.agent.RuleParserTool;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.SemanticParser;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.ChatContext;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
|
||||||
import com.tencent.supersonic.chat.core.query.QueryManager;
|
|
||||||
import com.tencent.supersonic.chat.core.query.SemanticQuery;
|
|
||||||
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class AgentCheckParser implements SemanticParser {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void parse(QueryContext queryContext, ChatContext chatContext) {
|
|
||||||
List<SemanticQuery> queries = queryContext.getCandidateQueries();
|
|
||||||
agentCanSupport(queryContext, queries);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void agentCanSupport(QueryContext queryContext, List<SemanticQuery> queries) {
|
|
||||||
Agent agent = queryContext.getAgent();
|
|
||||||
if (agent == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<RuleParserTool> queryTools = getRuleTools(agent);
|
|
||||||
if (CollectionUtils.isEmpty(queryTools)) {
|
|
||||||
queries.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
log.info("queries resolved:{} {}", agent.getName(),
|
|
||||||
queries.stream().map(SemanticQuery::getQueryMode).collect(Collectors.toList()));
|
|
||||||
queries.removeIf(query -> {
|
|
||||||
for (RuleParserTool tool : queryTools) {
|
|
||||||
if (CollectionUtils.isNotEmpty(tool.getQueryModes())
|
|
||||||
&& !tool.getQueryModes().contains(query.getQueryMode())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isNotEmpty(tool.getQueryTypes())) {
|
|
||||||
if (QueryManager.isTagQuery(query.getQueryMode())) {
|
|
||||||
return !tool.getQueryTypes().contains(QueryType.TAG.name());
|
|
||||||
}
|
|
||||||
if (QueryManager.isMetricQuery(query.getQueryMode())) {
|
|
||||||
return !tool.getQueryTypes().contains(QueryType.METRIC.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isEmpty(tool.getViewIds())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (tool.isContainsAllModel()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !tool.getViewIds().contains(query.getParseInfo().getViewId());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
log.info("rule queries witch can be supported by agent :{} {}", agent.getName(),
|
|
||||||
queries.stream().map(SemanticQuery::getQueryMode).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<RuleParserTool> getRuleTools(Agent agent) {
|
|
||||||
if (agent == null) {
|
|
||||||
return Lists.newArrayList();
|
|
||||||
}
|
|
||||||
List<String> tools = agent.getTools(AgentToolType.NL2SQL_RULE);
|
|
||||||
if (CollectionUtils.isEmpty(tools)) {
|
|
||||||
return Lists.newArrayList();
|
|
||||||
}
|
|
||||||
return tools.stream().map(tool -> JSONObject.parseObject(tool, RuleParserTool.class))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.llm;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.query.BaseSemanticQuery;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public abstract class LLMSemanticQuery extends BaseSemanticQuery {
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.llm.analytics;
|
|
||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class LLMAnswerReq {
|
|
||||||
|
|
||||||
private String queryText;
|
|
||||||
|
|
||||||
private String pluginOutput;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.llm.analytics;
|
|
||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class LLMAnswerResp {
|
|
||||||
private String assistantMessage;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.llm.analytics;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticSchema;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryState;
|
|
||||||
import com.tencent.supersonic.chat.core.config.OptimizationConfig;
|
|
||||||
import com.tencent.supersonic.chat.core.query.semantic.SemanticInterpreter;
|
|
||||||
import com.tencent.supersonic.chat.core.query.QueryManager;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.LLMSemanticQuery;
|
|
||||||
import com.tencent.supersonic.chat.core.utils.ComponentFactory;
|
|
||||||
import com.tencent.supersonic.chat.core.utils.QueryReqBuilder;
|
|
||||||
import com.tencent.supersonic.common.pojo.Aggregator;
|
|
||||||
import com.tencent.supersonic.common.pojo.QueryColumn;
|
|
||||||
import com.tencent.supersonic.common.pojo.enums.AggOperatorEnum;
|
|
||||||
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QueryStructReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.SemanticQueryResp;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.calcite.sql.parser.SqlParseException;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class MetricAnalyzeQuery extends LLMSemanticQuery {
|
|
||||||
|
|
||||||
|
|
||||||
public static final String QUERY_MODE = "METRIC_INTERPRET";
|
|
||||||
|
|
||||||
public MetricAnalyzeQuery() {
|
|
||||||
QueryManager.register(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getQueryMode() {
|
|
||||||
return QUERY_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public QueryResult execute(User user) throws SqlParseException {
|
|
||||||
QueryStructReq queryStructReq = convertQueryStruct();
|
|
||||||
SemanticInterpreter semanticInterpreter = ComponentFactory.getSemanticLayer();
|
|
||||||
|
|
||||||
OptimizationConfig optimizationConfig = ContextUtils.getBean(OptimizationConfig.class);
|
|
||||||
if (optimizationConfig.isUseS2SqlSwitch()) {
|
|
||||||
queryStructReq.setS2SQL(parseInfo.getSqlInfo().getS2SQL());
|
|
||||||
queryStructReq.setS2SQL(parseInfo.getSqlInfo().getQuerySQL());
|
|
||||||
}
|
|
||||||
|
|
||||||
SemanticQueryResp semanticQueryResp = semanticInterpreter.queryByStruct(queryStructReq, user);
|
|
||||||
String text = generateTableText(semanticQueryResp);
|
|
||||||
Map<String, Object> properties = parseInfo.getProperties();
|
|
||||||
Map<String, String> replacedMap = new HashMap<>();
|
|
||||||
String textReplaced = replaceText((String) properties.get("queryText"),
|
|
||||||
parseInfo.getElementMatches(), replacedMap);
|
|
||||||
String answer = replaceAnswer(fetchInterpret(textReplaced, text), replacedMap);
|
|
||||||
QueryResult queryResult = new QueryResult();
|
|
||||||
List<QueryColumn> queryColumns = Lists.newArrayList(new QueryColumn("结果", "string", "answer"));
|
|
||||||
Map<String, Object> result = new HashMap<>();
|
|
||||||
result.put("answer", answer);
|
|
||||||
List<Map<String, Object>> resultList = Lists.newArrayList();
|
|
||||||
resultList.add(result);
|
|
||||||
queryResult.setQueryResults(resultList);
|
|
||||||
queryResult.setQueryColumns(queryColumns);
|
|
||||||
queryResult.setQueryMode(getQueryMode());
|
|
||||||
queryResult.setQueryState(QueryState.SUCCESS);
|
|
||||||
return queryResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initS2Sql(SemanticSchema semanticSchema, User user) {
|
|
||||||
initS2SqlByStruct(semanticSchema);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected QueryStructReq convertQueryStruct() {
|
|
||||||
QueryStructReq queryStructReq = QueryReqBuilder.buildStructReq(parseInfo);
|
|
||||||
fillAggregator(queryStructReq, parseInfo.getMetrics());
|
|
||||||
queryStructReq.setQueryType(QueryType.TAG);
|
|
||||||
return queryStructReq;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String replaceText(String text, List<SchemaElementMatch> schemaElementMatches,
|
|
||||||
Map<String, String> replacedMap) {
|
|
||||||
if (CollectionUtils.isEmpty(schemaElementMatches)) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
List<SchemaElementMatch> valueSchemaElementMatches = schemaElementMatches.stream()
|
|
||||||
.filter(schemaElementMatch ->
|
|
||||||
SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType())
|
|
||||||
|| SchemaElementType.ID.equals(schemaElementMatch.getElement().getType()))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
for (SchemaElementMatch schemaElementMatch : valueSchemaElementMatches) {
|
|
||||||
String detectWord = schemaElementMatch.getDetectWord();
|
|
||||||
if (StringUtils.isBlank(detectWord)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
text = text.replace(detectWord, "xxx");
|
|
||||||
replacedMap.put("xxx", detectWord);
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fillAggregator(QueryStructReq queryStructReq, Set<SchemaElement> schemaElements) {
|
|
||||||
queryStructReq.getAggregators().clear();
|
|
||||||
for (SchemaElement schemaElement : schemaElements) {
|
|
||||||
Aggregator aggregator = new Aggregator();
|
|
||||||
aggregator.setColumn(schemaElement.getBizName());
|
|
||||||
aggregator.setFunc(AggOperatorEnum.SUM);
|
|
||||||
aggregator.setNameCh(schemaElement.getName());
|
|
||||||
queryStructReq.getAggregators().add(aggregator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String replaceAnswer(String text, Map<String, String> replacedMap) {
|
|
||||||
for (String key : replacedMap.keySet()) {
|
|
||||||
text = text.replaceAll(key, replacedMap.get(key));
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String generateTableText(SemanticQueryResp result) {
|
|
||||||
StringBuilder tableBuilder = new StringBuilder();
|
|
||||||
for (QueryColumn column : result.getColumns()) {
|
|
||||||
tableBuilder.append(column.getName()).append("\t");
|
|
||||||
}
|
|
||||||
tableBuilder.append("\n");
|
|
||||||
for (Map<String, Object> row : result.getResultList()) {
|
|
||||||
for (QueryColumn column : result.getColumns()) {
|
|
||||||
tableBuilder.append(row.get(column.getNameEn())).append("\t");
|
|
||||||
}
|
|
||||||
tableBuilder.append("\n");
|
|
||||||
}
|
|
||||||
return tableBuilder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String fetchInterpret(String queryText, String dataText) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.llm.s2sql;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticSchema;
|
|
||||||
import com.tencent.supersonic.chat.core.query.semantic.SemanticInterpreter;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryState;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.SqlInfo;
|
|
||||||
import com.tencent.supersonic.chat.core.utils.ComponentFactory;
|
|
||||||
import com.tencent.supersonic.chat.core.utils.QueryReqBuilder;
|
|
||||||
import com.tencent.supersonic.chat.core.query.QueryManager;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.LLMSemanticQuery;
|
|
||||||
import com.tencent.supersonic.common.pojo.QueryColumn;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.SemanticQueryResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QuerySqlReq;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class LLMSqlQuery extends LLMSemanticQuery {
|
|
||||||
|
|
||||||
public static final String QUERY_MODE = "LLM_S2SQL";
|
|
||||||
protected SemanticInterpreter semanticInterpreter = ComponentFactory.getSemanticLayer();
|
|
||||||
|
|
||||||
public LLMSqlQuery() {
|
|
||||||
QueryManager.register(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getQueryMode() {
|
|
||||||
return QUERY_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public QueryResult execute(User user) {
|
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
|
||||||
String querySql = parseInfo.getSqlInfo().getCorrectS2SQL();
|
|
||||||
QuerySqlReq querySQLReq = QueryReqBuilder.buildS2SQLReq(querySql, parseInfo.getViewId());
|
|
||||||
SemanticQueryResp queryResp = semanticInterpreter.queryByS2SQL(querySQLReq, user);
|
|
||||||
|
|
||||||
log.info("queryByS2SQL cost:{},querySql:{}", System.currentTimeMillis() - startTime, querySql);
|
|
||||||
|
|
||||||
QueryResult queryResult = new QueryResult();
|
|
||||||
if (Objects.nonNull(queryResp)) {
|
|
||||||
queryResult.setQueryAuthorization(queryResp.getQueryAuthorization());
|
|
||||||
}
|
|
||||||
String resultQql = queryResp == null ? null : queryResp.getSql();
|
|
||||||
List<Map<String, Object>> resultList = queryResp == null ? new ArrayList<>() : queryResp.getResultList();
|
|
||||||
List<QueryColumn> columns = queryResp == null ? new ArrayList<>() : queryResp.getColumns();
|
|
||||||
queryResult.setQuerySql(resultQql);
|
|
||||||
queryResult.setQueryResults(resultList);
|
|
||||||
queryResult.setQueryColumns(columns);
|
|
||||||
queryResult.setQueryMode(QUERY_MODE);
|
|
||||||
queryResult.setQueryState(QueryState.SUCCESS);
|
|
||||||
|
|
||||||
parseInfo.setProperties(null);
|
|
||||||
return queryResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initS2Sql(SemanticSchema semanticSchema, User user) {
|
|
||||||
SqlInfo sqlInfo = parseInfo.getSqlInfo();
|
|
||||||
sqlInfo.setCorrectS2SQL(sqlInfo.getS2SQL());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.plugin.webservice;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.query.plugin.WebBase;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class WebServiceResp {
|
|
||||||
|
|
||||||
private WebBase webBase;
|
|
||||||
|
|
||||||
private Object result;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.rule.metric;
|
|
||||||
|
|
||||||
import static com.tencent.supersonic.chat.core.query.rule.QueryMatchOption.OptionType.OPTIONAL;
|
|
||||||
import static com.tencent.supersonic.chat.core.query.rule.QueryMatchOption.RequireNumberType.AT_MOST;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
@Component
|
|
||||||
public class MetricModelQuery extends MetricSemanticQuery {
|
|
||||||
|
|
||||||
public static final String QUERY_MODE = "METRIC_MODEL";
|
|
||||||
|
|
||||||
public MetricModelQuery() {
|
|
||||||
super();
|
|
||||||
queryMatcher.addOption(SchemaElementType.VIEW, OPTIONAL, AT_MOST, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getQueryMode() {
|
|
||||||
return QUERY_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public QueryResult execute(User user) {
|
|
||||||
QueryResult queryResult = super.execute(user);
|
|
||||||
return queryResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.rule.tag;
|
|
||||||
|
|
||||||
import static com.tencent.supersonic.headless.api.pojo.SchemaElementType.DIMENSION;
|
|
||||||
import static com.tencent.supersonic.headless.api.pojo.SchemaElementType.ID;
|
|
||||||
import static com.tencent.supersonic.chat.core.query.rule.QueryMatchOption.RequireNumberType.AT_LEAST;
|
|
||||||
import static com.tencent.supersonic.chat.core.query.rule.QueryMatchOption.OptionType.REQUIRED;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class TagDetailQuery extends TagSemanticQuery {
|
|
||||||
|
|
||||||
public static final String QUERY_MODE = "TAG_DETAIL";
|
|
||||||
|
|
||||||
public TagDetailQuery() {
|
|
||||||
super();
|
|
||||||
queryMatcher.addOption(DIMENSION, REQUIRED, AT_LEAST, 1)
|
|
||||||
.addOption(ID, REQUIRED, AT_LEAST, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getQueryMode() {
|
|
||||||
return QUERY_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.semantic;
|
|
||||||
|
|
||||||
import com.google.common.cache.Cache;
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.ViewSchema;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ViewSchemaResp;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public abstract class BaseSemanticInterpreter implements SemanticInterpreter {
|
|
||||||
|
|
||||||
protected final Cache<String, List<ViewSchemaResp>> viewSchemaCache =
|
|
||||||
CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build();
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
public List<ViewSchemaResp> fetchViewSchema(List<Long> ids, Boolean cacheEnable) {
|
|
||||||
if (cacheEnable) {
|
|
||||||
return viewSchemaCache.get(String.valueOf(ids), () -> {
|
|
||||||
List<ViewSchemaResp> data = doFetchViewSchema(ids);
|
|
||||||
viewSchemaCache.put(String.valueOf(ids), data);
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return doFetchViewSchema(ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ViewSchema getViewSchema(Long viewId, Boolean cacheEnable) {
|
|
||||||
List<Long> ids = new ArrayList<>();
|
|
||||||
ids.add(viewId);
|
|
||||||
List<ViewSchemaResp> viewSchemaResps = fetchViewSchema(ids, cacheEnable);
|
|
||||||
if (!CollectionUtils.isEmpty(viewSchemaResps)) {
|
|
||||||
Optional<ViewSchemaResp> viewSchemaResp = viewSchemaResps.stream()
|
|
||||||
.filter(d -> d.getId().equals(viewId)).findFirst();
|
|
||||||
if (viewSchemaResp.isPresent()) {
|
|
||||||
ViewSchemaResp viewSchema = viewSchemaResp.get();
|
|
||||||
return ViewSchemaBuilder.build(viewSchema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ViewSchema> getViewSchema() {
|
|
||||||
return getViewSchema(new ArrayList<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ViewSchema> getViewSchema(List<Long> ids) {
|
|
||||||
List<ViewSchema> domainSchemaList = new ArrayList<>();
|
|
||||||
|
|
||||||
for (ViewSchemaResp resp : fetchViewSchema(ids, true)) {
|
|
||||||
domainSchemaList.add(ViewSchemaBuilder.build(resp));
|
|
||||||
}
|
|
||||||
|
|
||||||
return domainSchemaList;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract List<ViewSchemaResp> doFetchViewSchema(List<Long> ids);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.semantic;
|
|
||||||
|
|
||||||
import com.github.pagehelper.PageInfo;
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
|
||||||
import com.tencent.supersonic.common.util.JsonUtil;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.ExplainSqlReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.PageDimensionReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.PageMetricReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QueryMultiStructReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QuerySqlReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QueryStructReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.ViewFilterReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.DimensionResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.DomainResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ExplainResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ItemResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.MetricResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.SemanticQueryResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ViewResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ViewSchemaResp;
|
|
||||||
import com.tencent.supersonic.headless.server.service.DimensionService;
|
|
||||||
import com.tencent.supersonic.headless.server.service.MetricService;
|
|
||||||
import com.tencent.supersonic.headless.server.service.QueryService;
|
|
||||||
import com.tencent.supersonic.headless.server.service.SchemaService;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class LocalSemanticInterpreter extends BaseSemanticInterpreter {
|
|
||||||
|
|
||||||
private SchemaService schemaService;
|
|
||||||
private DimensionService dimensionService;
|
|
||||||
private MetricService metricService;
|
|
||||||
private QueryService queryService;
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Override
|
|
||||||
public SemanticQueryResp queryByStruct(QueryStructReq queryStructReq, User user) {
|
|
||||||
if (StringUtils.isNotBlank(queryStructReq.getCorrectS2SQL())) {
|
|
||||||
QuerySqlReq querySqlReq = new QuerySqlReq();
|
|
||||||
querySqlReq.setSql(queryStructReq.getCorrectS2SQL());
|
|
||||||
querySqlReq.setViewId(queryStructReq.getViewId());
|
|
||||||
querySqlReq.setParams(new ArrayList<>());
|
|
||||||
return queryByS2SQL(querySqlReq, user);
|
|
||||||
}
|
|
||||||
queryService = ContextUtils.getBean(QueryService.class);
|
|
||||||
return queryService.queryByReq(queryStructReq, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public SemanticQueryResp queryByMultiStruct(QueryMultiStructReq queryMultiStructReq, User user) {
|
|
||||||
queryService = ContextUtils.getBean(QueryService.class);
|
|
||||||
return queryService.queryByReq(queryMultiStructReq, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public SemanticQueryResp queryByS2SQL(QuerySqlReq querySqlReq, User user) {
|
|
||||||
queryService = ContextUtils.getBean(QueryService.class);
|
|
||||||
SemanticQueryResp object = queryService.queryByReq(querySqlReq, user);
|
|
||||||
return JsonUtil.toObject(JsonUtil.toString(object), SemanticQueryResp.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ViewSchemaResp> doFetchViewSchema(List<Long> ids) {
|
|
||||||
ViewFilterReq filter = new ViewFilterReq();
|
|
||||||
filter.setViewIds(ids);
|
|
||||||
schemaService = ContextUtils.getBean(SchemaService.class);
|
|
||||||
return schemaService.fetchViewSchema(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DomainResp> getDomainList(User user) {
|
|
||||||
schemaService = ContextUtils.getBean(SchemaService.class);
|
|
||||||
return schemaService.getDomainList(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ViewResp> getViewList(Long domainId) {
|
|
||||||
schemaService = ContextUtils.getBean(SchemaService.class);
|
|
||||||
return schemaService.getViewList(domainId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> ExplainResp explain(ExplainSqlReq<T> explainSqlReq, User user) throws Exception {
|
|
||||||
queryService = ContextUtils.getBean(QueryService.class);
|
|
||||||
return queryService.explain(explainSqlReq, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageInfo<DimensionResp> getDimensionPage(PageDimensionReq pageDimensionCmd) {
|
|
||||||
dimensionService = ContextUtils.getBean(DimensionService.class);
|
|
||||||
return dimensionService.queryDimension(pageDimensionCmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageInfo<MetricResp> getMetricPage(PageMetricReq pageMetricReq, User user) {
|
|
||||||
metricService = ContextUtils.getBean(MetricService.class);
|
|
||||||
return metricService.queryMetric(pageMetricReq, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ItemResp> getDomainViewTree() {
|
|
||||||
return schemaService.getDomainViewTree();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,267 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.semantic;
|
|
||||||
|
|
||||||
import com.github.pagehelper.PageInfo;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
|
||||||
import com.tencent.supersonic.chat.core.config.DefaultSemanticConfig;
|
|
||||||
import com.tencent.supersonic.common.pojo.ResultData;
|
|
||||||
import com.tencent.supersonic.common.pojo.enums.ReturnCode;
|
|
||||||
import com.tencent.supersonic.common.pojo.exception.CommonException;
|
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
|
||||||
import com.tencent.supersonic.common.util.JsonUtil;
|
|
||||||
import com.tencent.supersonic.common.util.S2ThreadContext;
|
|
||||||
import com.tencent.supersonic.common.util.ThreadContext;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.ExplainSqlReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.PageDimensionReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.PageMetricReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QueryMultiStructReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QuerySqlReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QueryStructReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.DimensionResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.DomainResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ExplainResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ItemResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.MetricResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.SemanticQueryResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ViewResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ViewSchemaResp;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.logging.log4j.util.Strings;
|
|
||||||
import org.springframework.beans.BeanUtils;
|
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
|
||||||
import org.springframework.http.HttpEntity;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.LIST_LOWER;
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.PAGESIZE_LOWER;
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.TOTAL_LOWER;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class RemoteSemanticInterpreter extends BaseSemanticInterpreter {
|
|
||||||
|
|
||||||
private S2ThreadContext s2ThreadContext;
|
|
||||||
|
|
||||||
private AuthenticationConfig authenticationConfig;
|
|
||||||
|
|
||||||
private ParameterizedTypeReference<ResultData<SemanticQueryResp>> structTypeRef =
|
|
||||||
new ParameterizedTypeReference<ResultData<SemanticQueryResp>>() {
|
|
||||||
};
|
|
||||||
|
|
||||||
private ParameterizedTypeReference<ResultData<ExplainResp>> explainTypeRef =
|
|
||||||
new ParameterizedTypeReference<ResultData<ExplainResp>>() {
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SemanticQueryResp queryByStruct(QueryStructReq queryStructReq, User user) {
|
|
||||||
if (StringUtils.isNotBlank(queryStructReq.getCorrectS2SQL())) {
|
|
||||||
QuerySqlReq querySqlReq = new QuerySqlReq();
|
|
||||||
querySqlReq.setSql(queryStructReq.getCorrectS2SQL());
|
|
||||||
querySqlReq.setModelIds(queryStructReq.getModelIdSet());
|
|
||||||
querySqlReq.setParams(new ArrayList<>());
|
|
||||||
return queryByS2SQL(querySqlReq, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class);
|
|
||||||
return searchByRestTemplate(
|
|
||||||
defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getSearchByStructPath(),
|
|
||||||
new Gson().toJson(queryStructReq));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SemanticQueryResp queryByMultiStruct(QueryMultiStructReq queryMultiStructReq, User user) {
|
|
||||||
DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class);
|
|
||||||
return searchByRestTemplate(
|
|
||||||
defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getSearchByMultiStructPath(),
|
|
||||||
new Gson().toJson(queryMultiStructReq));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SemanticQueryResp queryByS2SQL(QuerySqlReq querySqlReq, User user) {
|
|
||||||
DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class);
|
|
||||||
return searchByRestTemplate(defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getSearchBySqlPath(),
|
|
||||||
new Gson().toJson(querySqlReq));
|
|
||||||
}
|
|
||||||
|
|
||||||
public SemanticQueryResp searchByRestTemplate(String url, String jsonReq) {
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
||||||
fillToken(headers);
|
|
||||||
URI requestUrl = UriComponentsBuilder.fromHttpUrl(url).build().encode().toUri();
|
|
||||||
HttpEntity<String> entity = new HttpEntity<>(jsonReq, headers);
|
|
||||||
log.info("url:{},searchByRestTemplate:{}", url, entity.getBody());
|
|
||||||
ResultData<SemanticQueryResp> responseBody;
|
|
||||||
try {
|
|
||||||
RestTemplate restTemplate = ContextUtils.getBean(RestTemplate.class);
|
|
||||||
|
|
||||||
ResponseEntity<ResultData<SemanticQueryResp>> responseEntity = restTemplate.exchange(
|
|
||||||
requestUrl, HttpMethod.POST, entity, structTypeRef);
|
|
||||||
responseBody = responseEntity.getBody();
|
|
||||||
log.info("ApiResponse<QueryResultWithColumns> responseBody:{}", responseBody);
|
|
||||||
SemanticQueryResp schemaResp = new SemanticQueryResp();
|
|
||||||
if (ReturnCode.SUCCESS.getCode() == responseBody.getCode()) {
|
|
||||||
SemanticQueryResp data = responseBody.getData();
|
|
||||||
schemaResp.setColumns(data.getColumns());
|
|
||||||
schemaResp.setResultList(data.getResultList());
|
|
||||||
schemaResp.setSql(data.getSql());
|
|
||||||
schemaResp.setQueryAuthorization(data.getQueryAuthorization());
|
|
||||||
return schemaResp;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("search headless interface error,url:" + url, e);
|
|
||||||
}
|
|
||||||
throw new CommonException(responseBody.getCode(), responseBody.getMsg());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DomainResp> getDomainList(User user) {
|
|
||||||
DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class);
|
|
||||||
Object domainDescListObject = fetchHttpResult(
|
|
||||||
defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchDomainListPath(),
|
|
||||||
null, HttpMethod.GET);
|
|
||||||
return JsonUtil.toList(JsonUtil.toString(domainDescListObject), DomainResp.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> ExplainResp explain(ExplainSqlReq<T> explainResp, User user) throws Exception {
|
|
||||||
DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class);
|
|
||||||
String semanticUrl = defaultSemanticConfig.getSemanticUrl();
|
|
||||||
String explainPath = defaultSemanticConfig.getExplainPath();
|
|
||||||
URL url = new URL(new URL(semanticUrl), explainPath);
|
|
||||||
return explain(url.toString(), JsonUtil.toString(explainResp));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExplainResp explain(String url, String jsonReq) {
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
||||||
fillToken(headers);
|
|
||||||
URI requestUrl = UriComponentsBuilder.fromHttpUrl(url).build().encode().toUri();
|
|
||||||
HttpEntity<String> entity = new HttpEntity<>(jsonReq, headers);
|
|
||||||
log.info("url:{},explain:{}", url, entity.getBody());
|
|
||||||
ResultData<ExplainResp> responseBody;
|
|
||||||
try {
|
|
||||||
RestTemplate restTemplate = ContextUtils.getBean(RestTemplate.class);
|
|
||||||
|
|
||||||
ResponseEntity<ResultData<ExplainResp>> responseEntity = restTemplate.exchange(
|
|
||||||
requestUrl, HttpMethod.POST, entity, explainTypeRef);
|
|
||||||
log.info("ApiResponse<ExplainResp> responseBody:{}", responseEntity);
|
|
||||||
responseBody = responseEntity.getBody();
|
|
||||||
if (Objects.nonNull(responseBody.getData())) {
|
|
||||||
return responseBody.getData();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("explain interface error,url:" + url, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object fetchHttpResult(String url, String bodyJson, HttpMethod httpMethod) {
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
||||||
fillToken(headers);
|
|
||||||
URI requestUrl = UriComponentsBuilder.fromHttpUrl(url).build().encode().toUri();
|
|
||||||
ParameterizedTypeReference<ResultData<Object>> responseTypeRef =
|
|
||||||
new ParameterizedTypeReference<ResultData<Object>>() {
|
|
||||||
};
|
|
||||||
HttpEntity<String> entity = new HttpEntity<>(JsonUtil.toString(bodyJson), headers);
|
|
||||||
try {
|
|
||||||
RestTemplate restTemplate = ContextUtils.getBean(RestTemplate.class);
|
|
||||||
ResponseEntity<ResultData<Object>> responseEntity = restTemplate.exchange(requestUrl,
|
|
||||||
httpMethod, entity, responseTypeRef);
|
|
||||||
ResultData<Object> responseBody = responseEntity.getBody();
|
|
||||||
log.debug("ApiResponse<fetchModelSchema> responseBody:{}", responseBody);
|
|
||||||
if (ReturnCode.SUCCESS.getCode() == responseBody.getCode()) {
|
|
||||||
Object data = responseBody.getData();
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("fetchModelSchema interface error", e);
|
|
||||||
}
|
|
||||||
throw new RuntimeException("fetchModelSchema interface error");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fillToken(HttpHeaders headers) {
|
|
||||||
s2ThreadContext = ContextUtils.getBean(S2ThreadContext.class);
|
|
||||||
authenticationConfig = ContextUtils.getBean(AuthenticationConfig.class);
|
|
||||||
ThreadContext threadContext = s2ThreadContext.get();
|
|
||||||
if (Objects.nonNull(threadContext) && Strings.isNotEmpty(threadContext.getToken())) {
|
|
||||||
if (Objects.nonNull(authenticationConfig) && Strings.isNotEmpty(
|
|
||||||
authenticationConfig.getTokenHttpHeaderKey())) {
|
|
||||||
headers.set(authenticationConfig.getTokenHttpHeaderKey(), threadContext.getToken());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.debug("threadContext is null:{}", Objects.isNull(threadContext));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageInfo<MetricResp> getMetricPage(PageMetricReq pageMetricCmd, User user) {
|
|
||||||
String body = JsonUtil.toString(pageMetricCmd);
|
|
||||||
DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class);
|
|
||||||
log.info("url:{}", defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchMetricPagePath());
|
|
||||||
Object dimensionListObject = fetchHttpResult(
|
|
||||||
defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchMetricPagePath(),
|
|
||||||
body, HttpMethod.POST);
|
|
||||||
LinkedHashMap map = (LinkedHashMap) dimensionListObject;
|
|
||||||
PageInfo<Object> metricDescObjectPageInfo = generatePageInfo(map);
|
|
||||||
PageInfo<MetricResp> metricDescPageInfo = new PageInfo<>();
|
|
||||||
BeanUtils.copyProperties(metricDescObjectPageInfo, metricDescPageInfo);
|
|
||||||
metricDescPageInfo.setList(metricDescPageInfo.getList());
|
|
||||||
return metricDescPageInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageInfo<DimensionResp> getDimensionPage(PageDimensionReq pageDimensionCmd) {
|
|
||||||
String body = JsonUtil.toString(pageDimensionCmd);
|
|
||||||
DefaultSemanticConfig defaultSemanticConfig = ContextUtils.getBean(DefaultSemanticConfig.class);
|
|
||||||
Object dimensionListObject = fetchHttpResult(
|
|
||||||
defaultSemanticConfig.getSemanticUrl() + defaultSemanticConfig.getFetchDimensionPagePath(),
|
|
||||||
body, HttpMethod.POST);
|
|
||||||
LinkedHashMap map = (LinkedHashMap) dimensionListObject;
|
|
||||||
PageInfo<Object> dimensionDescObjectPageInfo = generatePageInfo(map);
|
|
||||||
PageInfo<DimensionResp> dimensionDescPageInfo = new PageInfo<>();
|
|
||||||
BeanUtils.copyProperties(dimensionDescObjectPageInfo, dimensionDescPageInfo);
|
|
||||||
dimensionDescPageInfo.setList(dimensionDescPageInfo.getList());
|
|
||||||
return dimensionDescPageInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
private PageInfo<Object> generatePageInfo(LinkedHashMap map) {
|
|
||||||
PageInfo<Object> pageInfo = new PageInfo<>();
|
|
||||||
pageInfo.setList((List<Object>) map.get(LIST_LOWER));
|
|
||||||
Integer total = (Integer) map.get(TOTAL_LOWER);
|
|
||||||
pageInfo.setTotal(total);
|
|
||||||
Integer pageSize = (Integer) map.get(PAGESIZE_LOWER);
|
|
||||||
pageInfo.setPageSize(pageSize);
|
|
||||||
pageInfo.setPages((int) Math.ceil((double) total / pageSize));
|
|
||||||
return pageInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<ViewSchemaResp> doFetchViewSchema(List<Long> ids) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ItemResp> getDomainViewTree() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ViewResp> getViewList(Long domainId) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.semantic;
|
|
||||||
|
|
||||||
import com.github.pagehelper.PageInfo;
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.ViewSchema;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.ExplainSqlReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.PageDimensionReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.PageMetricReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QueryMultiStructReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QuerySqlReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QueryStructReq;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.DimensionResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.DomainResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ExplainResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ItemResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.MetricResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.SemanticQueryResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ViewResp;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.ViewSchemaResp;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A semantic layer provides a simplified and consistent view of data from multiple sources.
|
|
||||||
* It abstracts away the complexity of the underlying data sources and provides a unified view
|
|
||||||
* of the data that is easier to understand and use.
|
|
||||||
* <p>
|
|
||||||
* The interface defines methods for getting metadata as well as querying data in the semantic layer.
|
|
||||||
* Implementations of this interface should provide concrete implementations that interact with the
|
|
||||||
* underlying data sources and return results in a consistent format. Or it can be implemented
|
|
||||||
* as proxy to a remote semantic service.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public interface SemanticInterpreter {
|
|
||||||
|
|
||||||
SemanticQueryResp queryByStruct(QueryStructReq queryStructReq, User user);
|
|
||||||
|
|
||||||
SemanticQueryResp queryByMultiStruct(QueryMultiStructReq queryMultiStructReq, User user);
|
|
||||||
|
|
||||||
SemanticQueryResp queryByS2SQL(QuerySqlReq querySQLReq, User user);
|
|
||||||
|
|
||||||
List<ViewSchema> getViewSchema();
|
|
||||||
|
|
||||||
List<ViewSchema> getViewSchema(List<Long> ids);
|
|
||||||
|
|
||||||
ViewSchema getViewSchema(Long model, Boolean cacheEnable);
|
|
||||||
|
|
||||||
PageInfo<DimensionResp> getDimensionPage(PageDimensionReq pageDimensionReq);
|
|
||||||
|
|
||||||
PageInfo<MetricResp> getMetricPage(PageMetricReq pageDimensionReq, User user);
|
|
||||||
|
|
||||||
List<DomainResp> getDomainList(User user);
|
|
||||||
|
|
||||||
<T> ExplainResp explain(ExplainSqlReq<T> explainSqlReq, User user) throws Exception;
|
|
||||||
|
|
||||||
List<ViewSchemaResp> fetchViewSchema(List<Long> ids, Boolean cacheEnable);
|
|
||||||
|
|
||||||
List<ViewResp> getViewList(Long domainId);
|
|
||||||
|
|
||||||
List<ItemResp> getDomainViewTree();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.core.utils;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.query.semantic.SemanticInterpreter;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.JavaLLMProxy;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.LLMProxy;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.sql.llm.ViewResolver;
|
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class ComponentFactory {
|
|
||||||
|
|
||||||
private static SemanticInterpreter semanticInterpreter;
|
|
||||||
private static LLMProxy llmProxy;
|
|
||||||
private static ViewResolver modelResolver;
|
|
||||||
|
|
||||||
public static SemanticInterpreter getSemanticLayer() {
|
|
||||||
if (Objects.isNull(semanticInterpreter)) {
|
|
||||||
semanticInterpreter = init(SemanticInterpreter.class);
|
|
||||||
}
|
|
||||||
return semanticInterpreter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LLMProxy getLLMProxy() {
|
|
||||||
//1.Preferentially retrieve from environment variables
|
|
||||||
String llmProxyEnv = System.getenv("llmProxy");
|
|
||||||
if (StringUtils.isNotBlank(llmProxyEnv)) {
|
|
||||||
Map<String, LLMProxy> implementations = ContextUtils.getBeansOfType(LLMProxy.class);
|
|
||||||
llmProxy = implementations.entrySet().stream()
|
|
||||||
.filter(entry -> entry.getKey().equalsIgnoreCase(llmProxyEnv))
|
|
||||||
.map(Map.Entry::getValue)
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
//2.default JavaLLMProxy
|
|
||||||
if (Objects.isNull(llmProxy)) {
|
|
||||||
llmProxy = ContextUtils.getBean(JavaLLMProxy.class);
|
|
||||||
}
|
|
||||||
log.info("llmProxy:{}", llmProxy);
|
|
||||||
return llmProxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ViewResolver getModelResolver() {
|
|
||||||
if (Objects.isNull(modelResolver)) {
|
|
||||||
modelResolver = init(ViewResolver.class);
|
|
||||||
}
|
|
||||||
return modelResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T> T init(Class<T> factoryType) {
|
|
||||||
return SpringFactoriesLoader.loadFactories(factoryType,
|
|
||||||
Thread.currentThread().getContextClassLoader()).get(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<modules>
|
<modules>
|
||||||
<module>api</module>
|
<module>api</module>
|
||||||
<module>core</module>
|
|
||||||
<module>server</module>
|
<module>server</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
|||||||
@@ -11,19 +11,10 @@
|
|||||||
|
|
||||||
<artifactId>chat-server</artifactId>
|
<artifactId>chat-server</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-context</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.tencent.supersonic</groupId>
|
|
||||||
<artifactId>common</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.tencent.supersonic</groupId>
|
<groupId>com.tencent.supersonic</groupId>
|
||||||
<artifactId>auth-api</artifactId>
|
<artifactId>auth-api</artifactId>
|
||||||
@@ -36,13 +27,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.tencent.supersonic</groupId>
|
<groupId>com.tencent.supersonic</groupId>
|
||||||
<artifactId>headless-core</artifactId>
|
<artifactId>headless-server</artifactId>
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.tencent.supersonic</groupId>
|
|
||||||
<artifactId>chat-core</artifactId>
|
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -51,12 +36,6 @@
|
|||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-inline</artifactId>
|
|
||||||
<version>${mockito-inline.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package com.tencent.supersonic.chat.core.agent;
|
package com.tencent.supersonic.chat.server.agent;
|
||||||
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import com.tencent.supersonic.common.pojo.RecordInfo;
|
import com.tencent.supersonic.common.pojo.RecordInfo;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
@@ -65,12 +66,29 @@ public class Agent extends RecordInfo {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Long> getViewIds(AgentToolType agentToolType) {
|
public boolean containsLLMParserTool() {
|
||||||
|
return !CollectionUtils.isEmpty(getParserTools(AgentToolType.NL2SQL_LLM));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsNL2SQLTool() {
|
||||||
|
return !CollectionUtils.isEmpty(getParserTools(AgentToolType.NL2SQL_LLM))
|
||||||
|
|| !CollectionUtils.isEmpty(getParserTools(AgentToolType.NL2SQL_RULE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Long> getDataSetIds() {
|
||||||
|
Set<Long> dataSetIds = getDataSetIds(null);
|
||||||
|
if (containsAllModel(dataSetIds)) {
|
||||||
|
return Sets.newHashSet();
|
||||||
|
}
|
||||||
|
return dataSetIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Long> getDataSetIds(AgentToolType agentToolType) {
|
||||||
List<NL2SQLTool> commonAgentTools = getParserTools(agentToolType);
|
List<NL2SQLTool> commonAgentTools = getParserTools(agentToolType);
|
||||||
if (CollectionUtils.isEmpty(commonAgentTools)) {
|
if (CollectionUtils.isEmpty(commonAgentTools)) {
|
||||||
return new HashSet<>();
|
return new HashSet<>();
|
||||||
}
|
}
|
||||||
return commonAgentTools.stream().map(NL2SQLTool::getViewIds)
|
return commonAgentTools.stream().map(NL2SQLTool::getDataSetIds)
|
||||||
.filter(modelIds -> !CollectionUtils.isEmpty(modelIds))
|
.filter(modelIds -> !CollectionUtils.isEmpty(modelIds))
|
||||||
.flatMap(Collection::stream)
|
.flatMap(Collection::stream)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.tencent.supersonic.chat.core.agent;
|
package com.tencent.supersonic.chat.server.agent;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.tencent.supersonic.chat.core.agent;
|
package com.tencent.supersonic.chat.server.agent;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.tencent.supersonic.chat.core.agent;
|
package com.tencent.supersonic.chat.server.agent;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.tencent.supersonic.chat.core.agent;
|
package com.tencent.supersonic.chat.server.agent;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.tencent.supersonic.chat.core.agent;
|
package com.tencent.supersonic.chat.server.agent;
|
||||||
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@@ -12,6 +12,6 @@ import java.util.List;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class NL2SQLTool extends AgentTool {
|
public class NL2SQLTool extends AgentTool {
|
||||||
|
|
||||||
protected List<Long> viewIds;
|
protected List<Long> dataSetIds;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.tencent.supersonic.chat.core.agent;
|
package com.tencent.supersonic.chat.server.agent;
|
||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.tencent.supersonic.chat.core.agent;
|
package com.tencent.supersonic.chat.server.agent;
|
||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -15,7 +15,7 @@ public class RuleParserTool extends NL2SQLTool {
|
|||||||
private List<String> queryTypes;
|
private List<String> queryTypes;
|
||||||
|
|
||||||
public boolean isContainsAllModel() {
|
public boolean isContainsAllModel() {
|
||||||
return CollectionUtils.isNotEmpty(viewIds) && viewIds.contains(-1L);
|
return CollectionUtils.isNotEmpty(dataSetIds) && dataSetIds.contains(-1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.executor;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.chat.server.pojo.ChatExecuteContext;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
|
|
||||||
|
public interface ChatExecutor {
|
||||||
|
|
||||||
|
QueryResult execute(ChatExecuteContext chatExecuteContext);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.executor;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.PluginQueryManager;
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.build.PluginSemanticQuery;
|
||||||
|
import com.tencent.supersonic.chat.server.pojo.ChatExecuteContext;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
|
|
||||||
|
public class PluginExecutor implements ChatExecutor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryResult execute(ChatExecuteContext chatExecuteContext) {
|
||||||
|
SemanticParseInfo parseInfo = chatExecuteContext.getParseInfo();
|
||||||
|
if (!PluginQueryManager.isPluginQuery(parseInfo.getQueryMode())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PluginSemanticQuery query = PluginQueryManager.getPluginQuery(parseInfo.getQueryMode());
|
||||||
|
query.setParseInfo(parseInfo);
|
||||||
|
return query.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.executor;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.PluginQueryManager;
|
||||||
|
import com.tencent.supersonic.chat.server.pojo.ChatExecuteContext;
|
||||||
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.request.ExecuteQueryReq;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
|
import com.tencent.supersonic.headless.server.service.ChatQueryService;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
public class SqlExecutor implements ChatExecutor {
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
public QueryResult execute(ChatExecuteContext chatExecuteContext) {
|
||||||
|
SemanticParseInfo parseInfo = chatExecuteContext.getParseInfo();
|
||||||
|
if (PluginQueryManager.isPluginQuery(parseInfo.getQueryMode())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ExecuteQueryReq executeQueryReq = buildExecuteReq(chatExecuteContext);
|
||||||
|
ChatQueryService chatQueryService = ContextUtils.getBean(ChatQueryService.class);
|
||||||
|
return chatQueryService.performExecution(executeQueryReq);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExecuteQueryReq buildExecuteReq(ChatExecuteContext chatExecuteContext) {
|
||||||
|
SemanticParseInfo parseInfo = chatExecuteContext.getParseInfo();
|
||||||
|
return ExecuteQueryReq.builder()
|
||||||
|
.queryId(chatExecuteContext.getQueryId())
|
||||||
|
.chatId(chatExecuteContext.getChatId())
|
||||||
|
.queryText(chatExecuteContext.getQueryText())
|
||||||
|
.parseInfo(parseInfo)
|
||||||
|
.saveAnswer(chatExecuteContext.isSaveAnswer())
|
||||||
|
.user(chatExecuteContext.getUser())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.parser;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.chat.server.pojo.ChatParseContext;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
||||||
|
|
||||||
|
public interface ChatParser {
|
||||||
|
|
||||||
|
void parse(ChatParseContext chatParseContext, ParseResp parseResp);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.parser;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.recognize.PluginRecognizer;
|
||||||
|
import com.tencent.supersonic.chat.server.pojo.ChatParseContext;
|
||||||
|
import com.tencent.supersonic.chat.server.util.ComponentFactory;
|
||||||
|
import com.tencent.supersonic.common.util.JsonUtil;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class NL2PluginParser implements ChatParser {
|
||||||
|
|
||||||
|
private final List<PluginRecognizer> pluginRecognizers = ComponentFactory.getPluginRecognizers();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parse(ChatParseContext chatParseContext, ParseResp parseResp) {
|
||||||
|
pluginRecognizers.forEach(pluginRecognizer -> {
|
||||||
|
pluginRecognizer.recognize(chatParseContext, parseResp);
|
||||||
|
log.info("{} context:{} result:{}", pluginRecognizer.getClass().getSimpleName(),
|
||||||
|
JsonUtil.toString(chatParseContext), JsonUtil.toString(parseResp));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.parser;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.chat.server.pojo.ChatParseContext;
|
||||||
|
import com.tencent.supersonic.chat.server.util.QueryReqConverter;
|
||||||
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.request.QueryReq;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
||||||
|
import com.tencent.supersonic.headless.server.service.ChatQueryService;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class NL2SQLParser implements ChatParser {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parse(ChatParseContext chatParseContext, ParseResp parseResp) {
|
||||||
|
if (!chatParseContext.enableNL2SQL()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (checkSkip(parseResp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QueryReq queryReq = QueryReqConverter.buildText2SqlQueryReq(chatParseContext);
|
||||||
|
ChatQueryService chatQueryService = ContextUtils.getBean(ChatQueryService.class);
|
||||||
|
ParseResp text2SqlParseResp = chatQueryService.performParsing(queryReq);
|
||||||
|
if (!ParseResp.ParseState.FAILED.equals(text2SqlParseResp.getState())) {
|
||||||
|
parseResp.getSelectedParses().addAll(text2SqlParseResp.getSelectedParses());
|
||||||
|
}
|
||||||
|
parseResp.getParseTimeCost().setSqlTime(text2SqlParseResp.getParseTimeCost().getSqlTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkSkip(ParseResp parseResp) {
|
||||||
|
List<SemanticParseInfo> selectedParses = parseResp.getSelectedParses();
|
||||||
|
for (SemanticParseInfo semanticParseInfo : selectedParses) {
|
||||||
|
if (semanticParseInfo.getScore() >= parseResp.getQueryText().length()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.dataobject;
|
package com.tencent.supersonic.chat.server.persistence.dataobject;
|
||||||
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.config.DefaultMetric;
|
import com.tencent.supersonic.headless.core.config.DefaultMetric;
|
||||||
import com.tencent.supersonic.chat.core.config.Dim4Dict;
|
import com.tencent.supersonic.headless.core.config.Dim4Dict;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ToString
|
@ToString
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class PluginDO {
|
|||||||
|
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
private String view;
|
private String dataSet;
|
||||||
|
|
||||||
private String pattern;
|
private String pattern;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.repository;
|
package com.tencent.supersonic.chat.server.persistence.repository;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.headless.core.pojo.ChatContext;
|
||||||
import com.tencent.supersonic.chat.core.pojo.ChatContext;
|
|
||||||
|
|
||||||
public interface ChatContextRepository {
|
public interface ChatContextRepository {
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.repository;
|
package com.tencent.supersonic.chat.server.persistence.repository;
|
||||||
|
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatParseReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq;
|
import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.ParseResp;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResp;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.ChatContext;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
|
||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatParseDO;
|
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.headless.api.pojo.SemanticParseInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
||||||
|
import com.tencent.supersonic.chat.api.pojo.response.QueryResp;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface ChatQueryRepository {
|
public interface ChatQueryRepository {
|
||||||
@@ -25,8 +25,10 @@ public interface ChatQueryRepository {
|
|||||||
|
|
||||||
int updateChatQuery(ChatQueryDO chatQueryDO);
|
int updateChatQuery(ChatQueryDO chatQueryDO);
|
||||||
|
|
||||||
List<ChatParseDO> batchSaveParseInfo(ChatContext chatCtx, QueryContext queryContext,
|
Long createChatQuery(ChatParseReq chatParseReq);
|
||||||
ParseResp parseResult, List<SemanticParseInfo> candidateParses);
|
|
||||||
|
List<ChatParseDO> batchSaveParseInfo(ChatParseReq chatParseReq, ParseResp parseResult,
|
||||||
|
List<SemanticParseInfo> candidateParses);
|
||||||
|
|
||||||
ChatParseDO getParseInfo(Long questionId, int parseId);
|
ChatParseDO getParseInfo(Long questionId, int parseId);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.repository;
|
|
||||||
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.StatisticsDO;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface StatisticsRepository {
|
|
||||||
|
|
||||||
void batchSaveStatistics(List<StatisticsDO> list);
|
|
||||||
}
|
|
||||||
@@ -3,14 +3,9 @@ package com.tencent.supersonic.chat.server.persistence.repository.impl;
|
|||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
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.SemanticParseInfo;
|
import com.tencent.supersonic.chat.api.pojo.request.ChatParseReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq;
|
import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.ParseResp;
|
|
||||||
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.SimilarQueryRecallResp;
|
import com.tencent.supersonic.chat.api.pojo.response.SimilarQueryRecallResp;
|
||||||
import com.tencent.supersonic.chat.core.pojo.ChatContext;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
|
||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatParseDO;
|
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.chat.server.persistence.dataobject.ChatQueryDOExample;
|
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatQueryDOExample;
|
||||||
@@ -21,17 +16,21 @@ import com.tencent.supersonic.chat.server.persistence.mapper.custom.ShowCaseCust
|
|||||||
import com.tencent.supersonic.chat.server.persistence.repository.ChatQueryRepository;
|
import com.tencent.supersonic.chat.server.persistence.repository.ChatQueryRepository;
|
||||||
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 java.util.ArrayList;
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
import java.util.Comparator;
|
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
||||||
import java.util.List;
|
import com.tencent.supersonic.chat.api.pojo.response.QueryResp;
|
||||||
import java.util.Objects;
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
@Primary
|
@Primary
|
||||||
@@ -108,51 +107,46 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository {
|
|||||||
queryResult.setQueryId(chatQueryDO.getQuestionId());
|
queryResult.setQueryId(chatQueryDO.getQuestionId());
|
||||||
queryResp.setQueryResult(queryResult);
|
queryResp.setQueryResult(queryResult);
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotBlank(chatQueryDO.getSimilarQueries())) {
|
queryResp.setSimilarQueries(JSONObject.parseArray(chatQueryDO.getSimilarQueries(),
|
||||||
List<SimilarQueryRecallResp> similarQueries = JSONObject.parseArray(chatQueryDO.getSimilarQueries(),
|
SimilarQueryRecallResp.class));
|
||||||
SimilarQueryRecallResp.class);
|
|
||||||
queryResp.setSimilarQueries(similarQueries);
|
|
||||||
}
|
|
||||||
return queryResp;
|
return queryResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long createChatQuery(ParseResp parseResult, ChatContext chatCtx, QueryContext queryContext) {
|
@Override
|
||||||
|
public Long createChatQuery(ChatParseReq chatParseReq) {
|
||||||
ChatQueryDO chatQueryDO = new ChatQueryDO();
|
ChatQueryDO chatQueryDO = new ChatQueryDO();
|
||||||
chatQueryDO.setChatId(Long.valueOf(chatCtx.getChatId()));
|
chatQueryDO.setChatId(Long.valueOf(chatParseReq.getChatId()));
|
||||||
chatQueryDO.setCreateTime(new java.util.Date());
|
chatQueryDO.setCreateTime(new java.util.Date());
|
||||||
chatQueryDO.setUserName(queryContext.getUser().getName());
|
chatQueryDO.setUserName(chatParseReq.getUser().getName());
|
||||||
chatQueryDO.setQueryText(queryContext.getQueryText());
|
chatQueryDO.setQueryText(chatParseReq.getQueryText());
|
||||||
chatQueryDO.setAgentId(queryContext.getAgentId());
|
chatQueryDO.setAgentId(chatParseReq.getAgentId());
|
||||||
chatQueryDO.setQueryResult("");
|
chatQueryDO.setQueryResult("");
|
||||||
try {
|
try {
|
||||||
chatQueryDOMapper.insert(chatQueryDO);
|
chatQueryDOMapper.insert(chatQueryDO);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.info("database insert has an exception:{}", e.toString());
|
log.info("database insert has an exception:{}", e.toString());
|
||||||
}
|
}
|
||||||
Long queryId = chatQueryDO.getQuestionId();
|
return chatQueryDO.getQuestionId();
|
||||||
parseResult.setQueryId(queryId);
|
|
||||||
return queryId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ChatParseDO> batchSaveParseInfo(ChatContext chatCtx, QueryContext queryContext,
|
public List<ChatParseDO> batchSaveParseInfo(ChatParseReq chatParseReq,
|
||||||
ParseResp parseResult, List<SemanticParseInfo> candidateParses) {
|
ParseResp parseResult, List<SemanticParseInfo> candidateParses) {
|
||||||
Long queryId = createChatQuery(parseResult, chatCtx, queryContext);
|
|
||||||
List<ChatParseDO> chatParseDOList = new ArrayList<>();
|
List<ChatParseDO> chatParseDOList = new ArrayList<>();
|
||||||
getChatParseDO(chatCtx, queryContext, queryId, candidateParses, chatParseDOList);
|
getChatParseDO(chatParseReq, parseResult.getQueryId(), candidateParses, chatParseDOList);
|
||||||
if (!CollectionUtils.isEmpty(candidateParses)) {
|
if (!CollectionUtils.isEmpty(candidateParses)) {
|
||||||
chatParseMapper.batchSaveParseInfo(chatParseDOList);
|
chatParseMapper.batchSaveParseInfo(chatParseDOList);
|
||||||
}
|
}
|
||||||
return chatParseDOList;
|
return chatParseDOList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getChatParseDO(ChatContext chatCtx, QueryContext queryContext, Long queryId,
|
public void getChatParseDO(ChatParseReq chatParseReq, Long queryId,
|
||||||
List<SemanticParseInfo> parses, List<ChatParseDO> chatParseDOList) {
|
List<SemanticParseInfo> parses, List<ChatParseDO> chatParseDOList) {
|
||||||
for (int i = 0; i < parses.size(); i++) {
|
for (int i = 0; i < parses.size(); i++) {
|
||||||
ChatParseDO chatParseDO = new ChatParseDO();
|
ChatParseDO chatParseDO = new ChatParseDO();
|
||||||
chatParseDO.setChatId(Long.valueOf(chatCtx.getChatId()));
|
chatParseDO.setChatId(Long.valueOf(chatParseReq.getChatId()));
|
||||||
chatParseDO.setQuestionId(queryId);
|
chatParseDO.setQuestionId(queryId);
|
||||||
chatParseDO.setQueryText(queryContext.getQueryText());
|
chatParseDO.setQueryText(chatParseReq.getQueryText());
|
||||||
chatParseDO.setParseInfo(JsonUtil.toString(parses.get(i)));
|
chatParseDO.setParseInfo(JsonUtil.toString(parses.get(i)));
|
||||||
chatParseDO.setIsCandidate(1);
|
chatParseDO.setIsCandidate(1);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
@@ -160,7 +154,7 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository {
|
|||||||
}
|
}
|
||||||
chatParseDO.setParseId(parses.get(i).getId());
|
chatParseDO.setParseId(parses.get(i).getId());
|
||||||
chatParseDO.setCreateTime(new java.util.Date());
|
chatParseDO.setCreateTime(new java.util.Date());
|
||||||
chatParseDO.setUserName(queryContext.getUser().getName());
|
chatParseDO.setUserName(chatParseReq.getUser().getName());
|
||||||
chatParseDOList.add(chatParseDO);
|
chatParseDOList.add(chatParseDO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
package com.tencent.supersonic.chat.server.persistence.repository.impl;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.server.persistence.dataobject.StatisticsDO;
|
|
||||||
import com.tencent.supersonic.chat.server.persistence.mapper.StatisticsMapper;
|
|
||||||
import com.tencent.supersonic.chat.server.persistence.repository.StatisticsRepository;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.context.annotation.Primary;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
@Primary
|
|
||||||
@Slf4j
|
|
||||||
public class StatisticsRepositoryImpl implements StatisticsRepository {
|
|
||||||
|
|
||||||
private final StatisticsMapper statisticsMapper;
|
|
||||||
|
|
||||||
public StatisticsRepositoryImpl(StatisticsMapper statisticsMapper) {
|
|
||||||
this.statisticsMapper = statisticsMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void batchSaveStatistics(List<StatisticsDO> list) {
|
|
||||||
statisticsMapper.batchSaveStatistics(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin;
|
package com.tencent.supersonic.chat.server.plugin;
|
||||||
|
|
||||||
public enum ParseMode {
|
public enum ParseMode {
|
||||||
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
package com.tencent.supersonic.chat.core.plugin;
|
package com.tencent.supersonic.chat.server.plugin;
|
||||||
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.tencent.supersonic.chat.core.parser.plugin.ParseMode;
|
|
||||||
import com.tencent.supersonic.common.pojo.RecordInfo;
|
import com.tencent.supersonic.common.pojo.RecordInfo;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
@@ -20,7 +19,7 @@ public class Plugin extends RecordInfo {
|
|||||||
*/
|
*/
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
private List<Long> viewList = Lists.newArrayList();
|
private List<Long> dataSetList = Lists.newArrayList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* description, for parsing
|
* description, for parsing
|
||||||
@@ -52,7 +51,7 @@ public class Plugin extends RecordInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isContainsAllModel() {
|
public boolean isContainsAllModel() {
|
||||||
return CollectionUtils.isNotEmpty(viewList) && viewList.contains(-1L);
|
return CollectionUtils.isNotEmpty(dataSetList) && dataSetList.contains(-1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getDefaultMode() {
|
public Long getDefaultMode() {
|
||||||
@@ -1,31 +1,34 @@
|
|||||||
package com.tencent.supersonic.chat.core.plugin;
|
package com.tencent.supersonic.chat.server.plugin;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
import com.tencent.supersonic.chat.server.agent.Agent;
|
||||||
import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch;
|
import com.tencent.supersonic.chat.server.agent.AgentToolType;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
import com.tencent.supersonic.chat.server.agent.PluginTool;
|
||||||
import com.tencent.supersonic.chat.api.pojo.SchemaMapInfo;
|
import com.tencent.supersonic.chat.server.plugin.build.ParamOption;
|
||||||
import com.tencent.supersonic.chat.core.agent.Agent;
|
import com.tencent.supersonic.chat.server.plugin.build.WebBase;
|
||||||
import com.tencent.supersonic.chat.core.agent.AgentToolType;
|
import com.tencent.supersonic.chat.server.plugin.event.PluginAddEvent;
|
||||||
import com.tencent.supersonic.chat.core.agent.PluginTool;
|
import com.tencent.supersonic.chat.server.plugin.event.PluginDelEvent;
|
||||||
import com.tencent.supersonic.chat.core.plugin.event.PluginAddEvent;
|
import com.tencent.supersonic.chat.server.plugin.event.PluginUpdateEvent;
|
||||||
import com.tencent.supersonic.chat.core.plugin.event.PluginDelEvent;
|
import com.tencent.supersonic.chat.server.pojo.ChatParseContext;
|
||||||
import com.tencent.supersonic.chat.core.plugin.event.PluginUpdateEvent;
|
import com.tencent.supersonic.chat.server.service.PluginService;
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
|
||||||
import com.tencent.supersonic.chat.core.query.plugin.ParamOption;
|
|
||||||
import com.tencent.supersonic.chat.core.query.plugin.WebBase;
|
|
||||||
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
||||||
import com.tencent.supersonic.common.util.ComponentFactory;
|
import com.tencent.supersonic.common.util.ComponentFactory;
|
||||||
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
import com.tencent.supersonic.common.util.embedding.EmbeddingQuery;
|
import com.tencent.supersonic.common.util.embedding.EmbeddingQuery;
|
||||||
import com.tencent.supersonic.common.util.embedding.Retrieval;
|
import com.tencent.supersonic.common.util.embedding.Retrieval;
|
||||||
import com.tencent.supersonic.common.util.embedding.RetrieveQuery;
|
import com.tencent.supersonic.common.util.embedding.RetrieveQuery;
|
||||||
import com.tencent.supersonic.common.util.embedding.RetrieveQueryResult;
|
import com.tencent.supersonic.common.util.embedding.RetrieveQueryResult;
|
||||||
import com.tencent.supersonic.common.util.embedding.S2EmbeddingStore;
|
import com.tencent.supersonic.common.util.embedding.S2EmbeddingStore;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaElementMatch;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaMapInfo;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -43,21 +46,16 @@ import java.util.stream.Collectors;
|
|||||||
@Component
|
@Component
|
||||||
public class PluginManager {
|
public class PluginManager {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
private EmbeddingConfig embeddingConfig;
|
private EmbeddingConfig embeddingConfig;
|
||||||
|
|
||||||
private S2EmbeddingStore s2EmbeddingStore = ComponentFactory.getS2EmbeddingStore();
|
private S2EmbeddingStore s2EmbeddingStore = ComponentFactory.getS2EmbeddingStore();
|
||||||
|
|
||||||
public PluginManager(EmbeddingConfig embeddingConfig) {
|
public static List<Plugin> getPluginAgentCanSupport(ChatParseContext chatParseContext) {
|
||||||
this.embeddingConfig = embeddingConfig;
|
PluginService pluginService = ContextUtils.getBean(PluginService.class);
|
||||||
}
|
Agent agent = chatParseContext.getAgent();
|
||||||
|
List<Plugin> plugins = pluginService.getPluginList();
|
||||||
public static List<Plugin> getPluginAgentCanSupport(QueryContext queryContext) {
|
if (Objects.isNull(agent)) {
|
||||||
List<Plugin> plugins = queryContext.getPluginList();
|
|
||||||
if (Objects.isNull(queryContext.getAgent())) {
|
|
||||||
return plugins;
|
|
||||||
}
|
|
||||||
Agent agent = queryContext.getAgent();
|
|
||||||
if (agent == null) {
|
|
||||||
return plugins;
|
return plugins;
|
||||||
}
|
}
|
||||||
List<Long> pluginIds = getPluginTools(agent).stream().map(PluginTool::getPlugins)
|
List<Long> pluginIds = getPluginTools(agent).stream().map(PluginTool::getPlugins)
|
||||||
@@ -197,9 +195,9 @@ public class PluginManager {
|
|||||||
return String.valueOf(Integer.parseInt(id) / 1000);
|
return String.valueOf(Integer.parseInt(id) / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pair<Boolean, Set<Long>> resolve(Plugin plugin, QueryContext queryContext) {
|
public static Pair<Boolean, Set<Long>> resolve(Plugin plugin, ChatParseContext chatParseContext) {
|
||||||
SchemaMapInfo schemaMapInfo = queryContext.getMapInfo();
|
SchemaMapInfo schemaMapInfo = chatParseContext.getMapInfo();
|
||||||
Set<Long> pluginMatchedModel = getPluginMatchedModel(plugin, queryContext);
|
Set<Long> pluginMatchedModel = getPluginMatchedModel(plugin, chatParseContext);
|
||||||
if (CollectionUtils.isEmpty(pluginMatchedModel) && !plugin.isContainsAllModel()) {
|
if (CollectionUtils.isEmpty(pluginMatchedModel) && !plugin.isContainsAllModel()) {
|
||||||
return Pair.of(false, Sets.newHashSet());
|
return Pair.of(false, Sets.newHashSet());
|
||||||
}
|
}
|
||||||
@@ -265,15 +263,15 @@ public class PluginManager {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<Long> getPluginMatchedModel(Plugin plugin, QueryContext queryContext) {
|
private static Set<Long> getPluginMatchedModel(Plugin plugin, ChatParseContext chatParseContext) {
|
||||||
Set<Long> matchedViews = queryContext.getMapInfo().getMatchedViewInfos();
|
Set<Long> matchedDataSets = chatParseContext.getMapInfo().getMatchedDataSetInfos();
|
||||||
if (plugin.isContainsAllModel()) {
|
if (plugin.isContainsAllModel()) {
|
||||||
return Sets.newHashSet(plugin.getDefaultMode());
|
return Sets.newHashSet(plugin.getDefaultMode());
|
||||||
}
|
}
|
||||||
List<Long> modelIds = plugin.getViewList();
|
List<Long> modelIds = plugin.getDataSetList();
|
||||||
Set<Long> pluginMatchedModel = Sets.newHashSet();
|
Set<Long> pluginMatchedModel = Sets.newHashSet();
|
||||||
for (Long modelId : modelIds) {
|
for (Long modelId : modelIds) {
|
||||||
if (matchedViews.contains(modelId)) {
|
if (matchedDataSets.contains(modelId)) {
|
||||||
pluginMatchedModel.add(modelId);
|
pluginMatchedModel.add(modelId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
package com.tencent.supersonic.chat.core.plugin;
|
package com.tencent.supersonic.chat.server.plugin;
|
||||||
|
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.parser.plugin.function.Parameters;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@@ -18,8 +17,6 @@ import lombok.ToString;
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class PluginParseConfig implements Serializable {
|
public class PluginParseConfig implements Serializable {
|
||||||
|
|
||||||
public Parameters parameters;
|
|
||||||
|
|
||||||
public List<String> examples;
|
public List<String> examples;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.tencent.supersonic.chat.core.plugin;
|
package com.tencent.supersonic.chat.server.plugin;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.QueryFilters;
|
import com.tencent.supersonic.headless.api.pojo.request.QueryFilters;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.plugin;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.build.PluginSemanticQuery;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class PluginQueryManager {
|
||||||
|
|
||||||
|
private static Map<String, PluginSemanticQuery> pluginQueries = new HashMap<>();
|
||||||
|
|
||||||
|
public static void register(String queryMode, PluginSemanticQuery pluginSemanticQuery) {
|
||||||
|
pluginQueries.put(queryMode, pluginSemanticQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPluginQuery(String queryMode) {
|
||||||
|
return pluginQueries.containsKey(queryMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PluginSemanticQuery getPluginQuery(String queryMode) {
|
||||||
|
return pluginQueries.get(queryMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.tencent.supersonic.chat.core.plugin;
|
package com.tencent.supersonic.chat.server.plugin;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
@@ -15,7 +15,7 @@ public class PluginRecallResult {
|
|||||||
|
|
||||||
private Plugin plugin;
|
private Plugin plugin;
|
||||||
|
|
||||||
private Set<Long> viewIds;
|
private Set<Long> dataSetIds;
|
||||||
|
|
||||||
private double score;
|
private double score;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.plugin;
|
package com.tencent.supersonic.chat.server.plugin.build;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -1,32 +1,26 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.plugin;
|
package com.tencent.supersonic.chat.server.plugin.build;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
import com.tencent.supersonic.chat.server.plugin.PluginParseResult;
|
||||||
import com.tencent.supersonic.chat.api.pojo.SchemaElementMatch;
|
import com.tencent.supersonic.headless.api.pojo.SchemaElementMatch;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticSchema;
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.QueryFilter;
|
import com.tencent.supersonic.headless.api.pojo.request.QueryFilter;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.QueryFilters;
|
import com.tencent.supersonic.headless.api.pojo.request.QueryFilters;
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginParseResult;
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
import com.tencent.supersonic.chat.core.query.BaseSemanticQuery;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class PluginSemanticQuery extends BaseSemanticQuery {
|
public abstract class PluginSemanticQuery {
|
||||||
|
|
||||||
@Override
|
protected SemanticParseInfo parseInfo;
|
||||||
public String explain(User user) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public abstract QueryResult build();
|
||||||
public void initS2Sql(SemanticSchema semanticSchema, User user) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<Long, Object> getFilterMap(PluginParseResult pluginParseResult) {
|
private Map<Long, Object> getFilterMap(PluginParseResult pluginParseResult) {
|
||||||
Map<Long, Object> map = new HashMap<>();
|
Map<Long, Object> map = new HashMap<>();
|
||||||
@@ -79,7 +73,7 @@ public abstract class PluginSemanticQuery extends BaseSemanticQuery {
|
|||||||
if (!CollectionUtils.isEmpty(webPage.getParamOptions()) && !CollectionUtils.isEmpty(elementValueMap)) {
|
if (!CollectionUtils.isEmpty(webPage.getParamOptions()) && !CollectionUtils.isEmpty(elementValueMap)) {
|
||||||
for (ParamOption paramOption : webPage.getParamOptions()) {
|
for (ParamOption paramOption : webPage.getParamOptions()) {
|
||||||
if (paramOption.getModelId() != null
|
if (paramOption.getModelId() != null
|
||||||
&& !parseInfo.getViewId().equals(paramOption.getModelId())) {
|
&& !parseInfo.getDataSetId().equals(paramOption.getModelId())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
paramOptions.add(paramOption);
|
paramOptions.add(paramOption);
|
||||||
@@ -95,4 +89,8 @@ public abstract class PluginSemanticQuery extends BaseSemanticQuery {
|
|||||||
return webBaseResult;
|
return webBaseResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setParseInfo(SemanticParseInfo parseInfo) {
|
||||||
|
this.parseInfo = parseInfo;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.plugin;
|
package com.tencent.supersonic.chat.server.plugin.build;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.plugin.webpage;
|
package com.tencent.supersonic.chat.server.plugin.build.webpage;
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
import com.tencent.supersonic.chat.server.plugin.Plugin;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
import com.tencent.supersonic.chat.server.plugin.PluginParseResult;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryState;
|
import com.tencent.supersonic.chat.server.plugin.PluginQueryManager;
|
||||||
import com.tencent.supersonic.chat.core.plugin.Plugin;
|
import com.tencent.supersonic.chat.server.plugin.build.PluginSemanticQuery;
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginParseResult;
|
import com.tencent.supersonic.chat.server.plugin.build.WebBase;
|
||||||
import com.tencent.supersonic.chat.core.query.QueryManager;
|
|
||||||
import com.tencent.supersonic.chat.core.query.plugin.PluginSemanticQuery;
|
|
||||||
import com.tencent.supersonic.chat.core.query.plugin.WebBase;
|
|
||||||
import com.tencent.supersonic.common.pojo.Constants;
|
import com.tencent.supersonic.common.pojo.Constants;
|
||||||
import com.tencent.supersonic.common.util.JsonUtil;
|
import com.tencent.supersonic.common.util.JsonUtil;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryState;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -22,25 +21,7 @@ public class WebPageQuery extends PluginSemanticQuery {
|
|||||||
public static String QUERY_MODE = "WEB_PAGE";
|
public static String QUERY_MODE = "WEB_PAGE";
|
||||||
|
|
||||||
public WebPageQuery() {
|
public WebPageQuery() {
|
||||||
QueryManager.register(this);
|
PluginQueryManager.register(QUERY_MODE, this);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getQueryMode() {
|
|
||||||
return QUERY_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public QueryResult execute(User user) {
|
|
||||||
QueryResult queryResult = new QueryResult();
|
|
||||||
queryResult.setQueryMode(QUERY_MODE);
|
|
||||||
Map<String, Object> properties = parseInfo.getProperties();
|
|
||||||
PluginParseResult pluginParseResult = JsonUtil.toObject(JsonUtil.toString(properties.get(Constants.CONTEXT)),
|
|
||||||
PluginParseResult.class);
|
|
||||||
WebPageResp webPageResponse = buildResponse(pluginParseResult);
|
|
||||||
queryResult.setResponse(webPageResponse);
|
|
||||||
queryResult.setQueryState(QueryState.SUCCESS);
|
|
||||||
return queryResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WebPageResp buildResponse(PluginParseResult pluginParseResult) {
|
protected WebPageResp buildResponse(PluginParseResult pluginParseResult) {
|
||||||
@@ -54,4 +35,18 @@ public class WebPageQuery extends PluginSemanticQuery {
|
|||||||
webPageResponse.setWebPage(webBase);
|
webPageResponse.setWebPage(webBase);
|
||||||
return webPageResponse;
|
return webPageResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryResult build() {
|
||||||
|
QueryResult queryResult = new QueryResult();
|
||||||
|
queryResult.setQueryMode(QUERY_MODE);
|
||||||
|
Map<String, Object> properties = parseInfo.getProperties();
|
||||||
|
PluginParseResult pluginParseResult = JsonUtil.toObject(JsonUtil.toString(properties.get(Constants.CONTEXT)),
|
||||||
|
PluginParseResult.class);
|
||||||
|
WebPageResp webPageResponse = buildResponse(pluginParseResult);
|
||||||
|
queryResult.setResponse(webPageResponse);
|
||||||
|
queryResult.setQueryState(QueryState.SUCCESS);
|
||||||
|
return queryResult;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.plugin.webpage;
|
package com.tencent.supersonic.chat.server.plugin.build.webpage;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.query.plugin.WebBase;
|
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.build.WebBase;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class WebPageResp {
|
public class WebPageResp {
|
||||||
|
|
||||||
@@ -1,21 +1,19 @@
|
|||||||
package com.tencent.supersonic.chat.core.query.plugin.webservice;
|
package com.tencent.supersonic.chat.server.plugin.build.webservice;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
import com.tencent.supersonic.chat.server.plugin.Plugin;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
import com.tencent.supersonic.chat.server.plugin.PluginParseResult;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryState;
|
import com.tencent.supersonic.chat.server.plugin.PluginQueryManager;
|
||||||
import com.tencent.supersonic.chat.core.plugin.Plugin;
|
import com.tencent.supersonic.chat.server.plugin.build.ParamOption;
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginParseResult;
|
import com.tencent.supersonic.chat.server.plugin.build.PluginSemanticQuery;
|
||||||
import com.tencent.supersonic.chat.core.query.QueryManager;
|
import com.tencent.supersonic.chat.server.plugin.build.WebBase;
|
||||||
import com.tencent.supersonic.chat.core.query.plugin.ParamOption;
|
|
||||||
import com.tencent.supersonic.chat.core.query.plugin.PluginSemanticQuery;
|
|
||||||
import com.tencent.supersonic.chat.core.query.plugin.WebBase;
|
|
||||||
import com.tencent.supersonic.common.pojo.Constants;
|
import com.tencent.supersonic.common.pojo.Constants;
|
||||||
import com.tencent.supersonic.common.pojo.QueryColumn;
|
import com.tencent.supersonic.common.pojo.QueryColumn;
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
import com.tencent.supersonic.common.util.JsonUtil;
|
import com.tencent.supersonic.common.util.JsonUtil;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryState;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.calcite.sql.parser.SqlParseException;
|
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
@@ -24,6 +22,7 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -39,16 +38,11 @@ public class WebServiceQuery extends PluginSemanticQuery {
|
|||||||
private RestTemplate restTemplate;
|
private RestTemplate restTemplate;
|
||||||
|
|
||||||
public WebServiceQuery() {
|
public WebServiceQuery() {
|
||||||
QueryManager.register(this);
|
PluginQueryManager.register(QUERY_MODE, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getQueryMode() {
|
public QueryResult build() {
|
||||||
return QUERY_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public QueryResult execute(User user) throws SqlParseException {
|
|
||||||
QueryResult queryResult = new QueryResult();
|
QueryResult queryResult = new QueryResult();
|
||||||
queryResult.setQueryMode(QUERY_MODE);
|
queryResult.setQueryMode(QUERY_MODE);
|
||||||
Map<String, Object> properties = parseInfo.getProperties();
|
Map<String, Object> properties = parseInfo.getProperties();
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.plugin.build.webservice;
|
||||||
|
|
||||||
|
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.build.WebBase;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class WebServiceResp {
|
||||||
|
|
||||||
|
private WebBase webBase;
|
||||||
|
|
||||||
|
private Object result;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.tencent.supersonic.chat.core.plugin.event;
|
package com.tencent.supersonic.chat.server.plugin.event;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.Plugin;
|
import com.tencent.supersonic.chat.server.plugin.Plugin;
|
||||||
import org.springframework.context.ApplicationEvent;
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
public class PluginAddEvent extends ApplicationEvent {
|
public class PluginAddEvent extends ApplicationEvent {
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.tencent.supersonic.chat.core.plugin.event;
|
package com.tencent.supersonic.chat.server.plugin.event;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.Plugin;
|
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.Plugin;
|
||||||
import org.springframework.context.ApplicationEvent;
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
public class PluginDelEvent extends ApplicationEvent {
|
public class PluginDelEvent extends ApplicationEvent {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.tencent.supersonic.chat.core.plugin.event;
|
package com.tencent.supersonic.chat.server.plugin.event;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.core.plugin.Plugin;
|
import com.tencent.supersonic.chat.server.plugin.Plugin;
|
||||||
import org.springframework.context.ApplicationEvent;
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
public class PluginUpdateEvent extends ApplicationEvent {
|
public class PluginUpdateEvent extends ApplicationEvent {
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.plugin.recognize;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.Plugin;
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.PluginManager;
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.PluginParseResult;
|
||||||
|
import com.tencent.supersonic.chat.server.plugin.PluginRecallResult;
|
||||||
|
import com.tencent.supersonic.chat.server.pojo.ChatParseContext;
|
||||||
|
import com.tencent.supersonic.common.pojo.Constants;
|
||||||
|
import com.tencent.supersonic.common.pojo.enums.FilterOperatorEnum;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaElementMatch;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.request.QueryFilter;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.request.QueryFilters;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PluginParser defines the basic process and common methods for recalling plugins.
|
||||||
|
*/
|
||||||
|
public abstract class PluginRecognizer {
|
||||||
|
|
||||||
|
public void recognize(ChatParseContext chatParseContext, ParseResp parseResp) {
|
||||||
|
if (!checkPreCondition(chatParseContext)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PluginRecallResult pluginRecallResult = recallPlugin(chatParseContext);
|
||||||
|
if (pluginRecallResult == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buildQuery(chatParseContext, parseResp, pluginRecallResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean checkPreCondition(ChatParseContext chatParseContext);
|
||||||
|
|
||||||
|
public abstract PluginRecallResult recallPlugin(ChatParseContext chatParseContext);
|
||||||
|
|
||||||
|
public void buildQuery(ChatParseContext chatParseContext, ParseResp parseResp,
|
||||||
|
PluginRecallResult pluginRecallResult) {
|
||||||
|
Plugin plugin = pluginRecallResult.getPlugin();
|
||||||
|
Set<Long> dataSetIds = pluginRecallResult.getDataSetIds();
|
||||||
|
if (plugin.isContainsAllModel()) {
|
||||||
|
dataSetIds = Sets.newHashSet(-1L);
|
||||||
|
}
|
||||||
|
for (Long dataSetId : dataSetIds) {
|
||||||
|
SemanticParseInfo semanticParseInfo = buildSemanticParseInfo(dataSetId, plugin,
|
||||||
|
chatParseContext, pluginRecallResult.getDistance());
|
||||||
|
semanticParseInfo.setQueryMode(plugin.getType());
|
||||||
|
semanticParseInfo.setScore(pluginRecallResult.getScore());
|
||||||
|
parseResp.getSelectedParses().add(semanticParseInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<Plugin> getPluginList(ChatParseContext chatParseContext) {
|
||||||
|
return PluginManager.getPluginAgentCanSupport(chatParseContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SemanticParseInfo buildSemanticParseInfo(Long dataSetId, Plugin plugin,
|
||||||
|
ChatParseContext chatParseContext, double distance) {
|
||||||
|
List<SchemaElementMatch> schemaElementMatches = chatParseContext.getMapInfo().getMatchedElements(dataSetId);
|
||||||
|
QueryFilters queryFilters = chatParseContext.getQueryFilters();
|
||||||
|
if (schemaElementMatches == null) {
|
||||||
|
schemaElementMatches = Lists.newArrayList();
|
||||||
|
}
|
||||||
|
SemanticParseInfo semanticParseInfo = new SemanticParseInfo();
|
||||||
|
semanticParseInfo.setElementMatches(schemaElementMatches);
|
||||||
|
SchemaElement schemaElement = new SchemaElement();
|
||||||
|
schemaElement.setDataSet(dataSetId);
|
||||||
|
semanticParseInfo.setDataSet(schemaElement);
|
||||||
|
Map<String, Object> properties = new HashMap<>();
|
||||||
|
PluginParseResult pluginParseResult = new PluginParseResult();
|
||||||
|
pluginParseResult.setPlugin(plugin);
|
||||||
|
pluginParseResult.setQueryFilters(queryFilters);
|
||||||
|
pluginParseResult.setDistance(distance);
|
||||||
|
pluginParseResult.setQueryText(chatParseContext.getQueryText());
|
||||||
|
properties.put(Constants.CONTEXT, pluginParseResult);
|
||||||
|
properties.put("type", "plugin");
|
||||||
|
properties.put("name", plugin.getName());
|
||||||
|
semanticParseInfo.setProperties(properties);
|
||||||
|
semanticParseInfo.setScore(distance);
|
||||||
|
fillSemanticParseInfo(semanticParseInfo);
|
||||||
|
return semanticParseInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillSemanticParseInfo(SemanticParseInfo semanticParseInfo) {
|
||||||
|
List<SchemaElementMatch> schemaElementMatches = semanticParseInfo.getElementMatches();
|
||||||
|
if (CollectionUtils.isEmpty(schemaElementMatches)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
schemaElementMatches.stream().filter(schemaElementMatch ->
|
||||||
|
SchemaElementType.VALUE.equals(schemaElementMatch.getElement().getType())
|
||||||
|
|| SchemaElementType.ID.equals(schemaElementMatch.getElement().getType()))
|
||||||
|
.forEach(schemaElementMatch -> {
|
||||||
|
QueryFilter queryFilter = new QueryFilter();
|
||||||
|
queryFilter.setValue(schemaElementMatch.getWord());
|
||||||
|
queryFilter.setElementID(schemaElementMatch.getElement().getId());
|
||||||
|
queryFilter.setName(schemaElementMatch.getElement().getName());
|
||||||
|
queryFilter.setOperator(FilterOperatorEnum.EQUALS);
|
||||||
|
queryFilter.setBizName(schemaElementMatch.getElement().getBizName());
|
||||||
|
semanticParseInfo.getDimensionFilters().add(queryFilter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin.embedding;
|
package com.tencent.supersonic.chat.server.plugin.recognize.embedding;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
import com.tencent.supersonic.chat.server.plugin.ParseMode;
|
||||||
import com.tencent.supersonic.chat.core.plugin.Plugin;
|
import com.tencent.supersonic.chat.server.plugin.Plugin;
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginManager;
|
import com.tencent.supersonic.chat.server.plugin.PluginManager;
|
||||||
import com.tencent.supersonic.chat.core.plugin.PluginRecallResult;
|
import com.tencent.supersonic.chat.server.plugin.PluginRecallResult;
|
||||||
import com.tencent.supersonic.chat.core.utils.ComponentFactory;
|
import com.tencent.supersonic.chat.server.plugin.recognize.PluginRecognizer;
|
||||||
import com.tencent.supersonic.chat.core.parser.PythonLLMProxy;
|
import com.tencent.supersonic.chat.server.pojo.ChatParseContext;
|
||||||
import com.tencent.supersonic.chat.core.parser.plugin.ParseMode;
|
|
||||||
import com.tencent.supersonic.chat.core.parser.plugin.PluginParser;
|
|
||||||
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
import com.tencent.supersonic.common.util.embedding.Retrieval;
|
import com.tencent.supersonic.common.util.embedding.Retrieval;
|
||||||
import com.tencent.supersonic.common.util.embedding.RetrieveQueryResult;
|
import com.tencent.supersonic.common.util.embedding.RetrieveQueryResult;
|
||||||
|
import com.tencent.supersonic.headless.core.chat.parser.PythonLLMProxy;
|
||||||
|
import com.tencent.supersonic.headless.core.utils.ComponentFactory;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
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;
|
||||||
@@ -28,44 +28,42 @@ import java.util.stream.Collectors;
|
|||||||
* EmbeddingRecallParser is an implementation of a recall plugin based on Embedding
|
* EmbeddingRecallParser is an implementation of a recall plugin based on Embedding
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class EmbeddingRecallParser extends PluginParser {
|
public class EmbeddingRecallRecognizer extends PluginRecognizer {
|
||||||
|
|
||||||
@Override
|
public boolean checkPreCondition(ChatParseContext chatParseContext) {
|
||||||
public boolean checkPreCondition(QueryContext queryContext) {
|
|
||||||
EmbeddingConfig embeddingConfig = ContextUtils.getBean(EmbeddingConfig.class);
|
EmbeddingConfig embeddingConfig = ContextUtils.getBean(EmbeddingConfig.class);
|
||||||
if (StringUtils.isBlank(embeddingConfig.getUrl()) && ComponentFactory.getLLMProxy() instanceof PythonLLMProxy) {
|
if (StringUtils.isBlank(embeddingConfig.getUrl()) && ComponentFactory.getLLMProxy() instanceof PythonLLMProxy) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
List<Plugin> plugins = getPluginList(queryContext);
|
List<Plugin> plugins = getPluginList(chatParseContext);
|
||||||
return !CollectionUtils.isEmpty(plugins);
|
return !CollectionUtils.isEmpty(plugins);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public PluginRecallResult recallPlugin(ChatParseContext chatParseContext) {
|
||||||
public PluginRecallResult recallPlugin(QueryContext queryContext) {
|
String text = chatParseContext.getQueryText();
|
||||||
String text = queryContext.getQueryText();
|
|
||||||
List<Retrieval> embeddingRetrievals = embeddingRecall(text);
|
List<Retrieval> embeddingRetrievals = embeddingRecall(text);
|
||||||
if (CollectionUtils.isEmpty(embeddingRetrievals)) {
|
if (CollectionUtils.isEmpty(embeddingRetrievals)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
List<Plugin> plugins = getPluginList(queryContext);
|
List<Plugin> plugins = getPluginList(chatParseContext);
|
||||||
Map<Long, Plugin> pluginMap = plugins.stream().collect(Collectors.toMap(Plugin::getId, p -> p));
|
Map<Long, Plugin> pluginMap = plugins.stream().collect(Collectors.toMap(Plugin::getId, p -> p));
|
||||||
for (Retrieval embeddingRetrieval : embeddingRetrievals) {
|
for (Retrieval embeddingRetrieval : embeddingRetrievals) {
|
||||||
Plugin plugin = pluginMap.get(Long.parseLong(embeddingRetrieval.getId()));
|
Plugin plugin = pluginMap.get(Long.parseLong(embeddingRetrieval.getId()));
|
||||||
if (plugin == null) {
|
if (plugin == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Pair<Boolean, Set<Long>> pair = PluginManager.resolve(plugin, queryContext);
|
Pair<Boolean, Set<Long>> pair = PluginManager.resolve(plugin, chatParseContext);
|
||||||
log.info("embedding plugin resolve: {}", pair);
|
log.info("embedding plugin resolve: {}", pair);
|
||||||
if (pair.getLeft()) {
|
if (pair.getLeft()) {
|
||||||
Set<Long> viewList = pair.getRight();
|
Set<Long> dataSetList = pair.getRight();
|
||||||
if (CollectionUtils.isEmpty(viewList)) {
|
if (CollectionUtils.isEmpty(dataSetList)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
plugin.setParseMode(ParseMode.EMBEDDING_RECALL);
|
plugin.setParseMode(ParseMode.EMBEDDING_RECALL);
|
||||||
double distance = embeddingRetrieval.getDistance();
|
double distance = embeddingRetrieval.getDistance();
|
||||||
double score = queryContext.getQueryText().length() * (1 - distance);
|
double score = chatParseContext.getQueryText().length() * (1 - distance);
|
||||||
return PluginRecallResult.builder()
|
return PluginRecallResult.builder()
|
||||||
.plugin(plugin).viewIds(viewList).score(score).distance(distance).build();
|
.plugin(plugin).dataSetIds(dataSetList).score(score).distance(distance).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin.embedding;
|
package com.tencent.supersonic.chat.server.plugin.recognize.embedding;
|
||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
package com.tencent.supersonic.chat.core.parser.plugin.embedding;
|
package com.tencent.supersonic.chat.server.plugin.recognize.embedding;
|
||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.pojo;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ChatExecuteContext {
|
||||||
|
private User user;
|
||||||
|
private Long queryId;
|
||||||
|
private Integer chatId;
|
||||||
|
private int parseId;
|
||||||
|
private String queryText;
|
||||||
|
private boolean saveAnswer;
|
||||||
|
private SemanticParseInfo parseInfo;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.tencent.supersonic.chat.server.pojo;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||||
|
import com.tencent.supersonic.chat.server.agent.Agent;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaMapInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.request.QueryFilters;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ChatParseContext {
|
||||||
|
private String queryText;
|
||||||
|
private Integer chatId;
|
||||||
|
private Agent agent;
|
||||||
|
private User user;
|
||||||
|
private QueryFilters queryFilters;
|
||||||
|
private boolean saveAnswer = true;
|
||||||
|
private SchemaMapInfo mapInfo = new SchemaMapInfo();
|
||||||
|
|
||||||
|
public boolean enableNL2SQL() {
|
||||||
|
if (agent == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return agent.containsNL2SQLTool();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,4 +5,5 @@ package com.tencent.supersonic.chat.server.processor;
|
|||||||
*/
|
*/
|
||||||
public interface ResultProcessor {
|
public interface ResultProcessor {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
package com.tencent.supersonic.chat.server.processor.execute;
|
package com.tencent.supersonic.chat.server.processor.execute;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.tencent.supersonic.headless.api.pojo.RelatedSchemaElement;
|
import com.tencent.supersonic.chat.server.pojo.ChatExecuteContext;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.ViewSchema;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ExecuteQueryReq;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
|
||||||
import com.tencent.supersonic.chat.server.service.SemanticService;
|
|
||||||
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
||||||
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.RelatedSchemaElement;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
|
import com.tencent.supersonic.headless.server.service.impl.SemanticService;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -28,21 +28,22 @@ public class DimensionRecommendProcessor implements ExecuteResultProcessor {
|
|||||||
private static final int recommend_dimension_size = 5;
|
private static final int recommend_dimension_size = 5;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(QueryResult queryResult, SemanticParseInfo semanticParseInfo, ExecuteQueryReq queryReq) {
|
public void process(ChatExecuteContext chatExecuteContext, QueryResult queryResult) {
|
||||||
|
SemanticParseInfo semanticParseInfo = chatExecuteContext.getParseInfo();
|
||||||
if (!QueryType.METRIC.equals(semanticParseInfo.getQueryType())
|
if (!QueryType.METRIC.equals(semanticParseInfo.getQueryType())
|
||||||
|| CollectionUtils.isEmpty(semanticParseInfo.getMetrics())) {
|
|| CollectionUtils.isEmpty(semanticParseInfo.getMetrics())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SchemaElement element = semanticParseInfo.getMetrics().iterator().next();
|
SchemaElement element = semanticParseInfo.getMetrics().iterator().next();
|
||||||
List<SchemaElement> dimensionRecommended = getDimensions(element.getId(), element.getView());
|
List<SchemaElement> dimensionRecommended = getDimensions(element.getId(), element.getDataSet());
|
||||||
queryResult.setRecommendedDimensions(dimensionRecommended);
|
queryResult.setRecommendedDimensions(dimensionRecommended);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SchemaElement> getDimensions(Long metricId, Long viewId) {
|
private List<SchemaElement> getDimensions(Long metricId, Long dataSetId) {
|
||||||
SemanticService semanticService = ContextUtils.getBean(SemanticService.class);
|
SemanticService semanticService = ContextUtils.getBean(SemanticService.class);
|
||||||
ViewSchema viewSchema = semanticService.getViewSchema(viewId);
|
DataSetSchema dataSetSchema = semanticService.getDataSetSchema(dataSetId);
|
||||||
List<Long> drillDownDimensions = Lists.newArrayList();
|
List<Long> drillDownDimensions = Lists.newArrayList();
|
||||||
Set<SchemaElement> metricElements = viewSchema.getMetrics();
|
Set<SchemaElement> metricElements = dataSetSchema.getMetrics();
|
||||||
if (!CollectionUtils.isEmpty(metricElements)) {
|
if (!CollectionUtils.isEmpty(metricElements)) {
|
||||||
Optional<SchemaElement> metric = metricElements.stream().filter(schemaElement ->
|
Optional<SchemaElement> metric = metricElements.stream().filter(schemaElement ->
|
||||||
metricId.equals(schemaElement.getId())
|
metricId.equals(schemaElement.getId())
|
||||||
@@ -54,7 +55,7 @@ public class DimensionRecommendProcessor implements ExecuteResultProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
final List<Long> drillDownDimensionsFinal = drillDownDimensions;
|
final List<Long> drillDownDimensionsFinal = drillDownDimensions;
|
||||||
return viewSchema.getDimensions().stream()
|
return dataSetSchema.getDimensions().stream()
|
||||||
.filter(dim -> filterDimension(drillDownDimensionsFinal, dim))
|
.filter(dim -> filterDimension(drillDownDimensionsFinal, dim))
|
||||||
.sorted(Comparator.comparing(SchemaElement::getUseCnt).reversed())
|
.sorted(Comparator.comparing(SchemaElement::getUseCnt).reversed())
|
||||||
.limit(recommend_dimension_size)
|
.limit(recommend_dimension_size)
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
package com.tencent.supersonic.chat.server.processor.execute;
|
package com.tencent.supersonic.chat.server.processor.execute;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo;
|
import com.tencent.supersonic.chat.server.pojo.ChatExecuteContext;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ExecuteQueryReq;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
|
||||||
import com.tencent.supersonic.chat.server.processor.ResultProcessor;
|
import com.tencent.supersonic.chat.server.processor.ResultProcessor;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ExecuteResultProcessor wraps things up before returning results to users in execute stage.
|
* A ExecuteResultProcessor wraps things up before returning results to users in execute stage.
|
||||||
*/
|
*/
|
||||||
public interface ExecuteResultProcessor extends ResultProcessor {
|
public interface ExecuteResultProcessor extends ResultProcessor {
|
||||||
|
|
||||||
void process(QueryResult queryResult, SemanticParseInfo semanticParseInfo, ExecuteQueryReq queryReq);
|
void process(ChatExecuteContext chatExecuteContext, QueryResult queryResult);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,25 +1,7 @@
|
|||||||
package com.tencent.supersonic.chat.server.processor.execute;
|
package com.tencent.supersonic.chat.server.processor.execute;
|
||||||
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.DAY;
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.DAY_FORMAT;
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.DAY_FORMAT_INT;
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.MONTH;
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.MONTH_FORMAT;
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.MONTH_FORMAT_INT;
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.TIMES_FORMAT;
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.TIME_FORMAT;
|
|
||||||
import static com.tencent.supersonic.common.pojo.Constants.WEEK;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
import com.tencent.supersonic.auth.api.authentication.pojo.User;
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo;
|
import com.tencent.supersonic.chat.server.pojo.ChatExecuteContext;
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ExecuteQueryReq;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.AggregateInfo;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.MetricInfo;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
|
||||||
import com.tencent.supersonic.chat.core.config.AggregatorConfig;
|
|
||||||
import com.tencent.supersonic.chat.core.query.semantic.SemanticInterpreter;
|
|
||||||
import com.tencent.supersonic.chat.core.utils.ComponentFactory;
|
|
||||||
import com.tencent.supersonic.chat.core.utils.QueryReqBuilder;
|
|
||||||
import com.tencent.supersonic.common.pojo.DateConf;
|
import com.tencent.supersonic.common.pojo.DateConf;
|
||||||
import com.tencent.supersonic.common.pojo.DateConf.DateMode;
|
import com.tencent.supersonic.common.pojo.DateConf.DateMode;
|
||||||
import com.tencent.supersonic.common.pojo.QueryColumn;
|
import com.tencent.supersonic.common.pojo.QueryColumn;
|
||||||
@@ -28,9 +10,20 @@ import com.tencent.supersonic.common.pojo.enums.QueryType;
|
|||||||
import com.tencent.supersonic.common.pojo.enums.RatioOverType;
|
import com.tencent.supersonic.common.pojo.enums.RatioOverType;
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
import com.tencent.supersonic.common.util.DateUtils;
|
import com.tencent.supersonic.common.util.DateUtils;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.AggregateInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.MetricInfo;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
import com.tencent.supersonic.headless.api.pojo.request.QueryStructReq;
|
import com.tencent.supersonic.headless.api.pojo.request.QueryStructReq;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.SemanticQueryResp;
|
import com.tencent.supersonic.headless.api.pojo.response.SemanticQueryResp;
|
||||||
|
import com.tencent.supersonic.headless.core.config.AggregatorConfig;
|
||||||
|
import com.tencent.supersonic.headless.core.utils.QueryReqBuilder;
|
||||||
|
import com.tencent.supersonic.headless.server.service.QueryService;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.time.DayOfWeek;
|
import java.time.DayOfWeek;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
@@ -48,8 +41,16 @@ import java.util.Optional;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
import static com.tencent.supersonic.common.pojo.Constants.DAY;
|
||||||
|
import static com.tencent.supersonic.common.pojo.Constants.DAY_FORMAT;
|
||||||
|
import static com.tencent.supersonic.common.pojo.Constants.DAY_FORMAT_INT;
|
||||||
|
import static com.tencent.supersonic.common.pojo.Constants.MONTH;
|
||||||
|
import static com.tencent.supersonic.common.pojo.Constants.MONTH_FORMAT;
|
||||||
|
import static com.tencent.supersonic.common.pojo.Constants.MONTH_FORMAT_INT;
|
||||||
|
import static com.tencent.supersonic.common.pojo.Constants.TIMES_FORMAT;
|
||||||
|
import static com.tencent.supersonic.common.pojo.Constants.TIME_FORMAT;
|
||||||
|
import static com.tencent.supersonic.common.pojo.Constants.WEEK;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add ratio queries for metric queries.
|
* Add ratio queries for metric queries.
|
||||||
@@ -57,18 +58,17 @@ import org.springframework.util.CollectionUtils;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class MetricRatioProcessor implements ExecuteResultProcessor {
|
public class MetricRatioProcessor implements ExecuteResultProcessor {
|
||||||
|
|
||||||
private SemanticInterpreter semanticInterpreter = ComponentFactory.getSemanticLayer();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(QueryResult queryResult, SemanticParseInfo semanticParseInfo, ExecuteQueryReq queryReq) {
|
public void process(ChatExecuteContext chatExecuteContext, QueryResult queryResult) {
|
||||||
|
SemanticParseInfo semanticParseInfo = chatExecuteContext.getParseInfo();
|
||||||
AggregatorConfig aggregatorConfig = ContextUtils.getBean(AggregatorConfig.class);
|
AggregatorConfig aggregatorConfig = ContextUtils.getBean(AggregatorConfig.class);
|
||||||
if (CollectionUtils.isEmpty(semanticParseInfo.getMetrics())
|
if (CollectionUtils.isEmpty(semanticParseInfo.getMetrics())
|
||||||
|| !aggregatorConfig.getEnableRatio()
|
|| !aggregatorConfig.getEnableRatio()
|
||||||
|| !QueryType.METRIC.equals(semanticParseInfo.getQueryType())) {
|
|| !QueryType.METRIC.equals(semanticParseInfo.getQueryType())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AggregateInfo aggregateInfo = getAggregateInfo(queryReq.getUser(), semanticParseInfo, queryResult);
|
AggregateInfo aggregateInfo = getAggregateInfo(chatExecuteContext.getUser(),
|
||||||
|
semanticParseInfo, queryResult);
|
||||||
queryResult.setAggregateInfo(aggregateInfo);
|
queryResult.setAggregateInfo(aggregateInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,15 +124,17 @@ public class MetricRatioProcessor implements ExecuteResultProcessor {
|
|||||||
return aggregateInfo;
|
return aggregateInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
private MetricInfo queryRatio(User user, SemanticParseInfo semanticParseInfo, SchemaElement metric,
|
private MetricInfo queryRatio(User user, SemanticParseInfo semanticParseInfo, SchemaElement metric,
|
||||||
AggOperatorEnum aggOperatorEnum, QueryResult queryResult) {
|
AggOperatorEnum aggOperatorEnum, QueryResult queryResult) {
|
||||||
|
|
||||||
QueryStructReq queryStructReq = QueryReqBuilder.buildStructRatioReq(semanticParseInfo, metric, aggOperatorEnum);
|
QueryStructReq queryStructReq = QueryReqBuilder.buildStructRatioReq(semanticParseInfo, metric, aggOperatorEnum);
|
||||||
String dateField = QueryReqBuilder.getDateField(semanticParseInfo.getDateInfo());
|
String dateField = QueryReqBuilder.getDateField(semanticParseInfo.getDateInfo());
|
||||||
queryStructReq.setGroups(new ArrayList<>(Arrays.asList(dateField)));
|
queryStructReq.setGroups(new ArrayList<>(Arrays.asList(dateField)));
|
||||||
queryStructReq.setDateInfo(getRatioDateConf(aggOperatorEnum, semanticParseInfo, queryResult));
|
queryStructReq.setDateInfo(getRatioDateConf(aggOperatorEnum, semanticParseInfo, queryResult));
|
||||||
|
queryStructReq.setConvertToSql(false);
|
||||||
SemanticQueryResp queryResp = semanticInterpreter.queryByStruct(queryStructReq, user);
|
QueryService queryService = ContextUtils.getBean(QueryService.class);
|
||||||
|
SemanticQueryResp queryResp = queryService.queryByReq(queryStructReq, user);
|
||||||
MetricInfo metricInfo = new MetricInfo();
|
MetricInfo metricInfo = new MetricInfo();
|
||||||
metricInfo.setStatistics(new HashMap<>());
|
metricInfo.setStatistics(new HashMap<>());
|
||||||
if (Objects.isNull(queryResp) || CollectionUtils.isEmpty(queryResp.getResultList())) {
|
if (Objects.isNull(queryResp) || CollectionUtils.isEmpty(queryResp.getResultList())) {
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
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.headless.api.pojo.SchemaElement;
|
import com.tencent.supersonic.chat.server.pojo.ChatExecuteContext;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
import com.tencent.supersonic.common.pojo.Constants;
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.request.ExecuteQueryReq;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
|
||||||
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
|
||||||
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
||||||
import com.tencent.supersonic.common.util.ComponentFactory;
|
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
import com.tencent.supersonic.common.util.embedding.Retrieval;
|
import com.tencent.supersonic.common.util.embedding.Retrieval;
|
||||||
import com.tencent.supersonic.common.util.embedding.RetrieveQuery;
|
import com.tencent.supersonic.common.util.embedding.RetrieveQuery;
|
||||||
import com.tencent.supersonic.common.util.embedding.RetrieveQueryResult;
|
import com.tencent.supersonic.common.util.embedding.RetrieveQueryResult;
|
||||||
import com.tencent.supersonic.common.util.embedding.S2EmbeddingStore;
|
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
|
import com.tencent.supersonic.headless.core.chat.knowledge.MetaEmbeddingService;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -31,11 +31,9 @@ public class MetricRecommendProcessor implements ExecuteResultProcessor {
|
|||||||
|
|
||||||
private static final int METRIC_RECOMMEND_SIZE = 5;
|
private static final int METRIC_RECOMMEND_SIZE = 5;
|
||||||
|
|
||||||
private S2EmbeddingStore s2EmbeddingStore = ComponentFactory.getS2EmbeddingStore();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(QueryResult queryResult, SemanticParseInfo semanticParseInfo, ExecuteQueryReq queryReq) {
|
public void process(ChatExecuteContext chatExecuteContext, QueryResult queryResult) {
|
||||||
fillSimilarMetric(queryResult.getChatContext());
|
fillSimilarMetric(chatExecuteContext.getParseInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillSimilarMetric(SemanticParseInfo parseInfo) {
|
private void fillSimilarMetric(SemanticParseInfo parseInfo) {
|
||||||
@@ -46,15 +44,14 @@ public class MetricRecommendProcessor implements ExecuteResultProcessor {
|
|||||||
}
|
}
|
||||||
List<String> metricNames = Collections.singletonList(parseInfo.getMetrics().iterator().next().getName());
|
List<String> metricNames = Collections.singletonList(parseInfo.getMetrics().iterator().next().getName());
|
||||||
Map<String, String> filterCondition = new HashMap<>();
|
Map<String, String> filterCondition = new HashMap<>();
|
||||||
filterCondition.put("modelId", parseInfo.getMetrics().iterator().next().getView().toString());
|
filterCondition.put("modelId", parseInfo.getMetrics().iterator().next().getDataSet().toString());
|
||||||
filterCondition.put("type", SchemaElementType.METRIC.name());
|
filterCondition.put("type", SchemaElementType.METRIC.name());
|
||||||
RetrieveQuery retrieveQuery = RetrieveQuery.builder().queryTextsList(metricNames)
|
RetrieveQuery retrieveQuery = RetrieveQuery.builder().queryTextsList(metricNames)
|
||||||
.filterCondition(filterCondition).queryEmbeddings(null).build();
|
.filterCondition(filterCondition).queryEmbeddings(null).build();
|
||||||
|
MetaEmbeddingService metaEmbeddingService = ContextUtils.getBean(MetaEmbeddingService.class);
|
||||||
EmbeddingConfig embeddingConfig = ContextUtils.getBean(EmbeddingConfig.class);
|
List<RetrieveQueryResult> retrieveQueryResults =
|
||||||
|
metaEmbeddingService.retrieveQuery(retrieveQuery, METRIC_RECOMMEND_SIZE + 1, new HashMap<>(),
|
||||||
List<RetrieveQueryResult> retrieveQueryResults = s2EmbeddingStore.retrieveQuery(
|
new HashSet<>());
|
||||||
embeddingConfig.getMetaCollectionName(), retrieveQuery, METRIC_RECOMMEND_SIZE + 1);
|
|
||||||
if (CollectionUtils.isEmpty(retrieveQueryResults)) {
|
if (CollectionUtils.isEmpty(retrieveQueryResults)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -71,9 +68,10 @@ public class MetricRecommendProcessor implements ExecuteResultProcessor {
|
|||||||
if (!metricIds.contains(Retrieval.getLongId(retrieval.getId()))) {
|
if (!metricIds.contains(Retrieval.getLongId(retrieval.getId()))) {
|
||||||
SchemaElement schemaElement = JSONObject.parseObject(JSONObject.toJSONString(retrieval.getMetadata()),
|
SchemaElement schemaElement = JSONObject.parseObject(JSONObject.toJSONString(retrieval.getMetadata()),
|
||||||
SchemaElement.class);
|
SchemaElement.class);
|
||||||
if (retrieval.getMetadata().containsKey("viewId")) {
|
if (retrieval.getMetadata().containsKey("dataSetId")) {
|
||||||
String viewId = retrieval.getMetadata().get("viewId").toString();
|
String dataSetId = retrieval.getMetadata().get("dataSetId").toString()
|
||||||
schemaElement.setView(Long.parseLong(viewId));
|
.replace(Constants.UNDERLINE, "");
|
||||||
|
schemaElement.setDataSet(Long.parseLong(dataSetId));
|
||||||
}
|
}
|
||||||
schemaElement.setOrder(++metricOrder);
|
schemaElement.setOrder(++metricOrder);
|
||||||
parseInfo.getMetrics().add(schemaElement);
|
parseInfo.getMetrics().add(schemaElement);
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
package com.tencent.supersonic.chat.server.processor.parse;
|
package com.tencent.supersonic.chat.server.processor.parse;
|
||||||
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.SemanticParseInfo;
|
import com.tencent.supersonic.chat.server.pojo.ChatParseContext;
|
||||||
import com.tencent.supersonic.chat.api.pojo.ViewSchema;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.EntityInfo;
|
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.ParseResp;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.ChatContext;
|
|
||||||
import com.tencent.supersonic.chat.core.pojo.QueryContext;
|
|
||||||
import com.tencent.supersonic.chat.core.query.QueryManager;
|
|
||||||
import com.tencent.supersonic.chat.core.query.SemanticQuery;
|
|
||||||
import com.tencent.supersonic.chat.core.query.llm.analytics.MetricAnalyzeQuery;
|
|
||||||
import com.tencent.supersonic.chat.server.service.SemanticService;
|
|
||||||
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.EntityInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
|
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
||||||
|
import com.tencent.supersonic.headless.core.chat.query.QueryManager;
|
||||||
|
import com.tencent.supersonic.headless.server.service.impl.SemanticService;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EntityInfoProcessor fills core attributes of an entity so that
|
* EntityInfoProcessor fills core attributes of an entity so that
|
||||||
@@ -23,23 +19,20 @@ import java.util.stream.Collectors;
|
|||||||
public class EntityInfoProcessor implements ParseResultProcessor {
|
public class EntityInfoProcessor implements ParseResultProcessor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(ParseResp parseResp, QueryContext queryContext, ChatContext chatContext) {
|
public void process(ChatParseContext chatParseContext, ParseResp parseResp) {
|
||||||
List<SemanticQuery> semanticQueries = queryContext.getCandidateQueries();
|
List<SemanticParseInfo> selectedParses = parseResp.getSelectedParses();
|
||||||
if (CollectionUtils.isEmpty(semanticQueries)) {
|
if (CollectionUtils.isEmpty(selectedParses)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<SemanticParseInfo> selectedParses = semanticQueries.stream().map(SemanticQuery::getParseInfo)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
selectedParses.forEach(parseInfo -> {
|
selectedParses.forEach(parseInfo -> {
|
||||||
String queryMode = parseInfo.getQueryMode();
|
String queryMode = parseInfo.getQueryMode();
|
||||||
if (QueryManager.containsPluginQuery(queryMode)
|
if (QueryManager.containsRuleQuery(queryMode)) {
|
||||||
|| MetricAnalyzeQuery.QUERY_MODE.equalsIgnoreCase(queryMode)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//1. set entity info
|
//1. set entity info
|
||||||
ViewSchema viewSchema = queryContext.getSemanticSchema().getViewSchemaMap().get(parseInfo.getViewId());
|
|
||||||
SemanticService semanticService = ContextUtils.getBean(SemanticService.class);
|
SemanticService semanticService = ContextUtils.getBean(SemanticService.class);
|
||||||
EntityInfo entityInfo = semanticService.getEntityInfo(parseInfo, viewSchema, queryContext.getUser());
|
DataSetSchema dataSetSchema = semanticService.getDataSetSchema(parseInfo.getDataSetId());
|
||||||
|
EntityInfo entityInfo = semanticService.getEntityInfo(parseInfo, dataSetSchema, chatParseContext.getUser());
|
||||||
if (QueryManager.isTagQuery(queryMode)
|
if (QueryManager.isTagQuery(queryMode)
|
||||||
|| QueryManager.isMetricQuery(queryMode)) {
|
|| QueryManager.isMetricQuery(queryMode)) {
|
||||||
parseInfo.setEntityInfo(entityInfo);
|
parseInfo.setEntityInfo(entityInfo);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user