Repository: ambition119/chatBI
Branch: master
Commit: 785185c9a6a2
Files: 35
Total size: 51.4 KB
Directory structure:
gitextract_nqa06b_p/
├── .gitignore
├── README.md
├── chat_rest/
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── com/
│ │ └── am/
│ │ └── chat/
│ │ └── bi/
│ │ ├── ChatBIApplication.java
│ │ ├── comm/
│ │ │ ├── AppCode.java
│ │ │ ├── ErrorCode.java
│ │ │ ├── Result.java
│ │ │ ├── ResultMeta.java
│ │ │ ├── StateCode.java
│ │ │ └── Utils.java
│ │ ├── config/
│ │ │ └── SwaggerConfiguration.java
│ │ ├── controller/
│ │ │ └── LLMsController.java
│ │ ├── domain/
│ │ │ ├── dao/
│ │ │ │ └── SchemaMetaInfo.java
│ │ │ └── vo/
│ │ │ └── ResponseVo.java
│ │ └── service/
│ │ ├── LLMsService.java
│ │ └── impl/
│ │ └── LLMsServiceImpl.java
│ ├── resources/
│ │ ├── application-dev.yml
│ │ ├── application.yml
│ │ ├── assembly.xml
│ │ ├── dev/
│ │ │ └── setenv.sh
│ │ ├── logback-dev.xml
│ │ ├── logback.xml
│ │ ├── press/
│ │ │ └── setenv.sh
│ │ ├── prod/
│ │ │ └── setenv.sh
│ │ ├── sql/
│ │ │ └── mysql.sql
│ │ └── test/
│ │ └── setenv.sh
│ └── shell/
│ ├── comm.sh
│ ├── start.sh
│ └── stop.sh
├── chat_ui/
│ └── pom.xml
├── plugins/
│ ├── pom.xml
│ └── src/
│ └── main/
│ └── java/
│ └── com/
│ └── am/
│ └── chat/
│ └── bi/
│ └── utils/
│ ├── AliLLMsUtil.java
│ ├── LLMsResultUtil.java
│ └── PromptUtil.java
└── pom.xml
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.idea
target
*.iml
.DS_Store
================================================
FILE: README.md
================================================
自定义BI改变了传统IT主导开发固定报表的时代,让数据能够即席分析达到所见即所得,随着大模型的兴起与火热,LLMs 结合数据可视化技术,通过问答的方式能够让系统智能与数据交互与生成图表,无论是BI copilot还是ChatBI, 除了替代之前小助手功能只能查询已有报表数据外,更多的是省略创建dashboard的时候图表的拖拉拽操作,让系统自动生成的图表能够在dashboard中布局应用。

