diff --git a/Jenkinsfile b/Jenkinsfile
index 079e0d48..0ebb8c08 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -19,7 +19,7 @@ pipeline {
sh "which java"
echo "打包子目录并进行代码检查 ${project_name}"
sh "mvn clean install"
- sh "mvn -f ${project_name} clean package -e -U -Dmaven.test.skip=true -Dsonar.login=admin -Dsonar.password=Digimeta@2023 sonar:sonar"
+ sh "mvn -f ${project_name} clean package -e -U -Dmaven.test.skip=true -P${build_env} -Dsonar.login=admin -Dsonar.password=Digimeta@2023 sonar:sonar"
}
}
}
@@ -31,8 +31,10 @@ pipeline {
def workspace=pwd()
// 删除所有report报告
sh "find ${workspace} -name report-task.txt | xargs rm -f"
+ // 删除所有sonar锁
+ sh "find ${workspace} -name .sonar_lock | xargs rm -f"
}
- timeout(time: 15, unit: 'MINUTES') {
+ timeout(time: 5, unit: 'MINUTES') {
// Parameter indicates whether to set pipeline to UNSTABLE if Quality Gate fails
// true = set pipeline to UNSTABLE, false = don't waitForQualityGates abortPipeline: true
waitForQualityGate abortPipeline: true
@@ -55,9 +57,9 @@ pipeline {
sh """
cd ${workspace}/${project_name}
docker login --username=缔智元2023 --password=digimeta@2023 ${ali_registry}
- docker build --tag ${ali_registry}/digitalman-multisaas/${module_name}:${version} .
- docker push ${ali_registry}/digitalman-multisaas/${module_name}:${version}
- docker rmi ${ali_registry}/digitalman-multisaas/${module_name}:${version}
+ docker build --tag ${ali_registry}/digitalman-multisaas/${module_name}:${git_version}-${build_env} .
+ docker push ${ali_registry}/digitalman-multisaas/${module_name}:${git_version}-${build_env}
+ docker rmi ${ali_registry}/digitalman-multisaas/${module_name}:${git_version}-${build_env}
"""
}
}
diff --git a/Jenkinsfile1 b/Jenkinsfile1
new file mode 100644
index 00000000..b6f9d2ce
--- /dev/null
+++ b/Jenkinsfile1
@@ -0,0 +1,67 @@
+node {
+ def workspace=pwd()
+ // 版本
+ def tag = "0.8"
+ def ali_registry = "registry.cn-beijing.aliyuncs.com"
+ // 镜像仓库的地址
+ // def harbor_url = "192.168.81.102:85"
+ // 镜像仓库的项目,这里建议项目名称和jenkins的item项目名称、以及harbor的项目名称保持一致,否则用一下脚本会出问题
+ // def harbor_project = "demo"
+ def mavenPath="/usr/share/maven"
+ // 拉取代码
+ stage('pull code') {
+ checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: '0f6d6eaa8754e735262afa495fe2828d611fca17', url: 'http://39.105.23.186:3000/develop/digimeta-MultiSaas.git']]])
+ }
+ // 代码静态检查
+ stage('Maven Package and Sonar') {
+ if ("${project_name}" == 'digimeta-MultiSaas' ) {
+ echo '打包根目录'
+ sh 'mvn clean package sonar:sonar'
+ } else {
+ echo "打包子目录并进行代码检查 ${project_name}"
+ sh "mvn clean install"
+ sh "mvn -f ${project_name} clean package -e -U -Dmaven.test.skip=true sonar:sonar"
+ }
+
+ //script {
+ //引入Jenkins SonarQube-Scanner全局工具 "全局配置中以SonarQube-Scanner命名的工具"
+ // scannerHome = tool 'SonarQube-Scanner'
+ //}
+ //引用SonarQube环境 "系统配置中配置的SonarQube servers的name值 "
+ //withSonarQubeEnv('Sonar') {
+ //执行sonar-scanner命令
+ //sh "${scannerHome}/bin/sonar-scanner"
+ // $mavenPath/bin/mvn sonar:sonar
+ //}
+ }
+ // build Docker并推送镜像仓库
+ stage('build project') {
+ if ("${project_name}" == 'digimeta-MultiSaas' ) {
+ echo '仅做代码检查,不打包目录'
+ } else {
+ echo "构件微服务 ${project_name},并推送到镜像仓库"
+ sh """
+ cd ${workspace}/${project_name}
+ docker login --username=缔智元2023 ${ali_registry}
+ docker build --tag ${ali_registry}/digitalman-multisaas/${project_name}:${version}
+ docker push ${ali_registry}/digitalman-multisaas/${project_name}:${version}
+ """
+
+ }
+ //echo "把jar上传镜像仓库"
+ //def oldImageName = "${project_name}:latest"
+ //def newImageName = "${harbor_url}/${harbor_project}/${project_name}:${tag}"
+ // 改名称 做规范
+ //sh "docker tag ${oldImageName} ${newImageName}"
+ // 删除之前的 镜像
+ //sh "docker rmi ${oldImageName}"
+ // 推送到 dockers仓库
+ //withCredentials([usernamePassword(credentialsId: '8a3d7ab1-4cd6-482c-86c9-a12aa6404d98', passwordVariable: 'harbor_password', usernameVariable: 'harbor_account')]) {
+ // 登录
+ //sh "docker login -u ${harbor_account} -p ${harbor_password} ${harbor_url}"
+ // 上传
+ //sh "docker push ${newImageName}"
+ //echo "镜像推送成功"
+ //}
+ }
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 1547fdc4..c8d4432b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -163,6 +163,11 @@
${fastjson2.version}
+
+ net.logstash.logback
+ logstash-logback-encoder
+ 7.4
+
io.jsonwebtoken
@@ -301,6 +306,12 @@
${xueyi.version}
+
+ com.xueyi
+ xueyi-api-nlt
+ ${xueyi.version}
+
+
cn.hutool
diff --git a/xueyi-api/pom.xml b/xueyi-api/pom.xml
index d5cec5ed..43a410fd 100644
--- a/xueyi-api/pom.xml
+++ b/xueyi-api/pom.xml
@@ -14,6 +14,7 @@
xueyi-api-tenant
xueyi-api-file
xueyi-api-job
+ xueyi-api-nlt
xueyi-api-modules-auth
diff --git a/xueyi-api/xueyi-api-nlt/pom.xml b/xueyi-api/xueyi-api-nlt/pom.xml
new file mode 100644
index 00000000..b42fb186
--- /dev/null
+++ b/xueyi-api/xueyi-api-nlt/pom.xml
@@ -0,0 +1,33 @@
+
+
+
+ com.xueyi
+ xueyi-api
+ 2.5.0
+
+ 4.0.0
+
+ xueyi-api-nlt
+
+
+ xueyi-api-nlt模型接入管理模块
+
+
+
+
+
+
+ com.xueyi
+ xueyi-common-core
+
+
+
+
+ com.xueyi
+ xueyi-api-system
+
+
+
+
\ No newline at end of file
diff --git a/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/netty/domain/vo/DmWebSocketMessageVo.java b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/netty/domain/vo/DmWebSocketMessageVo.java
new file mode 100644
index 00000000..2ad20b60
--- /dev/null
+++ b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/netty/domain/vo/DmWebSocketMessageVo.java
@@ -0,0 +1,13 @@
+package com.xueyi.nlt.api.netty.domain.vo;
+
+import com.alibaba.fastjson2.JSONObject;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+public class DmWebSocketMessageVo {
+ String devId;
+ String skillCode;
+ JSONObject format;
+}
diff --git a/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/netty/feign/RemoteWebsocketService.java b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/netty/feign/RemoteWebsocketService.java
new file mode 100644
index 00000000..119df79a
--- /dev/null
+++ b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/netty/feign/RemoteWebsocketService.java
@@ -0,0 +1,20 @@
+package com.xueyi.nlt.api.netty.feign;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.xueyi.common.core.constant.basic.SecurityConstants;
+import com.xueyi.common.core.constant.basic.ServiceConstants;
+import com.xueyi.common.core.web.result.R;
+import com.xueyi.nlt.api.netty.domain.vo.DmWebSocketMessageVo;
+import com.xueyi.nlt.api.nlt.domain.vo.DmIntentVo;
+import com.xueyi.nlt.api.nlt.feign.factory.RemoteIntentFallbackFactory;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+
+@FeignClient(contextId = "remoteWebsocketService", value = ServiceConstants.NLT_SERVICE, fallbackFactory = RemoteIntentFallbackFactory.class)
+public interface RemoteWebsocketService {
+
+ @PostMapping("websocket/inner/sendMessage")
+ R sendMessage(@RequestBody DmWebSocketMessageVo message, @RequestHeader(SecurityConstants.ENTERPRISE_ID) Long enterpriseId, @RequestHeader(SecurityConstants.SOURCE_NAME) String sourceName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+}
diff --git a/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/domain/vo/DmIntentVo.java b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/domain/vo/DmIntentVo.java
new file mode 100644
index 00000000..6f75e538
--- /dev/null
+++ b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/domain/vo/DmIntentVo.java
@@ -0,0 +1,16 @@
+package com.xueyi.nlt.api.nlt.domain.vo;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+public class DmIntentVo {
+ String devId;
+ Long operator;
+ String skillCode;
+ String content;
+ String preIntent;
+ String sign;
+ String requestId;
+}
diff --git a/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/domain/vo/DmRecognitionVo.java b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/domain/vo/DmRecognitionVo.java
new file mode 100644
index 00000000..39098bc9
--- /dev/null
+++ b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/domain/vo/DmRecognitionVo.java
@@ -0,0 +1,13 @@
+package com.xueyi.nlt.api.nlt.domain.vo;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+public class DmRecognitionVo {
+ String devId;
+ Long personId;
+ String registered;
+ String sign;
+}
diff --git a/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/feign/RemoteIntentService.java b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/feign/RemoteIntentService.java
new file mode 100644
index 00000000..fbb95712
--- /dev/null
+++ b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/feign/RemoteIntentService.java
@@ -0,0 +1,24 @@
+package com.xueyi.nlt.api.nlt.feign;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.xueyi.common.core.constant.basic.SecurityConstants;
+import com.xueyi.common.core.constant.basic.ServiceConstants;
+import com.xueyi.common.core.web.result.R;
+import com.xueyi.nlt.api.netty.domain.vo.DmWebSocketMessageVo;
+import com.xueyi.nlt.api.nlt.domain.vo.DmIntentVo;
+import com.xueyi.nlt.api.nlt.feign.factory.RemoteIntentFallbackFactory;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@FeignClient(contextId = "remoteIntentService", value = ServiceConstants.NLT_SERVICE, fallbackFactory = RemoteIntentFallbackFactory.class)
+public interface RemoteIntentService {
+
+ @PostMapping("/intent/inner/conversation")
+ R conversationInner(@RequestBody DmIntentVo intent, @RequestHeader(SecurityConstants.ENTERPRISE_ID) Long enterpriseId, @RequestHeader(SecurityConstants.SOURCE_NAME) String sourceName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+ @PostMapping("/intent/inner/sendMessage")
+ R sendMessage(@RequestBody DmWebSocketMessageVo message, @RequestHeader(SecurityConstants.ENTERPRISE_ID) Long enterpriseId, @RequestHeader(SecurityConstants.SOURCE_NAME) String sourceName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+}
diff --git a/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/feign/factory/RemoteIntentFallbackFactory.java b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/feign/factory/RemoteIntentFallbackFactory.java
new file mode 100644
index 00000000..a48cb1f9
--- /dev/null
+++ b/xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/feign/factory/RemoteIntentFallbackFactory.java
@@ -0,0 +1,15 @@
+package com.xueyi.nlt.api.nlt.feign.factory;
+
+import com.xueyi.nlt.api.nlt.feign.RemoteIntentService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cloud.openfeign.FallbackFactory;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class RemoteIntentFallbackFactory implements FallbackFactory {
+ @Override
+ public RemoteIntentService create(Throwable cause) {
+ return null;
+ }
+}
diff --git a/xueyi-api/xueyi-api-nlt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/xueyi-api/xueyi-api-nlt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 00000000..fcd3ba65
--- /dev/null
+++ b/xueyi-api/xueyi-api-nlt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.xueyi.nlt.api.nlt.feign.factory.RemoteIntentFallbackFactory
diff --git a/xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/RemoteMeetingService.java b/xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/RemoteMeetingService.java
index a5653282..110630ad 100644
--- a/xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/RemoteMeetingService.java
+++ b/xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/RemoteMeetingService.java
@@ -56,4 +56,7 @@ public interface RemoteMeetingService {
@GetMapping("/meeting/inner-api/recent/{deptId}/{dateStr}")
@ResponseBody
public List recent(@PathVariable(value = "deptId") Long deptId, @PathVariable(value = "dateStr") String dateStr, @RequestParam(value = "roomId", required = false) Long roomId,@RequestParam(value = "startTime", required = false) String startTime, @RequestHeader(SecurityConstants.ENTERPRISE_ID) Long enterpriseId, @RequestHeader(SecurityConstants.SOURCE_NAME) String sourceName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source) ;
+
+ @GetMapping(value = "/meeting/api/recent/{devId}/{dateStr}")
+ R> ableOrderList(@PathVariable(value = "devId") String devId, @PathVariable(value = "dateStr") String dateStr, @RequestParam(value = "roomId", required = false) Long roomId, @RequestParam(value = "startTime", required = false) String startTime);
}
\ No newline at end of file
diff --git a/xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/factory/RemoteMeetingFallbackFactory.java b/xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/factory/RemoteMeetingFallbackFactory.java
index 580a016f..bdd75b76 100644
--- a/xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/factory/RemoteMeetingFallbackFactory.java
+++ b/xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/factory/RemoteMeetingFallbackFactory.java
@@ -71,6 +71,11 @@ public class RemoteMeetingFallbackFactory implements FallbackFactory recent(Long deptId, String dateStr, Long roomId, String startTime, Long enterpriseId, String sourceName, String source) {
return null;
}
+
+ @Override
+ public R> ableOrderList(String devId, String dateStr, Long roomId, String startTime) {
+ return null;
+ }
};
}
}
\ No newline at end of file
diff --git a/xueyi-common/xueyi-common-core/src/main/java/com/xueyi/common/core/constant/basic/ServiceConstants.java b/xueyi-common/xueyi-common-core/src/main/java/com/xueyi/common/core/constant/basic/ServiceConstants.java
index 493e3e04..3c4ef333 100644
--- a/xueyi-common/xueyi-common-core/src/main/java/com/xueyi/common/core/constant/basic/ServiceConstants.java
+++ b/xueyi-common/xueyi-common-core/src/main/java/com/xueyi/common/core/constant/basic/ServiceConstants.java
@@ -26,6 +26,7 @@ public class ServiceConstants {
public static final String MESSAGE_SERVICE = "xueyi-message";
public static final String MODULES_AUTH_SERVICE = "xueyi-modules-auth";
+ public static final String NLT_SERVICE = "xueyi-nlt";
/** 定时任务模块的serviceId */
public static final String JOB_SERVICE = "xueyi-job";
diff --git a/xueyi-common/xueyi-common-mqtt/src/main/java/com/xueyi/common/mqtt/constant/MqttTopicConstant.java b/xueyi-common/xueyi-common-mqtt/src/main/java/com/xueyi/common/mqtt/constant/MqttTopicConstant.java
new file mode 100644
index 00000000..d8d1551a
--- /dev/null
+++ b/xueyi-common/xueyi-common-mqtt/src/main/java/com/xueyi/common/mqtt/constant/MqttTopicConstant.java
@@ -0,0 +1,15 @@
+package com.xueyi.common.mqtt.constant;
+
+public class MqttTopicConstant {
+
+ /**
+ * 数字人常量
+ */
+ public static final String TOPIC_DIGITALMAN = "/digitalman";
+ /**
+ * 通知重启
+ */
+ public static final String TOPIC_NOTIFY_RESTART = "notify/restart";
+
+
+}
diff --git a/xueyi-modules/pom.xml b/xueyi-modules/pom.xml
index 5f292c54..7610974a 100644
--- a/xueyi-modules/pom.xml
+++ b/xueyi-modules/pom.xml
@@ -16,6 +16,7 @@
xueyi-file
xueyi-message
xueyi-modules-auth
+ xueyi-nlt
xueyi-modules
diff --git a/xueyi-modules/xueyi-nlt/Dockerfile b/xueyi-modules/xueyi-nlt/Dockerfile
new file mode 100644
index 00000000..a72da462
--- /dev/null
+++ b/xueyi-modules/xueyi-nlt/Dockerfile
@@ -0,0 +1,17 @@
+# 基础镜像
+FROM openjdk:17-oracle
+# author
+MAINTAINER xueyi
+
+# 挂载目录
+VOLUME /home/xueyi
+# 创建目录
+RUN mkdir -p /home/xueyi
+RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
+# 指定路径
+WORKDIR /home/xueyi
+# 复制jar文件到路径
+COPY ./target/xueyi-modules-nlt.jar /home/xueyi/xueyi-modules-nlt.jar
+
+# 启动系统服务
+ENTRYPOINT ["java","-jar","xueyi-modules-nlt.jar"]
\ No newline at end of file
diff --git a/xueyi-modules/xueyi-nlt/pom.xml b/xueyi-modules/xueyi-nlt/pom.xml
new file mode 100644
index 00000000..bdac8af7
--- /dev/null
+++ b/xueyi-modules/xueyi-nlt/pom.xml
@@ -0,0 +1,117 @@
+
+
+
+ com.xueyi
+ xueyi-modules
+ 2.5.0
+
+ 4.0.0
+
+ xueyi-modules-nlt
+
+
+ xueyi-modules-nlt大模型处理模块
+
+
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 3.9.1
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+
+
+
+
+
+ com.xueyi
+ xueyi-common-log
+
+
+
+
+ com.xueyi
+ xueyi-common-web
+
+
+
+
+ com.xueyi
+ xueyi-common-swagger
+
+
+
+
+ com.xueyi
+ xueyi-api-nlt
+
+
+
+ com.xueyi
+ xueyi-api-system
+
+
+
+
+
+ ${project.artifactId}
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+ maven-resources-plugin
+ org.apache.maven.plugins
+
+ @
+ false
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
diff --git a/xueyi-modules/xueyi-nlt/sonar-project.properties b/xueyi-modules/xueyi-nlt/sonar-project.properties
new file mode 100644
index 00000000..d554b7c0
--- /dev/null
+++ b/xueyi-modules/xueyi-nlt/sonar-project.properties
@@ -0,0 +1,15 @@
+sonar.projectKey=digimeta-MultiSaas-nlt
+
+sonar.projectName=digimeta-MultiSaas-nlt
+sonar.sourceEncoding=UTF-8
+sonar.projectVersion=0.8
+
+
+
+sonar.sources=.
+sonar.exclusions=**/test/**,**/target/**
+sonar.java.binaries=.
+
+sonar.java.source=1.8
+sonar.java.target=1.8
+
diff --git a/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/XueYiNltApplication.java b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/XueYiNltApplication.java
new file mode 100644
index 00000000..146b79fa
--- /dev/null
+++ b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/XueYiNltApplication.java
@@ -0,0 +1,29 @@
+package com.xueyi.nlt;
+
+
+import com.xueyi.common.security.annotation.EnableCustomConfig;
+import com.xueyi.common.security.annotation.EnableRyFeignClients;
+import com.xueyi.common.swagger.annotation.EnableCustomSwagger;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@EnableCustomConfig
+@EnableCustomSwagger
+@EnableRyFeignClients
+@SpringBootApplication
+public class XueYiNltApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(XueYiNltApplication.class, args);
+ System.out.println("(♥◠‿◠)ノ゙ NLT模块启动成功 ლ(´ڡ`ლ)゙ \n" +
+ " _____ __ ____ __ \n" +
+ " \\ _\\ / / \\ \\ / / \n" +
+ " .-./ ). / ' \\ _. / ' \n" +
+ " \\ '_ .') .' _( )_ .' \n" +
+ " (_ (_) _) ' ___(_ o _)' \n" +
+ " / \\ \\ | |(_,_)' \n" +
+ " `-'`-' \\| `-' / \n" +
+ " / / \\ \\\\ / \n" +
+ " '--' '----'`-..-' ");
+ }
+
+}
diff --git a/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/NettyClient.java b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/NettyClient.java
new file mode 100644
index 00000000..82620267
--- /dev/null
+++ b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/NettyClient.java
@@ -0,0 +1,195 @@
+package com.xueyi.nlt.netty.client;
+
+import com.xueyi.nlt.netty.client.codec.WsChannelInitializer;
+import com.xueyi.nlt.netty.client.handler.MockClientHandler;
+import com.xueyi.nlt.netty.client.handler.NettyClientHandler;
+import com.xueyi.nlt.netty.client.handler.NettyWebsocketClientHandler;
+import com.xueyi.nlt.netty.client.message.ReceiveMessage;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http.DefaultHttpHeaders;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpServerCodec;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
+import io.netty.handler.codec.http.websocketx.WebSocketVersion;
+import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+import io.netty.handler.timeout.IdleStateHandler;
+import okhttp3.HttpUrl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
+import java.util.Base64;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+@Component
+public class NettyClient {
+ private static final Logger log = LoggerFactory.getLogger(NettyClient.class);
+ private final int PORT = 8000;
+
+
+ public static String hostUrl = "https://spark-api.xf-yun.com/v1.1/chat";
+ public static String APPID = "3d9282da";//从开放平台控制台中获取
+ public static String APIKEY = "7c217b3a313f4b66fcc14a8e97f85103";//从开放平台控制台中获取
+ public static String APISecret = "ZTRiNDQwMTRlOTlmZDQwMDUwYTdjMDM0";//从开放平台控制台中获取
+ public static NettyClient nettyClient;
+
+ private String mHost;
+
+ private int mPort;
+
+ private NettyClientHandler mClientHandler;
+
+ private ChannelFuture mChannelFuture;
+
+ /**
+ * websocket配置
+ */
+ private WebsocketConfig websocketConfig;
+
+ private Channel channel;
+
+ /**
+ * 接口消息的接口
+ */
+ private ReceiveMessage receiveMessage;
+
+
+ public void connect() {
+
+
+ EventLoopGroup workerGroup = new NioEventLoopGroup();
+ try {
+ HttpUrl authUrl = getAuthorizationUrl(hostUrl, APIKEY, APISecret);
+ String url = authUrl.toString().replace("https://","wss://").replace("http://","ws://");
+ URI uri = new URI(url);
+ final boolean ssl = "wss".equalsIgnoreCase(url);
+ final SslContext sslCtx;
+ if (ssl) {
+ sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
+ } else {
+ sslCtx = null;
+ }
+ NettyClientHandler webSocketClientHandler = new NettyClientHandler(
+ WebSocketClientHandshakerFactory.newHandshaker(authUrl.uri()
+ , WebSocketVersion.V07
+ , null
+ , false
+ , new DefaultHttpHeaders()));
+
+ final NettyWebsocketClientHandler handler =
+ new NettyWebsocketClientHandler(
+ WebSocketClientHandshakerFactory.newHandshaker(
+ authUrl.uri(), WebSocketVersion.V13, null, true, new DefaultHttpHeaders()), receiveMessage);
+
+ handler.setWebsocketConfig(websocketConfig);
+
+ Bootstrap b = new Bootstrap();
+// mClientHandler = new NettyClientHandler(webSocketClientHandler);
+// b.group(workerGroup).channel(NioSocketChannel.class)
+// // KeepAlive
+// .option(ChannelOption.SO_KEEPALIVE, true)
+// // Handler
+// .handler(new WsChannelInitializer(webSocketClientHandler));
+
+
+ b.group(workerGroup)
+ .channel(NioSocketChannel.class)
+ .handler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(SocketChannel ch) {
+ ChannelPipeline pipeline = ch.pipeline();
+ //wss 连接
+ if (sslCtx != null) {
+ pipeline.addLast(sslCtx.newHandler(ch.alloc(), authUrl.host(), authUrl.port()));
+ }
+ pipeline.addLast(
+ new HttpServerCodec(),
+ new HttpObjectAggregator(65536),
+ WebSocketClientCompressionHandler.INSTANCE,
+ //new LoggingHandler(LogLevel.INFO), // only for debug
+// new IdleStateHandler(websocketConfig.getReaderIdleTimeSeconds(),
+// websocketConfig.getWriterIdleTimeSeconds(),
+// websocketConfig.getAllIdleTimeSeconds()),
+ handler);
+ }
+ }).option(ChannelOption.SO_KEEPALIVE, true)
+
+ ;
+
+// mChannelFuture = b.connect(authUrl.host(),authUrl.port()).sync();
+ mChannelFuture = b.connect("spark-api.xf-yun.com",443).sync();
+ channel = mChannelFuture.channel();
+ handler.handshakeFuture().sync();
+ if (mChannelFuture.isSuccess()) {
+ log.info("Client,连接服务端成功");
+ }
+ channel.writeAndFlush("介绍下自己");
+// mChannelFuture.channel().closeFuture().sync();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ workerGroup.shutdownGracefully();
+ }
+ }
+
+ //鉴权url
+ public static HttpUrl getAuthorizationUrl(String hostUrl , String apikey ,String apisecret) throws Exception {
+ //获取host
+ URL url = new URL(hostUrl);
+ //获取鉴权时间 date
+ SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
+ System.out.println("format:\n" + format );
+ format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ String date = format.format(new Date());
+ //获取signature_origin字段
+ StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").
+// append("date: ").append(date).append("\n").
+ append("date: ").append("Wed, 02 Aug 2023 05:35:33 GMT").append("\n").
+ append("GET ").append(url.getPath()).append(" HTTP/1.1");
+ System.out.println("signature_origin:\n" + builder);
+ //获得signatue
+ Charset charset = Charset.forName("UTF-8");
+ Mac mac = Mac.getInstance("hmacsha256");
+ SecretKeySpec sp = new SecretKeySpec(apisecret.getBytes(charset),"hmacsha256");
+ mac.init(sp);
+ byte[] basebefore = mac.doFinal(builder.toString().getBytes(charset));
+ String signature = Base64.getEncoder().encodeToString(basebefore);
+ //获得 authorization_origin
+ String authorization_origin = String.format("api_key=\"%s\",algorithm=\"%s\",headers=\"%s\",signature=\"%s\"",apikey,"hmac-sha256","host date request-line",signature);
+ //获得authorization
+ String authorization = Base64.getEncoder().encodeToString(authorization_origin.getBytes(charset));
+ //获取httpurl
+ HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().//
+ addQueryParameter("authorization", authorization).//
+ addQueryParameter("date", date).//
+ addQueryParameter("host", url.getHost()).//
+ build();
+ System.out.println("httpUrl:\n" + httpUrl);
+ return httpUrl;
+ }
+
+ public static void main(String[] args) {
+ nettyClient = new NettyClient();
+ nettyClient.connect();
+
+ }
+}
diff --git a/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/WebSocketClient.java b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/WebSocketClient.java
new file mode 100644
index 00000000..05fc808a
--- /dev/null
+++ b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/WebSocketClient.java
@@ -0,0 +1,313 @@
+package com.xueyi.nlt.netty.client;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.nacos.shaded.com.google.gson.Gson;
+import com.alibaba.nacos.shaded.com.google.gson.JsonArray;
+import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
+import com.xueyi.nlt.api.netty.domain.vo.DmWebSocketMessageVo;
+import okhttp3.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
+import java.util.Base64;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+@Component
+public class WebSocketClient extends WebSocketListener {
+
+ public static WebSocketClient INSTANCE;
+ @Autowired
+ private RedisTemplate redisTemplate;
+ @Autowired
+ private StringRedisTemplate stringRedisTemplate;
+
+ public final static Object LOCK = new Object();
+ public static String hostUrl = "https://spark-api.xf-yun.com/v1.1/chat";
+ public static String APPID = "3d9282da";//从开放平台控制台中获取
+ public static String APIKEY = "7c217b3a313f4b66fcc14a8e97f85103";//从开放平台控制台中获取
+ public static String APISecret = "ZTRiNDQwMTRlOTlmZDQwMDUwYTdjMDM0";//从开放平台控制台中获取
+
+ public static WebSocket webSocket;
+// public static String APPID = "948cf4b6";//从开放平台控制台中获取
+// public static String APIKEY = "54f6e81f40a31d66d976496de895a7a4";//从开放平台控制台中获取
+// public static String APISecret = "ZDYyMjNmMTlkYTE0YWRmOWUwZTYxNjYz";//从开放平台控制台中获取
+ public static final Gson json = new Gson();
+// public static String question = "假设你是一位前台,你需要通过与其他人对话来获取会议相关信息,已知今天是2023-7-19,你需要获取会议日期,开始时间,持续时间,会议地点,会议主题。时间用类似00:00的格式输出。对方的话中可能不包含全部信息,对于未知的信息填充为none。如果所有信息都已知那么commit为true。否则为false。将你获得的信息输出为json格式。对方的话是:“明天下午开个会。从两点开到下午三点,在大会议室开,主题是访客接待”,只输出最后的json。输出只有一行,输出格式为{date:,start_time:,duration:,location:,theme:commit:}。";//可以修改question 内容,来向模型提问
+ public static String question = "请帮我安排五一出行计划";//可以修改question 内容,来向模型提问
+ public String answer = "";
+
+ @PostConstruct
+ public void init() {
+ INSTANCE = this;
+ INSTANCE.redisTemplate = this.redisTemplate;
+ INSTANCE.stringRedisTemplate = this.stringRedisTemplate;
+ }
+
+ public static void main(String[] args) {
+ synchronized (LOCK) {
+ try {
+ //构建鉴权httpurl
+ String authUrl = getAuthorizationUrl(hostUrl,APIKEY,APISecret);
+ OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
+ String url = authUrl.replace("https://","wss://").replace("http://","ws://");
+ Request request = new Request.Builder().url(url).build();
+ WebSocket webSocket = okHttpClient.newWebSocket(request,new WebSocketClient());
+ LOCK.wait();
+ System.out.println("查询完成");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+
+ // write your code here
+
+ }
+
+ public void sendMsg(String message){
+ question = message;
+
+ try {
+ //构建鉴权httpurl
+ String authUrl = getAuthorizationUrl(hostUrl,APIKEY,APISecret);
+ OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
+ String url = authUrl.replace("https://","wss://").replace("http://","ws://");
+ Request request = new Request.Builder().url(url).build();
+ webSocket = okHttpClient.newWebSocket(request,new WebSocketClient());
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ //鉴权url
+ public static String getAuthorizationUrl(String hostUrl , String apikey ,String apisecret) throws Exception {
+ //获取host
+ URL url = new URL(hostUrl);
+ //获取鉴权时间 date
+ SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
+ System.out.println("format:\n" + format );
+ format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ String date = format.format(new Date());
+ //获取signature_origin字段
+ StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").
+ append("date: ").append(date).append("\n").
+ append("GET ").append(url.getPath()).append(" HTTP/1.1");
+ System.out.println("signature_origin:\n" + builder);
+ //获得signatue
+ Charset charset = Charset.forName("UTF-8");
+ Mac mac = Mac.getInstance("hmacsha256");
+ SecretKeySpec sp = new SecretKeySpec(apisecret.getBytes(charset),"hmacsha256");
+ mac.init(sp);
+ byte[] basebefore = mac.doFinal(builder.toString().getBytes(charset));
+ String signature = Base64.getEncoder().encodeToString(basebefore);
+ //获得 authorization_origin
+ String authorization_origin = String.format("api_key=\"%s\",algorithm=\"%s\",headers=\"%s\",signature=\"%s\"",apikey,"hmac-sha256","host date request-line",signature);
+ //获得authorization
+ String authorization = Base64.getEncoder().encodeToString(authorization_origin.getBytes(charset));
+ //获取httpurl
+ HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().//
+ addQueryParameter("authorization", authorization).//
+ addQueryParameter("date", date).//
+ addQueryParameter("host", url.getHost()).//
+ build();
+
+ return httpUrl.toString();
+ }
+
+ //重写onopen
+ @Override
+ public void onOpen(WebSocket webSocket, Response response) {
+ super.onOpen(webSocket, response);
+ new Thread(()->{
+ JsonObject frame = new JsonObject();
+ JsonObject header = new JsonObject();
+ JsonObject chat = new JsonObject();
+ JsonObject parameter = new JsonObject();
+ JsonObject payload = new JsonObject();
+ JsonObject message = new JsonObject();
+ JsonObject text = new JsonObject();
+ JsonArray ja = new JsonArray();
+
+ //填充header
+ header.addProperty("app_id",APPID);
+ header.addProperty("uid","123456789");
+ //填充parameter
+ chat.addProperty("domain","general");
+ chat.addProperty("random_threshold",0);
+ chat.addProperty("max_tokens",1024);
+ chat.addProperty("auditing","default");
+ parameter.add("chat",chat);
+ //填充payload
+ text.addProperty("role","user");
+ text.addProperty("content",question);
+ ja.add(text);
+// message.addProperty("text",ja.getAsString());
+ message.add("text",ja);
+ payload.add("message",message);
+ frame.add("header",header);
+ frame.add("parameter",parameter);
+ frame.add("payload",payload);
+ System.out.println("frame:\n" + frame.toString());
+ webSocket.send(frame.toString());
+
+
+ }
+
+
+ ).start();
+ }
+
+ //重写onmessage
+
+ @Override
+ public void onMessage(WebSocket webSocket, String text) {
+ super.onMessage(webSocket, text);
+ System.out.println("text:\n" + text);
+ ResponseData responseData = json.fromJson(text,ResponseData.class);
+ synchronized (LOCK) {
+ try {
+ // System.out.println("code:\n" + responseData.getHeader().get("code"));
+ if (0 == responseData.getHeader().get("code").getAsInt()) {
+ System.out.println("###########");
+ System.out.println("getStatus: " + responseData.getHeader().get("status").getAsInt());
+ if (2 != responseData.getHeader().get("status").getAsInt()) {
+ System.out.println("****************");
+ Payload pl = json.fromJson(responseData.getPayload(), Payload.class);
+ JsonArray temp = (JsonArray) pl.getChoices().get("text");
+ JsonObject jo = (JsonObject) temp.get(0);
+ answer += jo.get("content").getAsString();
+// System.out.println(answer);
+ } else {
+ Payload pl1 = json.fromJson(responseData.getPayload(), Payload.class);
+ JsonObject jsonObject = (JsonObject) pl1.getUsage().get("text");
+ int prompt_tokens = jsonObject.get("prompt_tokens").getAsInt();
+ JsonArray temp1 = (JsonArray) pl1.getChoices().get("text");
+ JsonObject jo = (JsonObject) temp1.get(0);
+ answer += jo.get("content").getAsString();
+ System.out.println("返回结果为:\n" + answer);
+
+ if (INSTANCE.redisTemplate.hasKey("gpt:websocket:1")) {
+ DmWebSocketMessageVo message = (DmWebSocketMessageVo) INSTANCE.redisTemplate.opsForValue().get("gpt:websocket:1");
+ JSONObject preWebsocketJo = message.getFormat();
+ JSONObject meetingJo = new JSONObject();
+ meetingJo.put("timestamp",preWebsocketJo.get("timestamp"));
+ meetingJo.put("content",answer);
+ INSTANCE.stringRedisTemplate.opsForHash().put("group:nlp" + ":" + preWebsocketJo.getString("orderId"), "meeting", meetingJo.toString());
+ INSTANCE.redisTemplate.delete("gpt:websocket:1");
+
+ }else {
+ // 添加缓存
+ INSTANCE.stringRedisTemplate.opsForValue().set("group:websocket:content", answer);
+ LOCK.notifyAll();
+ }
+
+// webSocket.close(3,"客户端主动断开链接");
+ //webSocket.close(1000,"客户端主动断开链接");
+
+ }
+
+ } else {
+ System.out.println("返回结果错误:\n" + responseData.getHeader().get("code") + responseData.getHeader().get("message"));
+ LOCK.notifyAll();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+
+ //重写onFailure
+
+ @Override
+ public void onFailure(WebSocket webSocket, Throwable t, Response response) {
+ super.onFailure(webSocket, t, response);
+ System.out.println(response);
+ }
+
+
+
+ class ResponseData{
+ private JsonObject header;
+ private JsonObject payload;
+
+ public JsonObject getHeader() {
+ return header;
+ }
+
+ public JsonObject getPayload() {
+ return payload;
+ }
+ }
+
+ class Header{
+ private int code ;
+ private String message;
+ private String sid;
+ private String status;
+
+ public int getCode() {
+ return code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getSid() {
+ return sid;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+ }
+
+ class Payload{
+ private JsonObject choices;
+ private JsonObject usage;
+
+ public JsonObject getChoices() {
+ return choices;
+ }
+
+ public JsonObject getUsage() {
+ return usage;
+ }
+ }
+
+ class Choices{
+ private int status;
+ private int seq;
+ private JsonArray text;
+
+ public int getStatus() {
+ return status;
+ }
+
+ public int getSeq() {
+ return seq;
+ }
+
+ public JsonArray getText() {
+ return text;
+ }
+ }
+
+
+
+
+
+
+}
diff --git a/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/WebsocketConfig.java b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/WebsocketConfig.java
new file mode 100644
index 00000000..6a10962b
--- /dev/null
+++ b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/WebsocketConfig.java
@@ -0,0 +1,202 @@
+package com.xueyi.nlt.netty.client;
+
+import java.util.Map;
+
+public class WebsocketConfig {
+
+ /**
+ * websocket url-------------(如果存在则以url为主)
+ */
+ private String url;
+
+
+ /**
+ * websocket前缀
+ */
+ private String scheme = "ws";
+
+ /**
+ * 服务器IP
+ */
+ private String host;
+
+ /**
+ * 服务器端口
+ */
+ private int port;
+
+ /**
+ * 默认的websocket地址
+ */
+ private String path = "websocket";
+
+ /**
+ * url参数
+ */
+ private Map suffixParams;
+
+
+ // Optional settings below
+ /**
+ * 检查
+ */
+ private Long checkLiveDuration;
+
+ /**
+ * 自动重启客户端
+ */
+ private Boolean autoRebootClient;
+
+ /**
+ * 保持连接状态
+ */
+ private Boolean keepAlive;
+
+ /**
+ * 读空闲超时时间
+ */
+ private Integer readerIdleTimeSeconds = 60;
+
+ /**
+ * 写空闲超时时间
+ */
+ private Integer writerIdleTimeSeconds = 60;
+
+ /**
+ * 所有空闲超时时间
+ */
+ private Integer allIdleTimeSeconds = 0;
+
+ /**
+ * 心跳实现
+ */
+// private HeartBeat heartBeat;
+
+ public WebsocketConfig(){
+ }
+
+ public WebsocketConfig(String host, int port){
+ this.host = host;
+ this.port = port;
+ }
+
+
+ public WebsocketConfig(String host, int port, String path){
+ this.host = host;
+ this.port = port;
+ this.path = path;
+ }
+
+ public WebsocketConfig(String scheme, String host, int port, String path){
+ this.scheme = scheme;
+ this.host = host;
+ this.port = port;
+ this.path = path;
+ }
+
+
+ public String getScheme() {
+ return scheme;
+ }
+
+ public void setScheme(String scheme) {
+ this.scheme = scheme;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public Map getSuffixParams() {
+ return suffixParams;
+ }
+
+ public void setSuffixParams(Map suffixParams) {
+ this.suffixParams = suffixParams;
+ }
+
+ public Long getCheckLiveDuration() {
+ return checkLiveDuration;
+ }
+
+ public void setCheckLiveDuration(Long checkLiveDuration) {
+ this.checkLiveDuration = checkLiveDuration;
+ }
+
+ public Boolean getAutoRebootClient() {
+ return autoRebootClient;
+ }
+
+ public void setAutoRebootClient(Boolean autoRebootClient) {
+ this.autoRebootClient = autoRebootClient;
+ }
+
+
+ public Boolean getKeepAlive() {
+ return keepAlive;
+ }
+
+ public void setKeepAlive(Boolean keepAlive) {
+ this.keepAlive = keepAlive;
+ }
+
+ public Integer getReaderIdleTimeSeconds() {
+ return readerIdleTimeSeconds;
+ }
+
+ public void setReaderIdleTimeSeconds(Integer readerIdleTimeSeconds) {
+ this.readerIdleTimeSeconds = readerIdleTimeSeconds;
+ }
+
+ public Integer getWriterIdleTimeSeconds() {
+ return writerIdleTimeSeconds;
+ }
+
+ public void setWriterIdleTimeSeconds(Integer writerIdleTimeSeconds) {
+ this.writerIdleTimeSeconds = writerIdleTimeSeconds;
+ }
+
+ public Integer getAllIdleTimeSeconds() {
+ return allIdleTimeSeconds;
+ }
+
+ public void setAllIdleTimeSeconds(Integer allIdleTimeSeconds) {
+ this.allIdleTimeSeconds = allIdleTimeSeconds;
+ }
+
+// public HeartBeat getHeartBeat() {
+// return heartBeat;
+// }
+
+// public void setHeartBeat(HeartBeat heartBeat) {
+// this.heartBeat = heartBeat;
+// }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+}
diff --git a/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/codec/WsChannelInitializer.java b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/codec/WsChannelInitializer.java
new file mode 100644
index 00000000..d6f05655
--- /dev/null
+++ b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/codec/WsChannelInitializer.java
@@ -0,0 +1,46 @@
+package com.xueyi.nlt.netty.client.codec;
+
+import com.xueyi.nlt.netty.client.handler.MockClientHandler;
+import com.xueyi.nlt.netty.client.handler.NettyClientHandler;
+import com.xueyi.nlt.netty.client.handler.WsClientHandler;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpServerCodec;
+import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
+import io.netty.handler.logging.LogLevel;
+import io.netty.handler.logging.LoggingHandler;
+import io.netty.handler.stream.ChunkedWriteHandler;
+
+public class WsChannelInitializer extends ChannelInitializer {
+
+ private NettyClientHandler nettyClientHandler;
+
+ public WsChannelInitializer(NettyClientHandler nettyClientHandler) {
+ this.nettyClientHandler = nettyClientHandler;
+ }
+
+ @Override
+ protected void initChannel(Channel ch) {
+ ChannelPipeline pipeline = ch.pipeline();
+ // websocket是基于http协议的,所以需要使用http编解码器
+ pipeline.addLast(new HttpClientCodec());
+ pipeline.addLast(new LoggingHandler(LogLevel.INFO));
+ pipeline.addLast("decoder", new StringDecoder());
+ pipeline.addLast("encoder", new StringEncoder());
+ // 以上三个处理器是对http协议的支持
+
+ // websocket 服务器处理的协议,并用于指定客户端连接的路由(这里指定的是 /ws)
+ // 这里的URL就是 ws://ip:port/ws
+ // 该处理器为运行websocket服务器承担了所有繁重的工作
+ // 它会负责websocket的握手以及处理控制帧
+ // websocket的数据传输都是以frames进行的
+ pipeline.addLast(new WebSocketServerProtocolHandler("/wss"));
+ // 自定义的处理器
+ pipeline.addLast("handler", nettyClientHandler);
+ }
+}
diff --git a/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/MockClientHandler.java b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/MockClientHandler.java
new file mode 100644
index 00000000..4feba9eb
--- /dev/null
+++ b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/MockClientHandler.java
@@ -0,0 +1,66 @@
+package com.xueyi.nlt.netty.client.handler;
+
+import com.xueyi.nlt.netty.client.NettyClient;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Slf4j
+public class MockClientHandler extends SimpleChannelInboundHandler {
+
+ // private MsgHandleService msgHandleService;
+ private static final Logger log = LoggerFactory.getLogger(NettyClient.class);
+ private final WebSocketClientHandshaker webSocketClientHandshaker;
+
+ public MockClientHandler(WebSocketClientHandshaker webSocketClientHandshaker) {
+ this.webSocketClientHandshaker = webSocketClientHandshaker;
+// this.msgHandleService = SpringContextHolder.getBean(MsgHandleService.class);
+ }
+
+ /**
+ * 当客户端主动链接服务端的链接后,调用此方法
+ *
+ * @param channelHandlerContext ChannelHandlerContext
+ */
+ @Override
+ public void channelActive(ChannelHandlerContext channelHandlerContext) {
+ log.info("\n\t⌜⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓\n" +
+ "\t├ [Mock 建立连接]\n" +
+ "\t⌞⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓");
+
+ Channel channel = channelHandlerContext.channel();
+ // 握手
+ webSocketClientHandshaker.handshake(channel);
+ }
+
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, String data) {
+ log.info("接收到客户端的响应为:{}", data);
+ //自定义处理消息
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ log.info("\n\t⌜⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓\n" +
+ "\t├ [exception]: {}\n" +
+ "\t⌞⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓⎓", cause.getMessage());
+ ctx.close();
+ }
+
+ @Override
+ public void handlerRemoved(ChannelHandlerContext ctx) {
+ System.out.println("与服务器端断开连接");
+ }
+
+ @Override
+ public void channelReadComplete(ChannelHandlerContext channelHandlerContext) {
+ channelHandlerContext.flush();
+ }
+}
+
+
diff --git a/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/NettyClientHandler.java b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/NettyClientHandler.java
new file mode 100644
index 00000000..c64694fc
--- /dev/null
+++ b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/NettyClientHandler.java
@@ -0,0 +1,108 @@
+package com.xueyi.nlt.netty.client.handler;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.DefaultHttpResponse;
+import io.netty.handler.codec.http.websocketx.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.charset.Charset;
+
+import static com.xueyi.nlt.netty.client.NettyClient.APPID;
+
+public class NettyClientHandler extends SimpleChannelInboundHandler {
+
+
+
+ // 定义log
+ private static final Logger log = LoggerFactory.getLogger(NettyClientHandler.class);
+
+ private final WebSocketClientHandshaker webSocketClientHandshaker;
+
+ public NettyClientHandler(WebSocketClientHandshaker webSocketClientHandshaker) {
+ this.webSocketClientHandshaker = webSocketClientHandshaker;
+ }
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
+
+ Channel channel = ctx.channel();
+ // 握手
+ webSocketClientHandshaker.handshake(channel);
+
+ String question = "你是能帮我指定一个五一出行的计划么?";
+ log.info("Client,channelActive");
+ JSONObject frame = new JSONObject();
+ JSONObject header = new JSONObject();
+ JSONObject chat = new JSONObject();
+ JSONObject parameter = new JSONObject();
+ JSONObject payload = new JSONObject();
+ JSONObject message = new JSONObject();
+ JSONObject text = new JSONObject();
+ JSONArray ja = new JSONArray();
+
+ //填充header
+ header.put("app_id",APPID);
+ header.put("uid","123456789");
+ //填充parameter
+ chat.put("domain","general");
+ chat.put("random_threshold",0);
+ chat.put("max_tokens",1024);
+ chat.put("auditing","default");
+ parameter.put("chat",chat);
+ //填充payload
+ text.put("role","user");
+ text.put("content",question);
+ ja.add(text);
+// message.addProperty("text",ja.getAsString());
+ message.put("text",ja);
+ payload.put("message",message);
+ frame.put("header",header);
+ frame.put("parameter",parameter);
+ frame.put("payload",payload);
+ System.out.println("frame:\n" + frame.toString());
+ ByteBuf byteBuf = Unpooled.copiedBuffer(frame.toString(), Charset.forName("utf-8"));
+ ctx.writeAndFlush(frame.toString());
+ }
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+// log.info("Client,接收到服务端发来的消息:" + msg);
+// ByteBuf buf = (ByteBuf) msg;
+// byte[] buffer = new byte[buf.readableBytes()];
+// buf.readBytes(buffer);
+// String message = new String(buffer, "utf-8");
+// log.info("Client,接收到服务端发来的消息:" + message);
+
+ Channel ch = ctx.channel();
+ DefaultHttpResponse response = (DefaultHttpResponse) msg;
+ log.info(response.toString());
+ }
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
+ // 获取客户端传输来的文本消息
+ String text = textWebSocketFrame.text();
+ // 这个是自定义的日志工具类,可见其它文章
+ log.info("收到的文本消息:[{}]", text);
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ log.info("Client,exceptionCaught");
+ cause.printStackTrace();
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+ log.info("Client,channelInactive");
+ }
+
+}
diff --git a/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/NettyWebsocketClientHandler.java b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/NettyWebsocketClientHandler.java
new file mode 100644
index 00000000..56c25b51
--- /dev/null
+++ b/xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/NettyWebsocketClientHandler.java
@@ -0,0 +1,196 @@
+package com.xueyi.nlt.netty.client.handler;
+
+import com.xueyi.nlt.netty.client.message.ReceiveMessage;
+import com.xueyi.nlt.netty.client.WebsocketConfig;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.*;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.HttpHeaders;
+import io.netty.handler.codec.http.websocketx.*;
+import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler.HandshakeComplete;
+import io.netty.handler.timeout.IdleStateEvent;
+import io.netty.util.CharsetUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+public class NettyWebsocketClientHandler extends SimpleChannelInboundHandler
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
com.xueyi
@@ -103,6 +108,10 @@
thumbnailator
0.4.8
+
+ com.xueyi
+ xueyi-api-nlt
+
diff --git a/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/meeting/controller/api/DmMeetingApiController.java b/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/meeting/controller/api/DmMeetingApiController.java
index d9cac850..10625a12 100644
--- a/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/meeting/controller/api/DmMeetingApiController.java
+++ b/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/meeting/controller/api/DmMeetingApiController.java
@@ -15,6 +15,7 @@ import com.xueyi.system.api.pass.feign.RemoteRecognizedRecordsService;
import com.xueyi.system.resource.controller.api.BaseApiController;
import com.xueyi.system.utils.common.ImageUtil;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@@ -46,6 +47,9 @@ public class DmMeetingApiController extends BaseApiController {
@Autowired
private SmsService smsService;
+ @Autowired
+ private StringRedisTemplate redisTemplate;
+
@GetMapping(value = "/room-lists/{devId}")
public List roomList(@PathVariable(value = "devId") String devId){
DeviceTenantSourceMergeVo vo = super.getDeviceTenantSourceMergeVo(devId);
@@ -91,6 +95,14 @@ public class DmMeetingApiController extends BaseApiController {
return remoteMeetingService.delInner(id, vo.getTenantId(),vo.getSourceSlave(), SecurityConstants.INNER);
}
+ @ResponseBody
+ @PostMapping(value = "/cancel-order")
+ public JSONObject cancel(@RequestParam(required = true) String devId) {
+ redisTemplate.delete("group:websocket" + ":" + devId);
+
+ return outputSuccess().toJSON();
+ }
+
@ResponseBody
@PostMapping(value = "/lists")
public JSONObject list(String dateStr, Long spaceId, String devId) {
diff --git a/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/meeting/controller/api/DmMeetingInnerApiController.java b/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/meeting/controller/api/DmMeetingInnerApiController.java
index 35eb265b..66bffce9 100644
--- a/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/meeting/controller/api/DmMeetingInnerApiController.java
+++ b/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/meeting/controller/api/DmMeetingInnerApiController.java
@@ -5,18 +5,26 @@ import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.xueyi.common.cache.utils.SourceUtil;
+import com.xueyi.common.core.constant.basic.SecurityConstants;
import com.xueyi.common.core.constant.basic.SqlConstants;
import com.xueyi.common.core.web.result.R;
import com.xueyi.common.security.annotation.InnerAuth;
import com.xueyi.common.sms.configure.SmsProperties;
import com.xueyi.common.web.constant.ResponseCode;
import com.xueyi.common.web.utils.DateUtils;
+import com.xueyi.nlt.api.netty.domain.vo.DmWebSocketMessageVo;
+import com.xueyi.nlt.api.netty.feign.RemoteWebsocketService;
+import com.xueyi.nlt.api.nlt.feign.RemoteIntentService;
+import com.xueyi.system.api.digitalmans.domain.dto.DmManDeviceDto;
import com.xueyi.system.api.digitalmans.domain.po.DmDigitalmanExtPo;
import com.xueyi.system.api.digitalmans.domain.po.DmDigitalmanPo;
+import com.xueyi.system.api.digitalmans.feign.RemoteManDeviceService;
import com.xueyi.system.api.meeting.domain.dto.DmMeetingOrdersDto;
import com.xueyi.system.api.meeting.domain.dto.DmMeetingRoomsDto;
import com.xueyi.system.api.meeting.domain.po.DmMeetingOrdersPo;
import com.xueyi.system.api.meeting.domain.po.DmMeetingRoomsPo;
+import com.xueyi.system.api.model.Source;
import com.xueyi.system.api.sms.domain.vo.SmsReqEntity;
import com.xueyi.system.api.sms.feign.RemoteSmsService;
import com.xueyi.system.api.staff.domain.po.DmStaffPo;
@@ -31,6 +39,7 @@ import com.xueyi.system.meeting.service.impl.DmMeetingRoomsServiceImpl;
import com.xueyi.system.resource.controller.api.BaseApiController;
import com.xueyi.system.staff.mapper.DmStaffMapper;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@@ -94,6 +103,17 @@ public class DmMeetingInnerApiController extends BaseApiController {
@Autowired
private DmMeetingRoomsConverter dmMeetingRoomsConverter;
+ @Autowired
+ private StringRedisTemplate redisTemplate;
+
+ @Autowired
+ private RemoteWebsocketService remoteWebsocketService;
+
+ @Autowired
+ private RemoteIntentService remoteIntentService;
+ @Autowired
+ private RemoteManDeviceService manDeviceService;
+
@InnerAuth
@GetMapping("/rooms/{deptId}")
@@ -189,6 +209,27 @@ public class DmMeetingInnerApiController extends BaseApiController {
System.err.println(e.getMessage());
e.printStackTrace();
}
+ // 埋点 预定会议室
+ redisTemplate.opsForValue().increment("dashboard:meeting", 1);
+ // 创建会议提醒
+ // 创建json
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("meetingRoom", meetingRoom.getName());
+ jsonObject.put("orderName", dmStaffPo.getUserName());
+ jsonObject.put("orderId", dmStaffPo.getId());
+ jsonObject.put("timestamp", list.get(0).getStartTime().getTime());
+// redisTemplate.opsForValue().set("group:nlp" + ":" + dmStaffPo.getId() + ":" + "meeting",jsonObject.toString());
+ // 将创建临时信息添加进缓存:用户会议提醒
+
+ DmWebSocketMessageVo vo = new DmWebSocketMessageVo();
+ vo.setDevId(order.getDevId());
+ vo.setSkillCode("1");
+ vo.setFormat(jsonObject);
+ R manDeviceDtoR = manDeviceService.manDeviceInfoInner(order.getDevId());
+ Source source = SourceUtil.getSourceCache(manDeviceDtoR.getData().getStrategyId());
+ remoteIntentService.sendMessage(vo, manDeviceDtoR.getData().getTId(), source.getMaster(), SecurityConstants.INNER);
+ // 清除设备会议室模版session信息
+ redisTemplate.delete("group:websocket" + ":" + order.getDevId());
return outputSuccess().toJSON();
}