#### 一、实现思路主要考虑
1、如果没有大模型或者大模型服务宕机,自动化生成可视化工程化就不能实现?
—— 直接解耦,大模型不能影响主体工程,图表这块不能大模型生成。
2、如果大模型正常服务能够推理,是否所有的问答都要经过推理服务?
—— 大模型的推理是否那么靠谱稳定、对应响应的耗时以及对应采用商业大模型服务的费用成本因素。
3、以SQL交互为核心的配套组件,通过系统化的工程来达到生产可用要求。
借鉴[SQLChat](https://github.com/sqlchat/sqlchat), [DB-GPT](https://github.com/csunny/DB-GPT), 的开源项目思路,确定以SQL生成为核心,和数据库交互获取数据,通过data + 可视化图表组件方式实现。不考虑大模型自动生成图表的方式,主要考虑一是美观,二是灵活性,三最主要的是性能是否可控,尤其是大量查询的data很大时,是否分页等可以手动人为干预控制;而靠大模型自动生成图表类似markdown/html估计不会很理想。
#### 二、主要思路框架

#### 三、说明
1、是否有表,指标字段,维度字段列级的查询权限,以及行级 ${input_dim_conditions} <= ${user_has_permission},否直接报权限不足。
2、如果维度、度量,都来自于一张表,解析查询条件,然后sql模版组装:
```sql
select ${input_dim_names} , ${input_metric_names} from ${get_meta_table_name} where ${input_dim_conditions} [group by $s] [order by $s];
```
这种sql组装拼接成熟度很高,不一定直接依赖大模型服务,唯一有难点的就是文本中对应条件的解析。
3、 如果维度、度量都来自于多张表,则查找相似匹配的问题对应的答案Sql:
①、如果有对应sql, 则直接应用,可能只组装的就是sql的where条件。
②、如果有相似sql, 例如2张表的join找2张表join的sql模版则对应需要增加子查询方式与拼接where, 即
```sql
select ${input_dim_names} , ${input_metric_names} from ( ${get_query_sql} ) TT where ${input_dim_conditions} [group by $s] [order by $s];
```
**属于可选步骤(也可以直接调用大模型能力)**,这里where一般可以,sql引擎都支持谓词下推,但是子查询多列可能带来性能影响,不是所有的sql引擎都支持列剪裁。 同时注意相似如果是2张表join,则不能找3张表join的sql语句去拼接。
③、如果sql为null或者校验error的sql, 则通过提示词(问题、schema)交给大模型推理返回推理生成查询sql。
整体框架可能存在不足,但是相信随着时间的进步,大模型会越来越稳定可靠,响应快 以及细分领域SQL LLMs的诞生;也相信利他主义的开源者,会诞生更优秀的ChatBI项目。
#### 四、模块结构
|--rest api层
|-- server 服务层,调用解析,执行sql,和数据库交互
|-- mapper 元数据匹配
|--validate sql校验
|--common
|--parse 文本解析
|--plugins 大模型插件,和大模型交互,智能生成
================================================
FILE: chat_rest/pom.xml
================================================
chatBI
com.am
1.0-SNAPSHOT
4.0.0
chat_rest
org.springframework.boot
spring-boot-starter
logback-classic
ch.qos.logback
org.springframework.boot
spring-boot-starter-web
org.springframework
spring-context-support
org.springframework.boot
spring-boot-starter-websocket
org.springframework.boot
spring-boot-configuration-processor
true
org.springframework.boot
spring-boot-starter-test
test
io.springfox
springfox-swagger2
io.springfox
springfox-swagger-ui
com.github.pagehelper
pagehelper-spring-boot-starter
mybatis-spring-boot-starter
org.mybatis.spring.boot
org.mybatis.spring.boot
mybatis-spring-boot-starter
org.springframework.boot
spring-boot-starter
com.alibaba
druid-spring-boot-starter
mysql
mysql-connector-java
runtime
org.mybatis.spring.boot
mybatis-spring-boot-starter-test
org.projectlombok
lombok
org.apache.commons
commons-lang3
ch.qos.logback
logback-classic
logback-core
ch.qos.logback
ch.qos.logback
logback-core
redis.clients
jedis
com.google.code.gson
gson
com.am
plugins
compile
1.0-SNAPSHOT
dev
dev
true
test
test
prod
prod
press
press
${project.artifactId}
src/main/java
src/main/shell
src/main/resources
*.xml
**/*.xml
*.yml
static/
templates/
mapper/
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.2
mysql
mysql-connector-java
5.1.38
Generate MyBatis Artifacts
none
generate
src/main/resources/generatorConfig.xml
true
org.apache.maven.plugins
maven-jar-plugin
3.0.2
false
true
lib/
${start-class}
config/
*.xml
*.conf
*.yml
*.properties
org.apache.maven.plugins
maven-assembly-plugin
src/main/resources/assembly.xml
false
make-assembly
package
single
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/ChatBIApplication.java
================================================
package com.am.chat.bi;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan
@MapperScan(basePackages = { "com.am.chat.bi.dao" })
public class ChatBIApplication {
private static final Logger LOG = LoggerFactory.getLogger(ChatBIApplication.class);
public static void main(String[] args) {
SpringApplication.run(ChatBIApplication.class, args);
LOG.info("ChatBIApplication start run!");
}
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/comm/AppCode.java
================================================
package com.am.chat.bi.comm;
/**
* @author wpl
* 后期数据库配置
*/
public enum AppCode {
VSKIT(1, "vskit")
;
private int code;
private String appName;
AppCode(int code, String appName) {
this.code = code;
this.appName = appName;
}
public int getCode() {
return code;
}
public String getAppName() {
return appName;
}
public static String getAppName(int code) {
switch (code){
case 1:
case 2:
default:
return VSKIT.getAppName();
}
}
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/comm/ErrorCode.java
================================================
package com.am.chat.bi.comm;
/**
* @author wpl
*/
public enum ErrorCode {
SUCCESS(1000, "success"),
FAIL(1010, "fail"),
FAIL_LLMs(1020, "fail LLMs"),
FAIL_INSERT(1001, "fail insert"),
FAIL_UPDATE(1002, "fail update"),
FAIL_SELECT(1003, "fail select"),
FAIL_UPLOAD(1004, "fail upload"),
FAIL_EXPORT(1005, "fail export"),
FAIL_DEL(1006, "fail delete"),
FAIL_RUN_TASK(1007, "fail run task"),
;
private int code;
private String msg;
ErrorCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/comm/Result.java
================================================
package com.am.chat.bi.comm;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* @author wpl
*/
@Data
@ApiModel
public class Result {
@ApiModelProperty(value = "元数据", required = true)
private ResultMeta meta;
@ApiModelProperty(value = "返回结果")
private T response;
public Result() {}
private Result(ErrorCode errorCode) {
this.meta = new ResultMeta(errorCode);
}
public static Result success() {
return new Result<>(ErrorCode.SUCCESS);
}
public static Result fail(ErrorCode errorCode) {
return new Result<>(errorCode);
}
public static boolean isSuccess(Result result) {
return result != null && result.meta != null && result.meta.getCode() == 0;
}
public Result withErrorMsg(String msg) {
this.meta.setMsg(msg);
return this;
}
public Result withResponse(T response) {
this.response = response;
return this;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/comm/ResultMeta.java
================================================
package com.am.chat.bi.comm;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author: wpl
*/
@Data
@ApiModel
public class ResultMeta {
@ApiModelProperty(value = "错误码", required = true)
private int code;
@ApiModelProperty(value = "描述", required = true)
private String msg;
public ResultMeta() {}
public ResultMeta(ErrorCode errorCode) {
this.code = errorCode.getCode();
this.msg = errorCode.getMsg();
}
void setMsg(String msg) {
this.msg = this.msg + " : " + msg;
}
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/comm/StateCode.java
================================================
package com.am.chat.bi.comm;
/**
* @author wpl
*/
public enum StateCode {
IS_ADD(0),
IS_UPDATE(1),
IS_DEL(2)
;
private Integer code;
StateCode(Integer code) {
this.code = code;
}
public static StateCode getStateCode(Integer code) {
switch (code){
case 1:
return IS_UPDATE;
case 2:
return IS_DEL;
default:
return IS_ADD;
}
}
public Integer getCode() {
return code;
}
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/comm/Utils.java
================================================
package com.am.chat.bi.comm;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.atomic.AtomicLong;
public class Utils {
private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
public static String getStringDate(Date date) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(date);
return dateString;
}
public static Date getStringToDate(String date) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date result = formatter.parse(date);
return result;
} catch (ParseException e) {
e.printStackTrace();
LOG.error("string date 解析出错", e);
}
return null;
}
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/config/SwaggerConfiguration.java
================================================
package com.am.chat.bi.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @author wpl
*/
@EnableSwagger2
@Configuration
public class SwaggerConfiguration {
@Value("${com.am.chat.bi.api.doc.path:com.am.chat.bi}")
private String path;
@Value("${com.am.chat.bi.api.doc.title:Chat BI Platform API doc}")
private String title;
@Value("${com.am.chat.bi.api.doc.version:1.0}")
private String version;
@Value("${com.am.chat.bi.api.doc.description:Chat BI Platform API doc}")
private String description;
@Bean
public Docket createApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.pathMapping("/")
.select()
.apis(RequestHandlerSelectors.basePackage(path))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(title)
.description(description)
.version(version)
.build();
}
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/controller/LLMsController.java
================================================
package com.am.chat.bi.controller;
import com.am.chat.bi.comm.Result;
import com.am.chat.bi.service.LLMsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/chat")
@Api(value = "大模型服务", description = "大模型服务", tags = {"LLMs APIß"})
public class LLMsController {
@Autowired
LLMsService llMsService;
@PostMapping(value = "/intention", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ApiOperation(value = "查询意图", notes = "查询意图", response = Result.class)
public ResponseEntity> intention(@RequestBody String queryContent) {
Result result = llMsService.getIntention(queryContent);
return new ResponseEntity<>(result, HttpStatus.OK);
}
@PostMapping(value = "/dimMetrics", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ApiOperation(value = "查询维度指标", notes = "查询维度指标", response = Result.class)
public ResponseEntity> dimMetrics(@RequestBody String queryContent) {
Result result = llMsService.getDimMetric(queryContent);
return new ResponseEntity<>(result, HttpStatus.OK);
}
@PostMapping(value = "/querySql", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ApiOperation(value = "生成查询sql", notes = "生成查询sql", response = Result.class)
public ResponseEntity> querySql(@RequestBody String queryContent) {
Result result = llMsService.getSql(queryContent);
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/domain/dao/SchemaMetaInfo.java
================================================
package com.am.chat.bi.domain.dao;
public class SchemaMetaInfo {
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/domain/vo/ResponseVo.java
================================================
package com.am.chat.bi.domain.vo;
import lombok.Data;
/**
* @author wpl
* @param
*/
@Data
public class ResponseVo {
//返回插入或者修改的主键id
private String name;
private T value;
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/service/LLMsService.java
================================================
package com.am.chat.bi.service;
import com.am.chat.bi.comm.Result;
public interface LLMsService {
Result getIntention(String queryContent);
Result getDimMetric(String queryContent);
Result getSql(String queryContent);
}
================================================
FILE: chat_rest/src/main/java/com/am/chat/bi/service/impl/LLMsServiceImpl.java
================================================
package com.am.chat.bi.service.impl;
import com.am.chat.bi.comm.ErrorCode;
import com.am.chat.bi.comm.Result;
import com.am.chat.bi.domain.vo.ResponseVo;
import com.am.chat.bi.service.LLMsService;
import com.am.chat.bi.utils.AliLLMsUtil;
import com.am.chat.bi.utils.LLMsResultUtil;
import com.am.chat.bi.utils.PromptUtil;
import com.google.gson.JsonElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class LLMsServiceImpl implements LLMsService {
private static final Logger LOG = LoggerFactory.getLogger(LLMsServiceImpl.class);
@Override
public Result getIntention(String queryContent) {
LOG.info("chat query content: {}", queryContent);
try {
String intentionPrompt = PromptUtil.getIntentionPrompt(queryContent);
String intentionResult = AliLLMsUtil.getResult(intentionPrompt);
String result = LLMsResultUtil.getIntentionResult(intentionResult);
ResponseVo responseVo = new ResponseVo();
responseVo.setName("result");
responseVo.setValue(result);
return Result.success().withResponse(responseVo);
} catch (Exception e) {
LOG.error("用户查询意图大模型结果判断异常:", e);
return Result.fail(ErrorCode.FAIL_LLMs).withErrorMsg(e.getMessage());
}
}
@Override
public Result getDimMetric(String queryContent) {
LOG.info("chat query content: {}", queryContent);
try {
String dimensionMetricPrompt = PromptUtil.getDimensionMetricPrompt(queryContent);
String dimensionMetricResult = AliLLMsUtil.getResult(dimensionMetricPrompt);
String dimMetricJson = LLMsResultUtil.getDimMetricJson(dimensionMetricResult);
JsonElement dimensions = LLMsResultUtil.getJsonValue(dimMetricJson, "dimensions");
JsonElement metrics = LLMsResultUtil.getJsonValue(dimMetricJson, "metrics");
ResponseVo responseVo = new ResponseVo();
responseVo.setName("dimensions");
responseVo.setValue(dimensions);
responseVo.setName("metrics");
responseVo.setValue(metrics);
return Result.success().withResponse(responseVo);
} catch (Exception e) {
LOG.error("用户查询大模型维度指标解析异常:", e);
return Result.fail(ErrorCode.FAIL_LLMs).withErrorMsg(e.getMessage());
}
}
@Override
public Result getSql(String queryContent) {
LOG.info("chat query content: {}", queryContent);
try {
//TODO: 待补充数据库类型,基于解析的元数据信息
String schemaInfo = "{\n" +
" \"schema\":\"report_db\",\n" +
" \"tables\":[\n" +
" \"dim_table\",\n" +
" \"metric_table\"\n" +
" ],\n" +
" \"dim_table\":[\n" +
" {\n" +
" \"dim_date\":\"date\",\n" +
" \"dim_app_id\":\"int\",\n" +
" \"dim_app_name\":\"varchar\"\n" +
" },\n" +
" {\n" +
" \"count_date\":\"date\",\n" +
" \"app_id\":\"int\",\n" +
" \"app_pv\":\"bigint\",\n" +
" \"app_uv\":\"bigint\"\n" +
" }\n" +
" ]\n" +
"}";
String sqlPrompt = PromptUtil.getSqlPrompt(queryContent,"postgresql",schemaInfo, null);
LOG.info("LLMs sql prompt content: {}", sqlPrompt);
String sqlResult = AliLLMsUtil.getResult(sqlPrompt);
String result = LLMsResultUtil.getSqlResult(sqlResult);
ResponseVo responseVo = new ResponseVo();
responseVo.setName("result");
responseVo.setValue(result);
return Result.success().withResponse(responseVo);
} catch (Exception e) {
LOG.error("用户查询大模型生成sql异常:", e);
return Result.fail(ErrorCode.FAIL_LLMs).withErrorMsg(e.getMessage());
}
}
}
================================================
FILE: chat_rest/src/main/resources/application-dev.yml
================================================
server:
port: 8498
security:
basic:
enabled=false:
spring:
datasource:
name: dev
url: jdbc:mysql://127.0.0.1:3306/chat_bi?characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true
username: root
password: 123456
================================================
FILE: chat_rest/src/main/resources/application.yml
================================================
server:
context-path: /chatBI
tomcat:
accesslog:
enabled: false
buffered: false
directory:
pattern: common
awaitTerminationInSec: 30
spring:
profiles:
## dev, test, prod
active: dev
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
druid:
filters:
# 初始化大小,最小,最大
initial-size: 1
max-active: 20
min-idle: 1
# 配置获取连接等待超时的时间
max-wait: 5000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 30000
validation-query: select 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-open-prepared-statements: 20
# 配置监控页面密码登录
# stat-view-servlet:
# login-password: druid
# login-username: druid
http:
multipart:
max-file-size: 1024MB
max-request-size: 1024MB
mybatis:
mapperLocations: classpath:mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
pagehelper:
helperDialect: mysql
reasonable: true
management:
health:
redis:
enabled: false
================================================
FILE: chat_rest/src/main/resources/assembly.xml
================================================
${project.version}
tar.gz
true
lib
false
${project.basedir}
/
README*
LICENSE*
NOTICE*
src/main/resources
config/
*.xml
*.yml
static/
templates/
mapper/
logback-test.xml
generatorConfig.xml
application-*.yml
src/main/resources
config/
application-${env}.yml
${project.build.scriptSourceDirectory}
bin
*.*
true
0755
src/main/resources/${env}
bin
setenv.sh
${project.build.directory}
*.jar
================================================
FILE: chat_rest/src/main/resources/dev/setenv.sh
================================================
#!/bin/sh
PRG="$0"
PRGDIR=`dirname "$PRG"`
BASE_HOME=`cd "$PRGDIR/.." >/dev/null; pwd`
#server内存配置
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -server -Xms1G -Xmx1G -Xmn512M -XX:PermSize=128M -XX:MaxPermSize=256M -Xss512k -XX:SurvivorRatio=8"
#gc
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -XX:MaxTenuringThreshold=4 -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=2 -XX:+ExplicitGCInvokesConcurrent -XX:+CMSScavengeBeforeRemark"
#gc日志
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -Xloggc:$BASE_HOME/logs/jvm/gc.log.`date +%Y-%m-%d_%H_%M_%S` \
-XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:PrintFLSStatistics=1"
#内存溢出
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$BASE_HOME/logs/heapdump.hprof"
================================================
FILE: chat_rest/src/main/resources/logback-dev.xml
================================================
UTF-8
%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
================================================
FILE: chat_rest/src/main/resources/logback.xml
================================================
UTF-8
%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
INFO
DEBUG
${log.home}/label_%d{yyyy-MM-dd}_%i.log
100MB
7
10GB
UTF-8
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
================================================
FILE: chat_rest/src/main/resources/press/setenv.sh
================================================
#!/bin/sh
PRG="$0"
PRGDIR=`dirname "$PRG"`
BASE_HOME=`cd "$PRGDIR/.." >/dev/null; pwd`
#server内存配置
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -server -Xms4G -Xmx4G -Xmn2G -XX:PermSize=256M -XX:MaxPermSize=512M -Xss1M -XX:SurvivorRatio=8"
#gc
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -XX:MaxTenuringThreshold=4 -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=2 -XX:+ExplicitGCInvokesConcurrent -XX:+CMSScavengeBeforeRemark"
#gc日志
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -Xloggc:$BASE_HOME/logs/jvm/gc.log.`date +%Y-%m-%d_%H_%M_%S` \
-XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:PrintFLSStatistics=1"
#内存溢出
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$BASE_HOME/logs/heapdump.hprof"
================================================
FILE: chat_rest/src/main/resources/prod/setenv.sh
================================================
#!/bin/sh
PRG="$0"
PRGDIR=`dirname "$PRG"`
BASE_HOME=`cd "$PRGDIR/.." >/dev/null; pwd`
#server内存配置
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -server -Xms4G -Xmx4G -Xmn2G -XX:PermSize=256M -XX:MaxPermSize=512M -Xss1M -XX:SurvivorRatio=8"
#gc
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -XX:MaxTenuringThreshold=4 -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=2 -XX:+ExplicitGCInvokesConcurrent -XX:+CMSScavengeBeforeRemark"
#gc日志
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -Xloggc:$BASE_HOME/logs/jvm/gc.log.`date +%Y-%m-%d_%H_%M_%S` \
-XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:PrintFLSStatistics=1"
#内存溢出
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$BASE_HOME/logs/heapdump.hprof"
================================================
FILE: chat_rest/src/main/resources/sql/mysql.sql
================================================
USE chat_bi;
DROP TABLE IF EXISTS `scheam_meta_info`;
CREATE TABLE `scheam_meta_info` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`meta_name` varchar(64) NOT NULL COMMENT '维度,指标名称',
`meta_zh_name` varchar(128) NOT NULL COMMENT '维度,指标中文名称',
`meta_type` int(1) NOT NULL DEFAULT '1' COMMENT '维度1,指标2',
`meta_expression` varchar(128) DEFAULT NULL COMMENT '维度,指标表达式',
`meta_table_name` varchar(64) DEFAULT NULL COMMENT '维度,指标来源表名称',
`meta_state` int(1) NOT NULL DEFAULT '0' COMMENT '操作类型,0:新增,1:更新,2:删除',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='维度指标元数据信息表';
================================================
FILE: chat_rest/src/main/resources/test/setenv.sh
================================================
#!/bin/sh
PRG="$0"
PRGDIR=`dirname "$PRG"`
BASE_HOME=`cd "$PRGDIR/.." >/dev/null; pwd`
#server内存配置
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -d64 -server -Xms4G -Xmx4G -Xmn2G -XX:PermSize=256M -XX:MaxPermSize=512M -Xss1M -XX:SurvivorRatio=8"
#gc
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -XX:MaxTenuringThreshold=4 -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=2 -XX:+ExplicitGCInvokesConcurrent -XX:+CMSScavengeBeforeRemark"
#gc日志
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -Xloggc:$BASE_HOME/logs/jvm/gc.log.`date +%Y-%m-%d_%H_%M_%S` \
-XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:PrintFLSStatistics=1"
#内存溢出
export JAVA_MEM_OPTS="$JAVA_MEM_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$BASE_HOME/logs/heapdump.hprof"
================================================
FILE: chat_rest/src/main/shell/comm.sh
================================================
#!/bin/sh
# resolve links - $0 may be a softlink
PRG="$0"
while [ -h "$PRG" ]; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi
done
COMMAND="$1"
# Get standard environment variables
PRG_DIR=`dirname "$PRG"`
PLATFORM_HOME=`cd "$PRG_DIR/.." >/dev/null; pwd`
export PLATFORM_HOME
PLATFORM_CONF_DIR="$PLATFORM_HOME/config"
PLATFORM_LIB_DIR="$PLATFORM_HOME/lib"
export PLATFORM_LIB_DIR
LIB_JARS=`ls $PLATFORM_LIB_DIR | grep -E '.jar$' | awk '{print "'$PLATFORM_LIB_DIR'/"$0}' | tr "\n" ":"`
PRO_NAME=${project.artifactId}
PIDFILE="$PLATFORM_HOME/$(basename $PRO_NAME).pid"
PID=0
if [[ -f $PIDFILE ]]; then
PID=`cat $PIDFILE`
fi
JAVA_OPTS=""
JAVA_MEM_OPTS=""
JAVA_SPRING_OPTS=" --spring.profiles.active=${env}"
PLATFORM_MAIN_CLASS=${start-class}
running() {
if [[ -z $1 || $1 == 0 ]]; then
echo 0
return
fi
if ps -p $1 > /dev/null; then
echo 1
return
fi
echo 0
return
}
set_env() {
if [ -r "$PLATFORM_HOME/bin/setenv.sh" ]; then
source "$PLATFORM_HOME/bin/setenv.sh"
else
JAVA_MEM_OPTS=" -server -Xms4g -Xmx4g -XX:SurvivorRatio=2 -XX:+UseParallelGC "
fi
}
start() {
if [[ $(running $PID) != 0 ]]; then
echo "$PRO_NAME is running"
return
fi
echo "### starting $PRO_NAME `date '+%Y-%m-%d %H:%M:%S'` ###" >> /dev/null 2>&1 &
set_env
echo "$JAVA_HOME/bin/java $JAVA_OPTS $JAVA_MEM_OPTS -classpath $PLATFORM_CONF_DIR:$LIB_JARS $PLATFORM_MAIN_CLASS $JAVA_SPRING_OPTS"
START_CMD="$JAVA_HOME/bin/java $JAVA_OPTS $JAVA_MEM_OPTS -classpath $PLATFORM_CONF_DIR:$LIB_JARS $PLATFORM_MAIN_CLASS $JAVA_SPRING_OPTS"
print_env
nohup $START_CMD >> $PLATFORM_HOME/server.log 2>&1 &
if [[ $(running $!) == 0 ]]; then
echo "failed to start $PRO_NAME"
exit 1
fi
PID=$!
echo $! > $PIDFILE
# echo "new pid $!"
}
stop() {
if [[ $(running $PID) == 0 ]]; then
echo "no $PRO_NAME is running"
return
fi
echo "stopping $PID of $PRO_NAME ..."
kill $PID
}
restart() {
stop
start
}
print_env() {
echo "JRE_HOME: $JAVA_HOME"
echo "ENV: ${env}"
echo "JAVA_OPTS: $JAVA_OPTS"
echo "JAVA_MEM_OPTS: $JAVA_MEM_OPTS"
echo "JAVA_SPRING_OPTS: $JAVA_SPRING_OPTS"
echo "START_CMD: $START_CMD"
}
print_usage() {
echo "Usage: label.sh (start|stop)"
}
case $COMMAND in
(start)
start
;;
(stop)
stop
;;
(*)
print_usage
exit 1
;;
esac
================================================
FILE: chat_rest/src/main/shell/start.sh
================================================
#!/bin/sh
PRG="$0"
PRGDIR=`dirname "$PRG"`
PLATFORM_HOME=`cd "$PRGDIR/.." >/dev/null; pwd`
EXECUTABLE=comm.sh
exec "$PRGDIR"/"$EXECUTABLE" start "$@"
================================================
FILE: chat_rest/src/main/shell/stop.sh
================================================
#!/bin/sh
PRG="$0"
PRGDIR=`dirname "$PRG"`
PLATFORM_HOME=`cd "$PRGDIR/.." >/dev/null; pwd`
EXECUTABLE=comm.sh
exec "$PRGDIR"/"$EXECUTABLE" stop "$@"
================================================
FILE: chat_ui/pom.xml
================================================
chatBI
com.am
1.0-SNAPSHOT
4.0.0
chat_ui
================================================
FILE: plugins/pom.xml
================================================
chatBI
com.am
1.0-SNAPSHOT
4.0.0
plugins
plugins
com.google.code.gson
gson
com.alibaba
dashscope-sdk-java
ch.qos.logback
logback-classic
ch.qos.logback
logback-core
================================================
FILE: plugins/src/main/java/com/am/chat/bi/utils/AliLLMsUtil.java
================================================
package com.am.chat.bi.utils;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.aigc.generation.models.QwenParam;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.utils.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Semaphore;
public class AliLLMsUtil {
private static final Logger LOG = LoggerFactory.getLogger(AliLLMsUtil.class);
static {
Constants.apiKey = "sk-547";
}
public static String getResult(String prompt) throws Exception {
Generation gen = new Generation();
QwenParam param = QwenParam.builder().model(Generation.Models.QWEN_TURBO).prompt(prompt)
.topP(0.8).build();
Semaphore semaphore = new Semaphore(0);
final String[] result = {null};
gen.call(param, new ResultCallback() {
@Override
public void onEvent(GenerationResult message) {
System.out.println(message);
result[0] = message.getOutput().getText();
LOG.info("阿里大模型返回结果:{}",message);
}
@Override
public void onError(Exception ex){
System.out.println(ex.getMessage());
semaphore.release();
}
@Override
public void onComplete(){
System.out.println("onComplete");
semaphore.release();
}
});
semaphore.acquire();
return result[0];
}
}
================================================
FILE: plugins/src/main/java/com/am/chat/bi/utils/LLMsResultUtil.java
================================================
package com.am.chat.bi.utils;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LLMsResultUtil {
public static String getIntentionResult(String result){
String intentionResult = null;
Pattern pattern = Pattern.compile("(\\d+)");
Matcher matcher = pattern.matcher(result);
if (matcher.find()) {
intentionResult = matcher.group();
}
return intentionResult;
}
public static JsonElement getJsonValue(String result, String name) {
JsonParser parser = new JsonParser();
JsonObject jsonObject = parser.parse(result).getAsJsonObject();
return jsonObject.get(name);
}
public static String getDimMetricJson(String result){
String sqlResult = null;
// Pattern pattern = Pattern.compile("```json(.*?)```");
Pattern pattern = Pattern.compile("\\{.*\\}");
Matcher matcher = pattern.matcher(result);
if (matcher.find()) {
sqlResult = matcher.group();
}
return sqlResult;
}
public static String getSqlResult(String result){
String sqlResult = null;
Pattern pattern = Pattern.compile("querySql: \"(.*?)\"}");
Matcher matcher = pattern.matcher(result);
if (matcher.find()) {
sqlResult = matcher.group();
}
return sqlResult;
}
}
================================================
FILE: plugins/src/main/java/com/am/chat/bi/utils/PromptUtil.java
================================================
package com.am.chat.bi.utils;
public class PromptUtil {
/**
* 查询意图
* @param queryContent
* @return
*/
public static String getIntentionPrompt(String queryContent) {
String intentionPrompt = "“" + queryContent + "” 请帮忙判断这句话的意图是需要" +
"知识库还是数据查询。如果意图是知识库的话result返回值是1,是数据查询的话result返回值是2。" +
"最后返回值采用json数据格式,返回值格式为{result:result_$返回值}"
;
return intentionPrompt;
}
public static String getDimensionMetricPrompt(String queryContent) {
String dimMetricPrompt = "“" + queryContent + "” 请帮忙解析这句话中含有的维度与指标。解析要求:" +
"1,语句中除了指标名词外,默认其他名词为维度。" +
"2,最后的返回结果采用json数据格式,指定返回格式为{dimensions:array[$维度名称],metrics:array[$指标名称]}。";
return dimMetricPrompt;
}
public static String getSqlPrompt(String queryContent, String dbType, String schemaInfo, String dbDialect) {
String sqlPrompt = "假设你是"+dbType+"的专家,需要通过问题描述和指令语句两部分内容帮忙生成对应查询SQL语句。第一部分问题说明:\n" +
"“" + queryContent + "” \n" +
"第二部分指令内容:\n" +
"1,不能幻觉出现新的字段,schema字段、表名称、表字段名称必须使用提供的元数据内容信息,元数据信息json格式数据 " + schemaInfo + " \n" +
"2,可能需要关联表的查询SQL才满足问题内容的要求,关联的表和表字段一定存在已经提供的元数据内容。\n" +
"3,生产的sql语句使用json格式返回,返回数据格式要求{querySQL: $生成的结果SQL}。";
return sqlPrompt;
}
}
================================================
FILE: pom.xml
================================================
4.0.0
com.am
chatBI
pom
1.0-SNAPSHOT
chat_rest
chat_ui
plugins
UTF-8
8
8
1.5.9.RELEASE
4.3.13.RELEASE
1.3.2
1.1.10
1.1.1
3.7
1.2.47
2.7.0
1.2.3
1.18.0
2.7.2
5.1.46
org.springframework.boot
spring-boot-starter
${spring-boot-starter-parent}
logback-classic
ch.qos.logback
org.springframework.boot
spring-boot-starter-web
${spring-boot-starter-parent}
org.springframework
spring-context-support
${spring-content.version}
org.springframework.boot
spring-boot-starter-websocket
${spring-boot-starter-parent}
org.springframework.boot
spring-boot-configuration-processor
${spring-boot-starter-parent}
true
org.springframework.boot
spring-boot-starter-test
${spring-boot-starter-parent}
test
io.springfox
springfox-swagger2
${swagger.version}
io.springfox
springfox-swagger-ui
${swagger.version}
com.github.pagehelper
pagehelper-spring-boot-starter
${pagehelper}
mybatis-spring-boot-starter
org.mybatis.spring.boot
org.mybatis.spring.boot
mybatis-spring-boot-starter
${mybatis-spring-boot-starter}
org.springframework.boot
spring-boot-starter
com.alibaba
druid-spring-boot-starter
${druid}
mysql
mysql-connector-java
${mysql.version}
org.mybatis.spring.boot
mybatis-spring-boot-starter-test
${mybatis-spring-boot-starter}
org.projectlombok
lombok
${lombok.version}
org.apache.commons
commons-lang3
${commons-lang3}
ch.qos.logback
logback-classic
${logback.version}
logback-core
ch.qos.logback
ch.qos.logback
logback-core
${logback.version}
com.google.code.gson
gson
2.10.1
com.alibaba
dashscope-sdk-java
2.6.1
redis.clients
jedis
${redis.version}