Просмотр исходного кода

Merge branch 'dev_nlt' into test_nlt

tags/B.1.1.0.0_20230818_base
kira 2 лет назад
Родитель
Сommit
8e2aaa8da5
64 измененных файлов: 3000 добавлений и 22 удалений
  1. +7
    -5
      Jenkinsfile
  2. +67
    -0
      Jenkinsfile1
  3. +11
    -0
      pom.xml
  4. +1
    -0
      xueyi-api/pom.xml
  5. +16
    -0
      xueyi-api/xueyi-api-message/src/main/java/com/xueyi/message/api/transfer/domain/vo/Message.java
  6. +10
    -5
      xueyi-api/xueyi-api-message/src/main/java/com/xueyi/message/api/transfer/feign/RemoteTransferService.java
  7. +33
    -0
      xueyi-api/xueyi-api-nlt/pom.xml
  8. +13
    -0
      xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/netty/domain/vo/DmWebSocketMessageVo.java
  9. +20
    -0
      xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/netty/feign/RemoteWebsocketService.java
  10. +16
    -0
      xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/domain/vo/DmIntentVo.java
  11. +13
    -0
      xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/domain/vo/DmRecognitionVo.java
  12. +24
    -0
      xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/feign/RemoteIntentService.java
  13. +15
    -0
      xueyi-api/xueyi-api-nlt/src/main/java/com/xueyi/nlt/api/nlt/feign/factory/RemoteIntentFallbackFactory.java
  14. +1
    -0
      xueyi-api/xueyi-api-nlt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  15. +2
    -0
      xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/digitalmans/domain/dto/DmVisitorsDto.java
  16. +10
    -1
      xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/digitalmans/feign/RemoteDigitalmanService.java
  17. +9
    -0
      xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/RemoteMeetingService.java
  18. +10
    -0
      xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/factory/RemoteMeetingFallbackFactory.java
  19. +1
    -0
      xueyi-api/xueyi-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  20. +1
    -0
      xueyi-common/xueyi-common-core/src/main/java/com/xueyi/common/core/constant/basic/ServiceConstants.java
  21. +54
    -0
      xueyi-common/xueyi-common-core/src/main/java/com/xueyi/common/core/utils/InetAddressUtils.java
  22. +15
    -0
      xueyi-common/xueyi-common-mqtt/src/main/java/com/xueyi/common/mqtt/constant/MqttTopicConstant.java
  23. +1
    -0
      xueyi-modules/pom.xml
  24. +23
    -0
      xueyi-modules/xueyi-job/src/main/java/com/xueyi/job/task/DmBroadDataTask.java
  25. +2
    -1
      xueyi-modules/xueyi-job/src/main/java/com/xueyi/job/util/AbstractQuartzJob.java
  26. +11
    -1
      xueyi-modules/xueyi-message/pom.xml
  27. +69
    -8
      xueyi-modules/xueyi-message/src/main/java/com/xueyi/message/transfer/controller/ApiController.java
  28. +19
    -0
      xueyi-modules/xueyi-message/src/main/java/com/xueyi/message/transfer/service/IMessageQueueService.java
  29. +167
    -0
      xueyi-modules/xueyi-message/src/main/java/com/xueyi/message/transfer/service/impl/MessageQueueServiceImpl.java
  30. +17
    -0
      xueyi-modules/xueyi-nlt/Dockerfile
  31. +117
    -0
      xueyi-modules/xueyi-nlt/pom.xml
  32. +15
    -0
      xueyi-modules/xueyi-nlt/sonar-project.properties
  33. +29
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/XueYiNltApplication.java
  34. +195
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/NettyClient.java
  35. +313
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/WebSocketClient.java
  36. +202
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/WebsocketConfig.java
  37. +46
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/codec/WsChannelInitializer.java
  38. +66
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/MockClientHandler.java
  39. +108
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/NettyClientHandler.java
  40. +196
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/NettyWebsocketClientHandler.java
  41. +23
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/WsClientHandler.java
  42. +13
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/message/ReceiveMessage.java
  43. +66
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/controller/DmWebsocketController.java
  44. +296
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/controller/DmIntentController.java
  45. +14
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/domain/dto/DmIntentDto.java
  46. +13
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/domain/model/DmIntentConverter.java
  47. +61
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/domain/po/DmIntentPo.java
  48. +13
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/domain/query/DmIntentQuery.java
  49. +16
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/domain/vo/IntentTemplateVo.java
  50. +8
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/manager/IDmIntentManager.java
  51. +15
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/manager/impl/DmIntentManager.java
  52. +11
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/mapper/DmIntentMapper.java
  53. +8
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/service/IDmIntentService.java
  54. +12
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/service/impl/DmIntentServiceImpl.java
  55. +7
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/template/BaseTemplate.java
  56. +93
    -0
      xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/template/MeetingOrderTemplate.java
  57. +10
    -0
      xueyi-modules/xueyi-nlt/src/main/resources/banner.txt
  58. +34
    -0
      xueyi-modules/xueyi-nlt/src/main/resources/bootstrap.yml
  59. +74
    -0
      xueyi-modules/xueyi-nlt/src/main/resources/logback.xml
  60. +9
    -0
      xueyi-modules/xueyi-system/pom.xml
  61. +38
    -0
      xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/digitalmans/controller/DmDigitalmanController.java
  62. +33
    -0
      xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/meeting/controller/api/DmMeetingApiController.java
  63. +186
    -1
      xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/meeting/controller/api/DmMeetingInnerApiController.java
  64. +2
    -0
      xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/staff/controller/api/DmStaffInnerApiController.java

+ 7
- 5
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}
"""
}
}


+ 67
- 0
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 "镜像推送成功"
//}
}
}

+ 11
- 0
pom.xml Просмотреть файл

@@ -163,6 +163,11 @@
<version>${fastjson2.version}</version>
</dependency>

<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.4</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
@@ -301,6 +306,12 @@
<version>${xueyi.version}</version>
</dependency>

<dependency>
<groupId>com.xueyi</groupId>
<artifactId>xueyi-api-nlt</artifactId>
<version>${xueyi.version}</version>
</dependency>

<!-- huTool 工具类库 -->
<dependency>
<groupId>cn.hutool</groupId>


+ 1
- 0
xueyi-api/pom.xml Просмотреть файл

@@ -14,6 +14,7 @@
<module>xueyi-api-tenant</module>
<module>xueyi-api-file</module>
<module>xueyi-api-job</module>
<module>xueyi-api-nlt</module>
<module>xueyi-api-modules-auth</module>

</modules>


+ 16
- 0
xueyi-api/xueyi-api-message/src/main/java/com/xueyi/message/api/transfer/domain/vo/Message.java Просмотреть файл

@@ -0,0 +1,16 @@
package com.xueyi.message.api.transfer.domain.vo;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;

import java.io.Serializable;

@Data
@ToString
@Builder
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Message implements Serializable,Cloneable{


}

+ 10
- 5
xueyi-api/xueyi-api-message/src/main/java/com/xueyi/message/api/transfer/feign/RemoteTransferService.java Просмотреть файл

@@ -1,15 +1,14 @@
package com.xueyi.message.api.transfer.feign;

import com.xueyi.common.core.constant.basic.SecurityConstants;
import com.xueyi.common.core.constant.basic.ServiceConstants;
import com.xueyi.common.core.web.result.AjaxResult;
import com.xueyi.common.core.web.result.R;

import com.xueyi.message.api.transfer.feign.factory.RemoteTransferFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
* 数据源服务
@@ -21,4 +20,10 @@ public interface RemoteTransferService {
@RequestMapping(value = "/api/device_online_status/{devId}", method = {RequestMethod.GET})
@ResponseBody
public AjaxResult getDeviceOnlineStatus(@RequestParam(value = "devId") String devId);

@RequestMapping(value = "/api/broadcast", method = {RequestMethod.GET})
@ResponseBody
public R broadcast(@RequestParam(value = "channel") String channel);


}

+ 33
- 0
xueyi-api/xueyi-api-nlt/pom.xml Просмотреть файл

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.xueyi</groupId>
<artifactId>xueyi-api</artifactId>
<version>2.5.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>xueyi-api-nlt</artifactId>

<description>
xueyi-api-nlt模型接入管理模块
</description>

<dependencies>

<!-- XueYi Common Core -->
<dependency>
<groupId>com.xueyi</groupId>
<artifactId>xueyi-common-core</artifactId>
</dependency>


<dependency>
<groupId>com.xueyi</groupId>
<artifactId>xueyi-api-system</artifactId>
</dependency>
</dependencies>

</project>

+ 13
- 0
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;
}

+ 20
- 0
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);
}

+ 16
- 0
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;
}

+ 13
- 0
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;
}

+ 24
- 0
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<JSONObject> 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);
}

+ 15
- 0
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<RemoteIntentService> {
@Override
public RemoteIntentService create(Throwable cause) {
return null;
}
}

+ 1
- 0
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

+ 2
- 0
xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/digitalmans/domain/dto/DmVisitorsDto.java Просмотреть файл

@@ -22,4 +22,6 @@ public class DmVisitorsDto extends DmVisitorsPo {
public static final Long TYPE_VIP_VISITOR = 9L;
public static final Long TYPE_SPECIAL_VISITOR = 10L;

public String imgUrl;

}

+ 10
- 1
xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/digitalmans/feign/RemoteDigitalmanService.java Просмотреть файл

@@ -1,5 +1,6 @@
package com.xueyi.system.api.digitalmans.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;
@@ -8,7 +9,11 @@ import com.xueyi.system.api.digitalmans.domain.dto.DmSyncDigitalmanDto;
import com.xueyi.system.api.digitalmans.domain.po.DmDigitalmanExtPo;
import com.xueyi.system.api.organize.feign.factory.RemoteUserFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
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.RequestParam;

import java.util.List;

@@ -44,4 +49,8 @@ public interface RemoteDigitalmanService {
@GetMapping("/man/inner-api/devInfo/{devId}")
public R<DmDigitalmanExtPo> devInfo(@RequestParam(value = "devId") String devId, @RequestHeader(SecurityConstants.ENTERPRISE_ID) Long enterpriseId, @RequestHeader(SecurityConstants.SOURCE_NAME) String sourceName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);


@GetMapping("/man/api/mansInfo")
public R<JSONObject> mansInfo();

}

+ 9
- 0
xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/RemoteMeetingService.java Просмотреть файл

@@ -9,10 +9,12 @@ import com.xueyi.system.api.meeting.domain.dto.DmMeetingRoomsDto;
import com.xueyi.system.api.meeting.feign.factory.RemoteMeetingFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@@ -50,4 +52,11 @@ public interface RemoteMeetingService {

@PostMapping(value = "/meeting/inner-api/lists-all")
JSONObject listAllInner(@RequestParam("dateStr") String dateStr, @RequestParam("spaceId") Long spaceId, @RequestHeader(SecurityConstants.ENTERPRISE_ID) Long enterpriseId, @RequestHeader(SecurityConstants.SOURCE_NAME) String sourceName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);

@GetMapping("/meeting/inner-api/recent/{deptId}/{dateStr}")
@ResponseBody
public List<JSONObject> 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<List<JSONObject>> 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);
}

+ 10
- 0
xueyi-api/xueyi-api-system/src/main/java/com/xueyi/system/api/meeting/feign/factory/RemoteMeetingFallbackFactory.java Просмотреть файл

@@ -66,6 +66,16 @@ public class RemoteMeetingFallbackFactory implements FallbackFactory<RemoteMeeti
public JSONObject listAllInner(String dateStr, Long spaceId, Long enterpriseId, String sourceName, String source) {
return R.fail("获取会议室预约列表失败:" + throwable.getMessage()).toJson();
}

@Override
public List<JSONObject> recent(Long deptId, String dateStr, Long roomId, String startTime, Long enterpriseId, String sourceName, String source) {
return null;
}

@Override
public R<List<JSONObject>> ableOrderList(String devId, String dateStr, Long roomId, String startTime) {
return null;
}
};
}
}

+ 1
- 0
xueyi-api/xueyi-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports Просмотреть файл

@@ -6,3 +6,4 @@ com.xueyi.system.api.authority.feign.factory.RemoteMenuFallbackFactory
com.xueyi.system.api.authority.feign.factory.RemoteAuthFallbackFactory
com.xueyi.system.api.dict.feign.factory.RemoteConfigFallbackFactory
com.xueyi.system.api.log.feign.factory.RemoteLogFallbackFactory
com.xueyi.system.api.meeting.feign.factory.RemoteMeetingFallbackFactory

+ 1
- 0
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";


+ 54
- 0
xueyi-common/xueyi-common-core/src/main/java/com/xueyi/common/core/utils/InetAddressUtils.java Просмотреть файл

@@ -0,0 +1,54 @@
package com.xueyi.common.core.utils;


import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;

/**
* @author yinruoxi
* @version V1.0
* @className InetAddressUtils
* @description TO DO
* @Date 2023/8/10 14:19 PM
*/
public class InetAddressUtils {

public static InetAddress getLocalHostLANAddress() throws UnknownHostException {
try {
InetAddress candidateAddress = null;
// 遍历所有的网络接口
for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();) {
NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
// 在所有的接口下再遍历IP
for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {
InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
if (!inetAddr.isLoopbackAddress()) {// 排除loopback类型地址
if (inetAddr.isSiteLocalAddress()) {
// 如果是site-local地址,就是它了
return inetAddr;
} else if (candidateAddress == null) {
// site-local类型的地址未被发现,先记录候选地址
candidateAddress = inetAddr;
}
}
}
}
if (candidateAddress != null) {
return candidateAddress;
}
// 如果没有发现 non-loopback地址.只能用最次选的方案
InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
if (jdkSuppliedAddress == null) {
throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null.");
}
return jdkSuppliedAddress;
} catch (Exception e) {
UnknownHostException unknownHostException = new UnknownHostException(
"Failed to determine LAN address: " + e);
unknownHostException.initCause(e);
throw unknownHostException;
}
}
}

+ 15
- 0
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";


}

+ 1
- 0
xueyi-modules/pom.xml Просмотреть файл

@@ -16,6 +16,7 @@
<module>xueyi-file</module>
<module>xueyi-message</module>
<module>xueyi-modules-auth</module>
<module>xueyi-nlt</module>
</modules>

<artifactId>xueyi-modules</artifactId>


+ 23
- 0
xueyi-modules/xueyi-job/src/main/java/com/xueyi/job/task/DmBroadDataTask.java Просмотреть файл

@@ -0,0 +1,23 @@
package com.xueyi.job.task;

import com.xueyi.message.api.transfer.feign.RemoteTransferService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
* 定时任务调度测试
*
* @author xueyi
*/
@Component("dmBroadDataTask")
public class DmBroadDataTask {
@Autowired
RemoteTransferService remoteTransferService;
/**
* 触发条件:* 0/1 * * * *
* 每分钟执行一次
*/
public void syncData() {
remoteTransferService.broadcast("broadData");
}
}

+ 2
- 1
xueyi-modules/xueyi-job/src/main/java/com/xueyi/job/util/AbstractQuartzJob.java Просмотреть файл

@@ -43,7 +43,8 @@ public abstract class AbstractQuartzJob implements Job {
doExecute(context, sysJob);
after(context, sysJob, null);
} catch (Exception e) {
log.error("任务执行异常 - :", e);
log.error("任务执行异常 - :", e.getMessage());
e.printStackTrace();
after(context, sysJob, e);
}
}


+ 11
- 1
xueyi-modules/xueyi-message/pom.xml Просмотреть файл

@@ -47,7 +47,16 @@
<artifactId>spring-integration-mqtt</artifactId>
<version>5.5.14</version>
</dependency>

<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>io.socket</groupId>
<artifactId>socket.io-client</artifactId>
<version>1.0.0</version>
</dependency>

<!-- XueYi Common Log -->
<dependency>
@@ -55,6 +64,7 @@
<artifactId>xueyi-common-log</artifactId>
</dependency>


<!-- XueYi Common Web -->
<dependency>
<groupId>com.xueyi</groupId>


+ 69
- 8
xueyi-modules/xueyi-message/src/main/java/com/xueyi/message/transfer/controller/ApiController.java Просмотреть файл

@@ -1,7 +1,6 @@
package com.xueyi.message.transfer.controller;


import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.xueyi.common.cache.utils.SourceUtil;
import com.xueyi.common.core.constant.basic.SecurityConstants;
@@ -11,27 +10,33 @@ import com.xueyi.common.core.web.result.AjaxResult;
import com.xueyi.common.core.web.result.R;
import com.xueyi.message.api.transfer.domain.vo.DmActiveVo;
import com.xueyi.message.api.transfer.domain.vo.DmDeviceVo;
import com.xueyi.message.transfer.service.impl.MessageQueueServiceImpl;
import com.xueyi.system.api.authority.feign.RemoteLoginService;
import com.xueyi.system.api.device.domain.vo.DeviceTenantSourceMergeVo;
import com.xueyi.system.api.device.feign.RemoteDeviceTenantMergeService;
import com.xueyi.system.api.digitalmans.domain.dto.DmManDeviceDto;
import com.xueyi.system.api.digitalmans.domain.dto.DmSkillDto;
import com.xueyi.system.api.digitalmans.domain.dto.DmSyncDigitalmanDto;
import com.xueyi.system.api.digitalmans.domain.po.DmManDevicePo;
import com.xueyi.system.api.digitalmans.domain.vo.DmBroadcastVo;
import com.xueyi.system.api.digitalmans.domain.vo.DmReceptionVo;
import com.xueyi.system.api.digitalmans.feign.*;
import com.xueyi.system.api.digitalmans.feign.RemoteBroadcastService;
import com.xueyi.system.api.digitalmans.feign.RemoteDigitalmanService;
import com.xueyi.system.api.digitalmans.feign.RemoteManDeviceService;
import com.xueyi.system.api.digitalmans.feign.RemoteReceptionService;
import com.xueyi.system.api.digitalmans.feign.RemoteSkillService;
import com.xueyi.system.api.model.Source;
import com.xueyi.system.api.organize.domain.dto.SysEnterpriseDto;
import com.xueyi.system.api.staff.domain.vo.DmStaffFeature;
import com.xueyi.system.api.staff.feign.RemoteStaffService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
@@ -70,6 +75,10 @@ public class ApiController {
@Autowired
RemoteBroadcastService remoteBroadcastService;

@Autowired
MessageQueueServiceImpl messageQueueService;



@RequestMapping(value = "/heartbeat", method = {RequestMethod.POST})
@ResponseBody
@@ -264,6 +273,58 @@ public class ApiController {
return AjaxResult.success(System.currentTimeMillis() - Long.parseLong(timestamp) >10 * 60 * 1000 ? InitConstants.DEVICE_ACTIVATE_STATUS_OFFLINE : InitConstants.DEVICE_ACTIVATE_STATUS_ONLINE);
}

/**
* @Author yangkai
* @Description //TODO
* @Date 2023/8/11
* @Param
* @return
*
*
* manCount
* serviceTimeCount
* chatTimes
* chatDurationCount
* skillExecuteTimes
*
* recognizedPersonCount
* servicePerCount
*
* receptionServiceCount
* meetingServiceCount
* visitServiceCount
* largeModelKnowledgeBaseGroupChangeNum
* largeModelKnowledgeBaseChangeNum
**/
@RequestMapping(value = "/broadcast", method = {RequestMethod.GET})
@ResponseBody
public R broadcast(@RequestParam(value = "channel") String channel){
try {
JSONObject json = new JSONObject();


json.put("chatTimes", 865531);
json.put("chatDurationCount", 10068);
// json.put("skillExecuteTimes", 10);
json.put("recognizedPersonCount", 13899);
json.put("servicePerCount", 737521);
json.put("receptionServiceCount", 1824);
json.put("meetingServiceCount", 1762);
json.put("visitServiceCount", 523);

R<JSONObject> objectR = remoteDigitalmanService.mansInfo();
JSONObject jsonObj = objectR.getData();
jsonObj.keySet().forEach(key -> json.put(key, jsonObj.get(key)));
String str = json.toJSONString();

messageQueueService.broadcast(channel, str);
return R.ok(str);
}catch (Exception e){
e.printStackTrace();
return R.fail(e.getMessage());
}
}

@RequestMapping(value = "/get_activate/{snCode}", method = {RequestMethod.GET})
@ResponseBody
public AjaxResult activate(@PathVariable(value = "snCode") String snCode, HttpServletResponse response) {


+ 19
- 0
xueyi-modules/xueyi-message/src/main/java/com/xueyi/message/transfer/service/IMessageQueueService.java Просмотреть файл

@@ -0,0 +1,19 @@
package com.xueyi.message.transfer.service;

import com.corundumstudio.socketio.SocketIOClient;
import com.xueyi.message.api.transfer.domain.vo.Message;

import java.util.Collection;
import java.util.List;

public interface IMessageQueueService {

// public List<Message> getAll();
//
// public boolean add(Message message);

public void broadcast(String channel, String message);

public Collection<SocketIOClient> getAllClients();

}

+ 167
- 0
xueyi-modules/xueyi-message/src/main/java/com/xueyi/message/transfer/service/impl/MessageQueueServiceImpl.java Просмотреть файл

@@ -0,0 +1,167 @@
package com.xueyi.message.transfer.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DataListener;
import com.corundumstudio.socketio.listener.DisconnectListener;
import com.corundumstudio.socketio.listener.ExceptionListener;
import com.xueyi.common.core.utils.InetAddressUtils;
import com.xueyi.message.api.transfer.domain.vo.Message;
import com.xueyi.message.transfer.service.IMessageQueueService;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class MessageQueueServiceImpl implements IMessageQueueService {

@Autowired
RedisTemplate<String, Serializable> redisTemplate;
private Integer port = 9901;

private SocketIOServer server;
private ConcurrentHashMap<String, Message> messageMap = new ConcurrentHashMap<>();

MessageQueueServiceImpl(){
startServer(port);
}

// @Override
// public List<Message> getAll(){
// List<Message> list = new ArrayList<Message>();
// Iterator<Map.Entry<String, Message>> entries = messageMap.entrySet().iterator();
// while(entries.hasNext()){
// Map.Entry<String, Message> entry = entries.next();
// Message value = entry.getValue();
// if(System.currentTimeMillis()- value.getTimestamp() > 10000){
// messageMap.remove(entry.getKey());
// }else{
// list.add(value);
// }
// }
// if(list.size()>0){
// return list;
// }
// return null;
// }
//
// @Override
// public boolean add(Message message){
//
// messageMap.put(message.getVid(),message);
// return true;
// }

@Override
public void broadcast(String channel, String message){
server.getBroadcastOperations().sendEvent(channel,message);
}

@Override
public Collection<SocketIOClient> getAllClients(){
return server.getAllClients();
}


private void startServer(int port){
Configuration config = new Configuration();
ExceptionListener exceptionListener = new ExceptionListener() {
@Override
public void onEventException(Exception e, List<Object> list, SocketIOClient socketIOClient) {

}

@Override
public void onDisconnectException(Exception e, SocketIOClient socketIOClient) {

}

@Override
public void onConnectException(Exception e, SocketIOClient socketIOClient) {

}

@Override
public boolean exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) throws Exception {
channelHandlerContext.close();
return true;
}
};
try {
System.out.println("启动");
config.setHostname(InetAddressUtils.getLocalHostLANAddress().getHostAddress());

} catch (Exception e) {
e.printStackTrace();
}
config.setPort(port);
config.setExceptionListener(exceptionListener);
server = new SocketIOServer(config);
server.addConnectListener(new ConnectListener() {
// 添加客户端连接监听器
@Override
public void onConnect(SocketIOClient client) {
System.out.println(client.getRemoteAddress().toString());
if(client.getRemoteAddress().toString().contains("100.117") || client.getRemoteAddress().toString().contains("100.171")){
client.disconnect();
return;
}
client.sendEvent("connected", "hello");
}
});

server.addEventListener("client_info", String.class, new DataListener<String>(){
@Override
public void onData(SocketIOClient client, String data, AckRequest ackRequest) throws ClassNotFoundException {
//客户端推送advert_info事件时,onData接受数据,这里是string类型的json数据,还可以为Byte[],object其他类型
String sa = client.getRemoteAddress().toString();
String clientIp = sa.substring(1,sa.indexOf(":"));//获取客户端连接的ip
Map params = client.getHandshakeData().getUrlParams();//获取客户端url参数
System.out.println(clientIp+":客户端:************"+data);
}
});
// server.addEventListener("remove_vinfromrsu", String.class, new DataListener<String>() {
// @Override
// public void onData(SocketIOClient socketIOClient, String s, AckRequest ackRequest) throws Exception {
// System.out.println("remove_vinfromrsu : " + s);
// List<RsuEventSimulatorMessage> list = JSON.parseArray(s, RsuEventSimulatorMessage.class);
// for (RsuEventSimulatorMessage item : list) {
// for (String vout : item.getVinouts()) {
// redisTemplate.opsForSet().remove("rsu_" + item.getRsuId(),vout);
// }
// }
// }
// });
// server.addEventListener("screen_info", String.class, new DataListener<String>(){
// @Override
// public void onData(SocketIOClient client, String data, AckRequest ackRequest) throws ClassNotFoundException {
// VehicleGridCountItem item = ((JSONObject)JSON.parse(data)).toJavaObject(VehicleGridCountItem.class);
// gridCountItemMap.put(client,item);
// }
// });
//添加客户端断开连接事件
server.addDisconnectListener(new DisconnectListener(){
@Override
public void onDisconnect(SocketIOClient client) {
String sa = client.getRemoteAddress().toString();
String clientIp = sa.substring(1,sa.indexOf(":"));//获取设备ip
System.out.println(clientIp+"-------------------------"+"客户端已断开连接");
//给客户端发送消息
client.sendEvent("advert_info",clientIp+"客户端你好,我是服务端,期待下次和你见面");
}
});
server.start();
}

}

+ 17
- 0
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"]

+ 117
- 0
xueyi-modules/xueyi-nlt/pom.xml Просмотреть файл

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.xueyi</groupId>
<artifactId>xueyi-modules</artifactId>
<version>2.5.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>xueyi-modules-nlt</artifactId>

<description>
xueyi-modules-nlt大模型处理模块
</description>

<dependencies>

<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

<!-- https://mvnrepository.com/artifact/com.squareup.okhttp/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.9.1</version>
</dependency>

<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-elasticsearch</artifactId>-->
<!-- <version>3.1.2</version>-->
<!-- </dependency>-->
<!-- XueYi Common Log -->
<dependency>
<groupId>com.xueyi</groupId>
<artifactId>xueyi-common-log</artifactId>
</dependency>

<!-- XueYi Common Web -->
<dependency>
<groupId>com.xueyi</groupId>
<artifactId>xueyi-common-web</artifactId>
</dependency>

<!-- XueYi Common Swagger -->
<dependency>
<groupId>com.xueyi</groupId>
<artifactId>xueyi-common-swagger</artifactId>
</dependency>

<!-- XueYi Api File -->
<dependency>
<groupId>com.xueyi</groupId>
<artifactId>xueyi-api-nlt</artifactId>
</dependency>

<dependency>
<groupId>com.xueyi</groupId>
<artifactId>xueyi-api-system</artifactId>
</dependency>

</dependencies>

<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<groupId>org.apache.maven.plugins</groupId>
<configuration>
<delimiters>@</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>

+ 15
- 0
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


+ 29
- 0
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" +
" '--' '----'`-..-' ");
}

}

+ 195
- 0
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<SocketChannel>() {
@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();

}
}

+ 313
- 0
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;
}
}






}

+ 202
- 0
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<String, Object> 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<String, Object> getSuffixParams() {
return suffixParams;
}

public void setSuffixParams(Map<String, Object> 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;
}
}

+ 46
- 0
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);
}
}

+ 66
- 0
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<String> {

// 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();
}
}



+ 108
- 0
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<TextWebSocketFrame> {



// 定义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");
}

}

+ 196
- 0
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<Object> {
private Logger logger = LoggerFactory.getLogger(NettyWebsocketClientHandler.class);

private WebsocketConfig websocketConfig;

private final WebSocketClientHandshaker handshaker;

private ChannelPromise handshakeFuture;

private ReceiveMessage receiveMessage;

// private HeartBeat heartBeat;

public NettyWebsocketClientHandler(WebSocketClientHandshaker handshaker) {
this.handshaker = handshaker;
}

public NettyWebsocketClientHandler(WebSocketClientHandshaker handshaker, ReceiveMessage receiveMessage) {
this.handshaker = handshaker;
this.receiveMessage = receiveMessage;
}

public ChannelFuture handshakeFuture() {
return handshakeFuture;
}

@Override
public void handlerAdded(ChannelHandlerContext ctx) {
handshakeFuture = ctx.newPromise();
}

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception{
super.channelActive(ctx);
handshaker.handshake(ctx.channel());
logger.info("channelActive");
}

@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception{
super.channelInactive(ctx);
logger.info("WebSocket Client disconnected!");
}

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
super.channelRead(ctx, msg);
}

@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel ch = ctx.channel();
if (!handshaker.isHandshakeComplete()) {
try {
handshaker.finishHandshake(ch, (FullHttpResponse) msg);
logger.info("WebSocket Client connected!");
handshakeFuture.setSuccess();
} catch (WebSocketHandshakeException e) {
logger.info("WebSocket Client failed to connect, " + e.getMessage());
handshakeFuture.setFailure(e);
}
return;
}

if (msg instanceof FullHttpResponse) {
FullHttpResponse response = (FullHttpResponse) msg;
throw new IllegalStateException(
"Unexpected FullHttpResponse (getStatus=" + response.getStatus() +
", content=" + response.content().toString(CharsetUtil.UTF_8) + ')');
}

WebSocketFrame frame = (WebSocketFrame) msg;
if (frame instanceof TextWebSocketFrame) {
/**
* 我们主要是用TextWebSocketFrame
*/
TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
receiveMessage.onMessage(ch, textFrame.text());
} else if (frame instanceof PongWebSocketFrame) {
logger.info("WebSocket Client received pong");
receiveMessage.onMessage(ch, frame);
} else if (frame instanceof CloseWebSocketFrame) {
logger.info("WebSocket Client received close Frame");
//执行后将关闭
receiveMessage.onMessage(ch, frame);
//receive a closing frame to shutdown the event loop
ch.eventLoop().shutdownGracefully();
ch.close().sync();
}else if(frame instanceof BinaryWebSocketFrame){
BinaryWebSocketFrame binaryFrame = (BinaryWebSocketFrame)msg;
ByteBuf buf = binaryFrame.content();
if (buf.isReadable()){
int availableBytesNumber = buf.readableBytes();
byte[] receivedBytes = new byte[availableBytesNumber];
buf.readBytes(receivedBytes);
receiveMessage.onMessage(ch, receivedBytes);
}
//buf.release();
// byte [] bytes = receivedBytes;
}
}

@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
// if (evt instanceof IdleStateEvent) {
// IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
// switch (idleStateEvent.state()) {
// case WRITER_IDLE:
// handlerWriterIdleEvent(ctx);
// break;
// case READER_IDLE:
// handlerReaderIdleEvent(ctx);
// break;
// case ALL_IDLE:
// handlerAllIdleEvent(ctx);
// break;
// default:
// break;
// }
// } else {
// super.userEventTriggered(ctx, evt);
// }
if(evt instanceof HandshakeComplete) {
HandshakeComplete handshake = (WebSocketServerProtocolHandler.HandshakeComplete)evt;
//http request header
HttpHeaders headers = handshake.requestHeaders();

//http request uri: /chat?accesskey=hello
String uri = handshake.requestUri();

//TODO: parse uri parameters to map ...
Map<String, String> params ;

//put to channel context
// ctx.channel().attr(RequestParams).set(params);
}

}


// protected void handlerWriterIdleEvent(ChannelHandlerContext ctx){
// heartBeat.ping(ctx);
// }
//
// protected void handlerReaderIdleEvent(ChannelHandlerContext ctx){
// heartBeat.ping(ctx);
// }
//
// protected void handlerAllIdleEvent(ChannelHandlerContext ctx){
// heartBeat.ping(ctx);
// }


@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
if (!handshakeFuture.isDone()) {
handshakeFuture.setFailure(cause);
}
logger.info("exceptionCaught "+ cause.getMessage());
}


public WebsocketConfig getWebsocketConfig() {
return websocketConfig;
}

public void setWebsocketConfig(WebsocketConfig websocketConfig) {
this.websocketConfig = websocketConfig;
}

// public HeartBeat getHeartBeat() {
// return heartBeat;
// }

// public void setHeartBeat(HeartBeat heartBeat) {
// this.heartBeat = heartBeat;
// }
}

+ 23
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/handler/WsClientHandler.java Просмотреть файл

@@ -0,0 +1,23 @@
package com.xueyi.nlt.netty.client.handler;

import com.xueyi.nlt.netty.client.NettyClient;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class WsClientHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

private static final Logger log = LoggerFactory.getLogger(WsClientHandler.class);
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
// 获取客户端传输来的文本消息
String text = msg.text();
// 这个是自定义的日志工具类,可见其它文章
log.info("收到的文本消息:[{}]", text);
// 在这里可以判断消息类型(比如初始化连接、消息在客户端间传输等)
// 然后可以将客户端Channel与对应的唯一标识用Map关联起来,就可以做定向推送,而不是广播

}
}

+ 13
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/client/message/ReceiveMessage.java Просмотреть файл

@@ -0,0 +1,13 @@
package com.xueyi.nlt.netty.client.message;

import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;

public interface ReceiveMessage {

public void onMessage(Channel channel, String text);

public void onMessage(Channel channel, byte[] bytes);

public void onMessage(Channel channel, WebSocketFrame frame);
}

+ 66
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/netty/controller/DmWebsocketController.java Просмотреть файл

@@ -0,0 +1,66 @@
package com.xueyi.nlt.netty.controller;

import com.alibaba.fastjson2.JSONObject;
import com.xueyi.common.cache.utils.SourceUtil;
import com.xueyi.common.core.constant.basic.SecurityConstants;
import com.xueyi.common.core.web.result.AjaxResult;
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.netty.client.WebSocketClient;
import com.xueyi.nlt.nlt.domain.vo.IntentTemplateVo;
import com.xueyi.system.api.digitalmans.domain.dto.DmManDeviceDto;
import com.xueyi.system.api.model.Source;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.text.SimpleDateFormat;
import java.util.Date;

@RestController
@RequestMapping("/websocket")
public class DmWebsocketController {

private static final Logger log = LoggerFactory.getLogger(DmWebsocketController.class);

@Autowired
WebSocketClient webSocketClient;

@Autowired
StringRedisTemplate stringRedisTemplate;

@Autowired
RedisTemplate redisTemplate;


/**
* 意图请求
列表
*/
@PostMapping("/inner/sendMessage")
@ResponseBody
public R sendMessage(@RequestBody DmWebSocketMessageVo message) {

log.info("websocket sendMessage:{}", message);
if (message == null || message.getFormat() == null) {
return R.fail("参数为空");
}
JSONObject jo = message.getFormat();
SimpleDateFormat dateFormat3 = new SimpleDateFormat("MM-dd");
Double timestamp = Double.valueOf((String)jo.get("timestamp"));
String meetingRoom = jo.getString("meetingRoom");
Date date = new Date(timestamp.longValue());
if (message.getSkillCode().equals("1")) {
String prefix = "假设你是一名公司前台,你看到在你们公司工作的\\"+ jo.getString("orderName")+ "\\,请你从个人角度提醒他参加\\" +
dateFormat3.format(timestamp) + "\\在\\" + meetingRoom + "\\的会,要求语气友好。输出只包含你要对他说的话,在20字左右。";
webSocketClient.sendMsg(prefix);
// 设置缓存
redisTemplate.opsForValue().set("gpt:websocket" + ":" + "1", message);
}
return R.ok();
}
}

+ 296
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/controller/DmIntentController.java Просмотреть файл

@@ -0,0 +1,296 @@
package com.xueyi.nlt.nlt.controller;


import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.xueyi.common.cache.utils.SourceUtil;
import com.xueyi.common.core.constant.basic.SecurityConstants;
import com.xueyi.common.core.web.result.AjaxResult;
import com.xueyi.common.core.web.result.R;
import com.xueyi.common.core.web.validate.V_A;
import com.xueyi.common.core.web.validate.V_E;
import com.xueyi.common.log.annotation.Log;
import com.xueyi.common.log.enums.BusinessType;
import com.xueyi.common.security.annotation.Logical;
import com.xueyi.common.security.annotation.RequiresPermissions;
import com.xueyi.common.web.entity.controller.BaseController;
import com.xueyi.nlt.api.netty.domain.vo.DmWebSocketMessageVo;
import com.xueyi.nlt.api.nlt.domain.vo.DmRecognitionVo;
import com.xueyi.nlt.api.nlt.feign.RemoteIntentService;
import com.xueyi.nlt.netty.client.WebSocketClient;
import com.xueyi.nlt.netty.client.handler.NettyClientHandler;
import com.xueyi.nlt.nlt.domain.dto.DmIntentDto;
import com.xueyi.nlt.nlt.domain.query.DmIntentQuery;
import com.xueyi.nlt.api.nlt.domain.vo.DmIntentVo;
import com.xueyi.nlt.nlt.domain.vo.IntentTemplateVo;
import com.xueyi.nlt.nlt.service.IDmIntentService;
import com.xueyi.nlt.nlt.template.BaseTemplate;
import com.xueyi.nlt.nlt.template.MeetingOrderTemplate;
import com.xueyi.system.api.digitalmans.domain.dto.DmManDeviceDto;
import com.xueyi.system.api.digitalmans.feign.RemoteBroadcastService;
import com.xueyi.system.api.digitalmans.feign.RemoteManDeviceService;
import com.xueyi.system.api.meeting.feign.RemoteMeetingService;
import com.xueyi.system.api.model.Source;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/intent")
public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDto, IDmIntentService> {

private static final Logger log = LoggerFactory.getLogger(DmIntentController.class);
@Autowired
IDmIntentService dmIntentService;

@Autowired
WebSocketClient webSocketClient;

/** 定义节点名称 */
@Override
protected String getNodeName() {
return "意图管理 ";
}


@Autowired
private StringRedisTemplate redisTemplate;

@Autowired
private RedisTemplate<Object,Object> redisTemplate2;



@Autowired
private RemoteManDeviceService manDeviceService;

@Autowired
private RemoteIntentService remoteIntentService;
@Autowired
private MeetingOrderTemplate meetingOrderTemplate;

/**
* 意图请求
列表
*/
@PostMapping("/api/conversation")
@ResponseBody
public AjaxResult conversationApi(@RequestBody DmIntentVo intent) {
redisTemplate.opsForValue().increment("dashboard:server", 1);
R<DmManDeviceDto> manDeviceDtoR = manDeviceService.manDeviceInfoInner(intent.getDevId());
Source source = SourceUtil.getSourceCache(manDeviceDtoR.getData().getStrategyId());
R<JSONObject> jsonObjectR = remoteIntentService.conversationInner(intent, manDeviceDtoR.getData().getTId(), source.getMaster(), SecurityConstants.INNER);
IntentTemplateVo voResult = new IntentTemplateVo();
voResult.setMsg("");
if (jsonObjectR.getData() != null) {
voResult.setTarget(1);
} else {
voResult.setTarget(0);
}
voResult.setFormat(jsonObjectR.getData());
return AjaxResult.success(voResult);
}

/**
* 意图请求
列表
*/
@PostMapping("/api/say_hello")
@ResponseBody
public AjaxResult sayHelloApi(@RequestBody DmRecognitionVo recognition) {
log.info(recognition.toString());
redisTemplate.opsForValue().increment("dashboard:recognition", 1);
JSONObject joResult = new JSONObject();
joResult.put("msg","");
joResult.put("target",0);
if (StringUtils.isNotEmpty(recognition.getRegistered()) && recognition.getRegistered().equals("1")) {

Map cntMap = redisTemplate.opsForHash().entries("group:nlp" + ":" + recognition.getPersonId());
//遍历key和value
for (Object key : cntMap.keySet()) {
String value = (String) cntMap.get(key);
if (String.valueOf(key).equals("meeting")) {
JSONObject jo = JSONObject.parseObject(value);
// 判断是否在30分钟内
System.out.println("timestamp:" + jo.get("timestamp"));
System.out.println("currenttime:" + System.currentTimeMillis());
if(jo.containsKey("timestamp") &&
Double.valueOf(String.valueOf(jo.get("timestamp"))) - System.currentTimeMillis() < 1800000) {
joResult.put("msg",jo.get("content"));
joResult.put("target",1);
redisTemplate.opsForHash().delete("group:nlp" + ":" + recognition.getPersonId(), "meeting");
break;
} else if (Double.valueOf(String.valueOf(jo.get("timestamp"))) - System.currentTimeMillis() < 0) {
redisTemplate.opsForHash().delete("group:nlp" + ":" + recognition.getPersonId(), "meeting");
}
} else {
joResult.put("msg",value);
joResult.put("target",1);
redisTemplate.opsForHash().delete("group:nlp" + ":" + recognition.getPersonId(),key);
break;
}
}
}
return AjaxResult.success(joResult);
}

/**
* 意图请求列表
*/
@PostMapping("/inner/conversation")
@ResponseBody
public R<JSONObject> conversationInner(@RequestBody DmIntentVo intent) {
JSONObject joResult = null;
// 判断skill code的值
switch (intent.getSkillCode()) {
case "1":
// 获取名称为"meeting-order"的BaseTemplate的实例
joResult = meetingOrderTemplate.handle(intent.getDevId(),intent.getContent());
break;
default:
break;
}
return R.ok(joResult);
}

/**
* 意图请求
列表
*/
@PostMapping("/inner/sendMessage")
@ResponseBody
public R sendMessage(@RequestBody DmWebSocketMessageVo message) {

log.info("websocket sendMessage:{}", message);
if (message == null || message.getFormat() == null) {
return R.fail("参数为空");
}
JSONObject jo = message.getFormat();
SimpleDateFormat dateFormat3 = new SimpleDateFormat("MM-dd");
Double timestamp = Double.valueOf((String)jo.get("timestamp"));
String meetingRoom = jo.getString("meetingRoom");
Date date = new Date(timestamp.longValue());
if (message.getSkillCode().equals("1")) {
String prefix = "假设你是一名公司前台,你看到在你们公司工作的\\"+ jo.getString("orderName")+ "\\,请你从个人角度提醒他参加\\" +
dateFormat3.format(timestamp) + "\\在\\" + meetingRoom + "\\的会,要求语气友好。输出只包含你要对他说的话,在20字左右。";
webSocketClient.sendMsg(prefix);
// 设置缓存
redisTemplate2.opsForValue().set("gpt:websocket" + ":" + "1", message);
}
return R.ok();
}

/**
* 查询意图管理
列表
*/
@Override
@GetMapping("/list")
@RequiresPermissions(Auth.DM_INTENT_LIST)
public AjaxResult list(DmIntentQuery intent) {
return super.list(intent);
}

/**
* 查询意图管理
详细
*/
@Override
@GetMapping(value = "/{id}")
@RequiresPermissions(Auth.DM_INTENT_SINGLE)
public AjaxResult getInfo(@PathVariable Serializable id) {
return super.getInfo(id);
}

/**
* 意图管理
新增
*/
@Override
@PostMapping
@RequiresPermissions(Auth.DM_INTENT_ADD)
@Log(title = "意图管理", businessType = BusinessType.INSERT)
public AjaxResult add(@Validated({V_A.class}) @RequestBody DmIntentDto intent) {
return super.add(intent);
}

/**
* 意图管理
修改
*/
@Override
@PutMapping
@RequiresPermissions(Auth.DM_INTENT_EDIT)
@Log(title = "意图管理", businessType = BusinessType.UPDATE)
public AjaxResult edit(@Validated({V_E.class}) @RequestBody DmIntentDto intent) {
return super.edit(intent);
}

/**
* 意图管理
修改状态
*/
@Override
@PutMapping("/status")
@RequiresPermissions(value = {Auth.DM_INTENT_EDIT, Auth.DM_INTENT_ES}, logical = Logical.OR)
@Log(title = "意图管理", businessType = BusinessType.UPDATE_STATUS)
public AjaxResult editStatus(@RequestBody DmIntentDto intent) {
return super.editStatus(intent);
}

/**
* 意图管理
批量删除
*/
@Override
@DeleteMapping("/batch/{idList}")
@RequiresPermissions(Auth.DM_INTENT_DEL)
@Log(title = "意图管理", businessType = BusinessType.DELETE)
public AjaxResult batchRemove(@PathVariable List<Long> idList) {
return super.batchRemove(idList);
}

/**
* 获取意图管理
选择框列表
*/
@Override
@GetMapping("/option")
public AjaxResult option() {
return super.option();
}



interface Auth {
/** 系统 - 意图管理
管理 - 列表 */
String DM_INTENT_LIST = "nlt:intent:list";
/** 系统 - 意图管理
管理 - 详情 */
String DM_INTENT_SINGLE = "nlt:intent:single";
/** 系统 - 意图管理
管理 - 新增 */
String DM_INTENT_ADD = "nlt:intent:add";
/** 系统 - 意图管理
管理 - 修改 */
String DM_INTENT_EDIT = "nlt:intent:edit";
/** 系统 - 意图管理
管理 - 修改状态 */
String DM_INTENT_ES = "nlt:intent:es";
/** 系统 - 意图管理
管理 - 删除 */
String DM_INTENT_DEL = "nlt:intent:delete";
}
}

+ 14
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/domain/dto/DmIntentDto.java Просмотреть файл

@@ -0,0 +1,14 @@
package com.xueyi.nlt.nlt.domain.dto;


import com.xueyi.nlt.nlt.domain.po.DmIntentPo;
import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper = true)
public class DmIntentDto extends DmIntentPo {

private static final long serialVersionUID = 1L;

}

+ 13
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/domain/model/DmIntentConverter.java Просмотреть файл

@@ -0,0 +1,13 @@
package com.xueyi.nlt.nlt.domain.model;

import com.xueyi.common.core.web.entity.model.BaseConverter;
import com.xueyi.nlt.nlt.domain.dto.DmIntentDto;
import com.xueyi.nlt.nlt.domain.po.DmIntentPo;
import com.xueyi.nlt.nlt.domain.query.DmIntentQuery;
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;


@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface DmIntentConverter extends BaseConverter<DmIntentQuery, DmIntentDto, DmIntentPo> {
}

+ 61
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/domain/po/DmIntentPo.java Просмотреть файл

@@ -0,0 +1,61 @@
package com.xueyi.nlt.nlt.domain.po;

import com.baomidou.mybatisplus.annotation.TableName;
import com.xueyi.common.core.annotation.Excel;
import com.xueyi.common.core.web.tenant.base.TBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serial;

import static com.xueyi.common.core.constant.basic.EntityConstants.REMARK;
import static com.xueyi.common.core.constant.basic.EntityConstants.SORT;

/**
* 访客 持久化对象
*
* @author xueyi
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName(value = "dm_skills", excludeProperty = { SORT, REMARK })
public class DmIntentPo extends TBaseEntity {

@Serial
private static final long serialVersionUID = 1L;

/** 数字人id */
@Excel(name = "数字人id")
protected Long manId;

/** 技能id */
@Excel(name = "技能id")
protected String skillCode;

/** 技能名称 */
@Excel(name = "技能名称")
protected String name;

/** 技能信息 */
@Excel(name = "技能信息")
protected String info;

/** 访客公司 */
@Excel(name = "访客公司")
protected String resp;

/** 访客称呼 */
@Excel(name = "访客称呼")
protected Long motionId;

protected String motionName;

protected Integer firstCall;

protected String auth;

protected String intent;

protected String template;

}

+ 13
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/domain/query/DmIntentQuery.java Просмотреть файл

@@ -0,0 +1,13 @@
package com.xueyi.nlt.nlt.domain.query;


import com.xueyi.nlt.nlt.domain.po.DmIntentPo;
import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper = true)
public class DmIntentQuery extends DmIntentPo {

private static final long serialVersionUID = 1L;
}

+ 16
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/domain/vo/IntentTemplateVo.java Просмотреть файл

@@ -0,0 +1,16 @@
package com.xueyi.nlt.nlt.domain.vo;

import com.alibaba.fastjson2.JSONObject;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class IntentTemplateVo {
private String msg;
private JSONObject format;
/**
* 是否触发技能
*/
private Integer target;
}

+ 8
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/manager/IDmIntentManager.java Просмотреть файл

@@ -0,0 +1,8 @@
package com.xueyi.nlt.nlt.manager;

import com.xueyi.common.web.entity.manager.IBaseManager;
import com.xueyi.nlt.nlt.domain.dto.DmIntentDto;
import com.xueyi.nlt.nlt.domain.query.DmIntentQuery;

public interface IDmIntentManager extends IBaseManager<DmIntentQuery, DmIntentDto> {
}

+ 15
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/manager/impl/DmIntentManager.java Просмотреть файл

@@ -0,0 +1,15 @@
package com.xueyi.nlt.nlt.manager.impl;

import com.xueyi.common.web.entity.manager.impl.BaseManagerImpl;
import com.xueyi.nlt.nlt.domain.dto.DmIntentDto;
import com.xueyi.nlt.nlt.domain.model.DmIntentConverter;
import com.xueyi.nlt.nlt.domain.po.DmIntentPo;
import com.xueyi.nlt.nlt.domain.query.DmIntentQuery;
import com.xueyi.nlt.nlt.manager.IDmIntentManager;
import com.xueyi.nlt.nlt.mapper.DmIntentMapper;
import org.springframework.stereotype.Component;

@Component
public class DmIntentManager extends BaseManagerImpl<DmIntentQuery, DmIntentDto, DmIntentPo, DmIntentMapper, DmIntentConverter> implements IDmIntentManager {

}

+ 11
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/mapper/DmIntentMapper.java Просмотреть файл

@@ -0,0 +1,11 @@
package com.xueyi.nlt.nlt.mapper;

import com.xueyi.common.datasource.annotation.Isolate;
import com.xueyi.common.web.entity.mapper.BaseMapper;
import com.xueyi.nlt.nlt.domain.dto.DmIntentDto;
import com.xueyi.nlt.nlt.domain.po.DmIntentPo;
import com.xueyi.nlt.nlt.domain.query.DmIntentQuery;

@Isolate
public interface DmIntentMapper extends BaseMapper<DmIntentQuery, DmIntentDto, DmIntentPo> {
}

+ 8
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/service/IDmIntentService.java Просмотреть файл

@@ -0,0 +1,8 @@
package com.xueyi.nlt.nlt.service;

import com.xueyi.common.web.entity.service.IBaseService;
import com.xueyi.nlt.nlt.domain.dto.DmIntentDto;
import com.xueyi.nlt.nlt.domain.query.DmIntentQuery;

public interface IDmIntentService extends IBaseService<DmIntentQuery, DmIntentDto> {
}

+ 12
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/service/impl/DmIntentServiceImpl.java Просмотреть файл

@@ -0,0 +1,12 @@
package com.xueyi.nlt.nlt.service.impl;

import com.xueyi.common.web.entity.service.impl.BaseServiceImpl;
import com.xueyi.nlt.nlt.domain.dto.DmIntentDto;
import com.xueyi.nlt.nlt.domain.query.DmIntentQuery;
import com.xueyi.nlt.nlt.manager.IDmIntentManager;
import com.xueyi.nlt.nlt.service.IDmIntentService;
import org.springframework.stereotype.Service;

@Service
public class DmIntentServiceImpl extends BaseServiceImpl<DmIntentQuery, DmIntentDto, IDmIntentManager> implements IDmIntentService {
}

+ 7
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/template/BaseTemplate.java Просмотреть файл

@@ -0,0 +1,7 @@
package com.xueyi.nlt.nlt.template;

import com.alibaba.fastjson2.JSONObject;

public interface BaseTemplate {
JSONObject handle(String dev, String content);
}

+ 93
- 0
xueyi-modules/xueyi-nlt/src/main/java/com/xueyi/nlt/nlt/template/MeetingOrderTemplate.java Просмотреть файл

@@ -0,0 +1,93 @@
package com.xueyi.nlt.nlt.template;

import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.xueyi.common.core.web.result.R;
import com.xueyi.nlt.netty.client.WebSocketClient;
import com.xueyi.nlt.nlt.controller.DmIntentController;
import com.xueyi.system.api.meeting.feign.RemoteMeetingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;


@Service("meeting-order")
public class MeetingOrderTemplate implements BaseTemplate {

private static final Logger log = LoggerFactory.getLogger(MeetingOrderTemplate.class);
@Autowired
WebSocketClient webSocketClient;

// @Autowired
// RemoteMeetingService remoteMeetingService;

@Autowired
private RemoteMeetingService remoteMeetingService;
@Autowired
private StringRedisTemplate redisTemplate;

@Override
public JSONObject handle(String devId, String content) {
synchronized (WebSocketClient.LOCK) {
LocalDateTime date = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00");
DateTimeFormatter scheduleFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
// String prefix = "假设你是一位前台,你需要通过与其他人对话来获取会议相关信息,已知今天是" +
// date.format(formatter) + ",你需要获取会议日期,开始时间,持续时间,会议地点,会议主题。时间用类似00:00的格式输出。对方的话中可能不包含全部信息,对于未知的信息填充为none。如果所有信息都已知那么commit为true。否则为false。将你获得的信息输出为json格式。对方的话是:“";
// String suffix = "”,只输出最后的json。输出只有一行,输出格式为{date:,start_time:,duration:,location:,theme:commit:}。";
// remoteMeetingService.roomListInner()
// String prefix = "我想请你充当[企业前台], 已知现在是" +
// date.format(formatter) + "。我对你说:”";
// String suffix = "”。会议地点:{" + "大会议室,小会议室" + "}。会议内容:{其他会议,例会,访客接待,面试}。未知的项目输出null。输出为{date:,start_time:,duration_hours:,location:,meeting_content:}";
// String prefix = "我想请你充当[SQL数据库],我需要的数据格式为{date:,start_time:,location:,meeting_theme:},没有数据不返回字段,数据只能来自于如下文段:\"已知现在是" +
// date.format(formatter) + ",";
// String suffix = "\",只输出最后的JSON结果。不要输出任何解释说明或者代码。";
String prefix = "当前时间是" +
date.format(formatter) + " " + date.getDayOfWeek() + "。我将提供一些用户输入的信息,请提取输入的内容进行结构化转换并输出对应 json 格式的代码。下面是结构的描述:会议日期date(格式为YYYY-MM-DD);具体时间start_time(格式HH:MM);会议室地点location; 下面是用户的输入信息:\"";
String suffix = "\"。请开始信息提取,你回复的内容必须是一个json结构,我只要json结果,不需要代码。";
log.info(prefix + content + suffix);
webSocketClient.sendMsg(prefix + content + suffix);
try {
WebSocketClient.LOCK.wait();
String result = redisTemplate.opsForValue().get("group:websocket:content");
try {
//对result进行解析,获取字符串第一个与'{'和最后一个'}'之间的字符串,即为json字符串
result = result.substring(result.indexOf("{"), result.lastIndexOf("}") + 1);
System.out.println(result);
JSONObject jo = JSONObject.parseObject(result);
R<List<JSONObject>> recentListR = null;
if (jo.get("start_time") != null ) {
if (jo.get("start_time").equals("00:00")) {
recentListR = remoteMeetingService.ableOrderList(devId, jo.getString("date"), null, null);
} else {
recentListR = remoteMeetingService.ableOrderList(devId, jo.getString("date"), null, jo.getString("start_time"));
}
if (recentListR.isOk()) {
jo.put("start_time",recentListR.getData().get(0).get("startTime"));
jo.put("location",recentListR.getData().get(0).get("roomId"));
}
}

return jo;
} catch (JSONException je) {
// 返回结果错误,计日志,存log,返回空结果
log.error(je.getMessage(),je);
return null;
}

} catch (InterruptedException e) {
log.warn(e.getMessage());
}
}
return null;
}
}

+ 10
- 0
xueyi-modules/xueyi-nlt/src/main/resources/banner.txt Просмотреть файл

@@ -0,0 +1,10 @@
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}
_______ _________ _ _________
|\ /||\ /|( ____ \|\ /|\__ __/ ( ( /||\ \__ __/
( \ / )| ) ( || ( \/( \ / ) ) ( | \ ( || ) ) (
\ (_) / | | | || (__ \ (_) / | | _____ | \ | || | | |
) _ ( | | | || __) \ / | |(_____)| (\ \) || | | |
/ ( ) \ | | | || ( ) ( | | | | \ || | | |
( / \ )| (___) || (____/\ | | ___) (___ | ) \ || (____/\ | |
|/ \|(_______)(_______/ \_/ \_______/ |/ )_)(_______/ )_(

+ 34
- 0
xueyi-modules/xueyi-nlt/src/main/resources/bootstrap.yml Просмотреть файл

@@ -0,0 +1,34 @@
# Tomcat
server:
port: 9901

# Spring
spring:
application:
# 应用名称
name: xueyi-nlt
profiles:
# 环境配置
active: @activatedProperties@
servlet:
multipart:
max-request-size: 20MB
max-file-size: 100MB
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: @nacos.host@:@nacos.port@
namespace: @nacos.namespace@

config:
# 配置中心地址
server-addr: @nacos.host@:@nacos.port@
namespace: @nacos.namespace@
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
- application-secret-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
- application-datasource-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

+ 74
- 0
xueyi-modules/xueyi-nlt/src/main/resources/logback.xml Просмотреть файл

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/xueyi-nlt" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />

<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>

<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<!-- 系统模块日志级别控制 -->
<logger name="com.xueyi" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />

<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
</configuration>

+ 9
- 0
xueyi-modules/xueyi-system/pom.xml Просмотреть файл

@@ -41,6 +41,11 @@
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- SpringBoot Mock -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- XueYi Common Log -->
<dependency>
<groupId>com.xueyi</groupId>
@@ -103,6 +108,10 @@
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
<dependency>
<groupId>com.xueyi</groupId>
<artifactId>xueyi-api-nlt</artifactId>
</dependency>


</dependencies>


+ 38
- 0
xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/digitalmans/controller/DmDigitalmanController.java Просмотреть файл

@@ -11,6 +11,7 @@ import com.xueyi.common.core.web.result.AjaxResult;
import com.xueyi.common.core.web.result.R;
import com.xueyi.common.core.web.validate.V_A;
import com.xueyi.common.core.web.validate.V_E;
import com.xueyi.common.datasource.annotation.Master;
import com.xueyi.common.log.annotation.Log;
import com.xueyi.common.log.enums.BusinessType;
import com.xueyi.common.security.annotation.InnerAuth;
@@ -32,11 +33,13 @@ import com.xueyi.system.digitalmans.domain.dto.DmDigitalmanExtDto;
import com.xueyi.system.digitalmans.domain.model.DmDigitalmanExtConverter;
import com.xueyi.system.digitalmans.domain.query.DmDigitalmanExtQuery;
import com.xueyi.system.digitalmans.domain.query.DmDigitalmanQuery;
import com.xueyi.system.digitalmans.domain.query.DmManDeviceQuery;
import com.xueyi.system.digitalmans.mapper.DmManDeviceMapper;
import com.xueyi.system.digitalmans.service.IDmDigitalmanExtService;
import com.xueyi.system.digitalmans.service.IDmDigitalmanService;
import com.xueyi.system.digitalmans.service.IDmModelService;
import com.xueyi.system.digitalmans.service.IDmSkillService;
import com.xueyi.system.digitalmans.service.impl.DmManDeviceServiceImpl;
import com.xueyi.system.emcs.constant.EmcsUploadType;
import com.xueyi.system.emcs.domain.dto.DmDeviceLogFileDto;
import com.xueyi.system.emcs.domain.dto.DmExceptionLogDto;
@@ -63,6 +66,7 @@ import java.io.Serializable;
import java.text.ParseException;
import java.time.Duration;
import java.util.List;
import java.util.stream.Collectors;

/**
* 数字人基础管理 业务处理
@@ -382,6 +386,40 @@ public class DmDigitalmanController extends BaseController<DmDigitalmanQuery, Dm
return R.fail("请检查请求参数");
}


@Autowired
DmManDeviceServiceImpl dmManDeviceService;
@GetMapping("/api/mansInfo")
@Master
public R<JSONObject> mansInfo() {

List<DmManDeviceDto> dtos = dmManDeviceService.selectList(new DmManDeviceQuery());
List<DmManDeviceDto> dtos2 = dtos.stream().filter(dto -> StringUtils.isNotEmpty(dto.getDeviceId())).collect(Collectors.toList());;
System.err.println(dtos2.size());
Long serviceTimeCount = 0L;
//当前时间和activateTime时间的差值,activateTime类型是Date,差值返回的单位是小时
for (DmManDeviceDto dto : dtos2) {
serviceTimeCount += (System.currentTimeMillis() - dto.getActivateTime().getTime())/3600000;
}

Integer meetingServiceCount = (Integer) redisTemplate.opsForValue().get("dashboard:meeting");
Integer serverTimes = (Integer) redisTemplate.opsForValue().get("dashboard:server");
log.info("meetingServiceCount:{}",meetingServiceCount);
log.info("serverTimes:{}",serverTimes);

JSONObject json = new JSONObject();
json.put("manCount",dtos2.size());
json.put("serviceTimeCount",serviceTimeCount);
json.put("servicePerCount",serverTimes);
json.put("meetingServiceCount",meetingServiceCount);
System.err.println(json.toJSONString());
return R.ok(json);
}





@GetMapping("/api/devInfo/{devId}")
public R<DmDigitalmanExtPo> devInfo(@PathVariable(required = true) String devId) {
if (StringUtils.isNotEmpty(devId)){


+ 33
- 0
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<DmMeetingRoomsDto> 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) {
@@ -141,4 +153,25 @@ public class DmMeetingApiController extends BaseApiController {

return ImageUtil.urlImageToBase64(url);
}


@GetMapping(value = "/recent/{devId}/{dateStr}")
@ResponseBody
public R<List<JSONObject>> 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){
DeviceTenantSourceMergeVo vo = super.getDeviceTenantSourceMergeVo(devId);

R<DmDigitalmanExtPo> extR = digitalmanService.selectExtByDeviceId(devId,vo.getTenantId(),vo.getSourceSlave(), SecurityConstants.INNER);
DmDigitalmanExtPo extPo = null;
if (null != extR) {
extPo = extR.getData();
}
if (extPo != null) {
List<JSONObject> result = remoteMeetingService.recent(extPo.getDeptId(),dateStr, roomId, startTime, vo.getTenantId(),vo.getSourceSlave(), SecurityConstants.INNER);
return R.ok(result);
} else {
return R.fail("未找到设备信息");
}


}
}

+ 186
- 1
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,18 +39,27 @@ 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;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* 会议室预约管理 API
@@ -86,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}")
@@ -181,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<DmManDeviceDto> 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();
}

@@ -292,7 +341,7 @@ public class DmMeetingInnerApiController extends BaseApiController {
@GetMapping(value = "/lists")
public JSONObject listAllInner() {
List<DmMeetingOrdersPo> list = dmMeetingOrdersMapper.findAllList();
List<DmMeetingOrdersDto> res = new ArrayList<>();
List<DmMeetingOrdersPo> res = new ArrayList<>();
list.forEach(item -> {
DmMeetingOrdersDto dto = dmMeetingOrdersConverter.mapperDto(item);
DmMeetingRoomsPo mr = dmMeetingRoomsMapper.findById(dto.getSpaceId());
@@ -303,4 +352,140 @@ public class DmMeetingInnerApiController extends BaseApiController {
return outputSuccess(res).toJSON();
}

List freeTimePart (Long roomId, List<DmMeetingOrdersPo> objects, String currentTime) {
List<JSONObject> freeTimeList = new ArrayList<>();

if (null == objects || objects.size() ==0) {
JSONObject json = new JSONObject();
json.put("startTime", currentTime);
json.put("endTime", 0);
json.put("roomId", roomId);
freeTimeList.add(json);
return freeTimeList;
}
if (objects.size() ==1) {
DmMeetingOrdersPo current = objects.get(0);
if (DateUtils.formatDate(current.getStartTime(), "HH:mm").compareTo(currentTime) > 0 ) {
JSONObject json = new JSONObject();
json.put("startTime", currentTime);
json.put("endTime", DateUtils.formatDate(current.getStartTime(), "HH:mm"));
json.put("roomId", roomId);
freeTimeList.add(json);
}
JSONObject json = new JSONObject();
json.put("startTime", DateUtils.formatDate(current.getEndTime(), "HH:mm"));
json.put("endTime", 0);
json.put("roomId", roomId);
freeTimeList.add(json);
return freeTimeList;
}
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
objects = objects.stream().sorted(Comparator.comparing(po -> DateUtils.formatDate(po.getStartTime(), "HH:mm"))).collect(Collectors.toList());
if (objects.size() > 1)
for (int i = 0; i < objects.size() - 1; i++) {
DmMeetingOrdersPo current = objects.get(i);
DmMeetingOrdersPo next = objects.get(i + 1);

Date freeStartTime = current.getEndTime();
Date freeEndTime = next.getStartTime();

String freeStartTimeStr = DateUtils.formatDate(current.getEndTime(), "HH:mm");
String freeEndTimeStr = DateUtils.formatDate(next.getStartTime(), "HH:mm");

if (i==0 && DateUtils.formatDate(current.getStartTime(), "HH:mm").compareTo(currentTime) > 0 ) {
JSONObject json = new JSONObject();
json.put("startTime", currentTime);
json.put("endTime", DateUtils.formatDate(current.getStartTime(), "HH:mm"));
json.put("roomId", roomId);
freeTimeList.add(json);
}

if (freeStartTime.before(freeEndTime)) {
JSONObject json = new JSONObject();
json.put("startTime", freeStartTimeStr);
json.put("endTime", freeEndTimeStr);
json.put("roomId", roomId);
freeTimeList.add(json);
}

if (i==objects.size() - 2) {
JSONObject json = new JSONObject();
if (DateUtils.formatDate(next.getEndTime(), "HH:mm").compareTo(currentTime)>0) {
json.put("startTime", DateUtils.formatDate(next.getEndTime(), "HH:mm"));
} else {
json.put("startTime", currentTime);
}
json.put("endTime", 0);
json.put("roomId", current.getSpaceId());
freeTimeList.add(json);
}
}
return freeTimeList;
}

@InnerAuth
@GetMapping("/recent/{deptId}/{dateStr}")
@ResponseBody
public List<JSONObject> 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, HttpServletRequest request) {

List<DmMeetingOrdersPo> list = new ArrayList<>();
List<Long> ids = new ArrayList<>();
Map<Long, String> rooms = new HashMap<>();
if (null == roomId) {
DmMeetingRoomsPo dm = new DmMeetingRoomsPo();
dm.setDeptId(deptId);
List<DmMeetingRoomsPo> pos = dmMeetingRoomsMapper.selectRoomList(dm);
ids = pos.stream().map(DmMeetingRoomsPo::getId).collect(Collectors.toList());
rooms = pos.stream().collect(Collectors.toMap(DmMeetingRoomsPo::getId, DmMeetingRoomsPo::getName));
list = dmMeetingOrdersMapper.findListByDateStr(dateStr);
} else {
DmMeetingRoomsPo po = dmMeetingRoomsMapper.findById(roomId);
list = dmMeetingOrdersMapper.findListByDate(dateStr, po.getId());
ids.add(roomId);
rooms.put(po.getId(), po.getName());
}


//过滤掉今天的已经过去的预约记录,并按开始时间进行排序
list = list.stream().filter(t->DateUtils.formatDate(t.getOrderDate(), "yyyy-MM-dd").compareTo(DateUtils.formatDate(new Date(), "yyyy-MM-dd"))>0 || (DateUtils.formatDate(t.getOrderDate(), "yyyy-MM-dd").compareTo(DateUtils.formatDate(new Date(), "yyyy-MM-dd"))==0 && DateUtils.formatDate(t.getStartTime(), "HH:mm").compareTo(DateUtils.formatDate(new Date(), "HH:mm"))>0)).sorted(Comparator.comparing(po -> DateUtils.formatDate(po.getStartTime(), "HH:mm"))).collect(Collectors.toList());


//获得当前时间开始最近的整点,或者半点
String currentStr = "08:00";
if (StringUtils.isNotEmpty(startTime)) {
currentStr = startTime;
}

if (dateStr.compareTo(DateUtils.formatDate(new Date(), "yyyy-MM-dd")) == 0) {
LocalTime currentTime = LocalTime.now();
if (currentTime.getMinute() >= 30) {
currentTime = currentTime.plusHours(1).withMinute(0).withSecond(0);
} else {
currentTime = currentTime.withMinute(30).withSecond(0);
}

currentStr = currentTime.format(DateTimeFormatter.ofPattern("HH:mm"));
}

Map<Long, List<DmMeetingOrdersPo>> groupedByRoom = list.stream()
.collect(Collectors.groupingBy(DmMeetingOrdersPo::getSpaceId));

Map<Long, List<JSONObject>> freeTime = new HashMap<>();

for(int i=0;i<ids.size();i++){
Long key = ids.get(i);
//groupedByRoom.get(key)可能为空
freeTime.put(key, freeTimePart(key, groupedByRoom.get(key), currentStr));
}
List<JSONObject> arr = new ArrayList<>();
for (int i=0;i<freeTime.keySet().size();i++){
Long key = (Long) freeTime.keySet().toArray()[i];
List<JSONObject> value = freeTime.get(key);
arr.addAll(freeTime.get(key));
}
Map<Long, String> finalRooms = rooms;
arr = arr.stream().map(j->{j.put("roomName", finalRooms.get(j.getLong("roomId")));return j;}).sorted(Comparator.comparing(po -> po.getString("startTime"))).collect(Collectors.toList());
return arr;
}

}

+ 2
- 0
xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/staff/controller/api/DmStaffInnerApiController.java Просмотреть файл

@@ -90,6 +90,7 @@ public class DmStaffInnerApiController extends BaseApiController {
if (r.getData() instanceof DmResourcesDto) {
DmResourcesDto dmResourcesDto = (DmResourcesDto) r.getData();
v.setResourceId(dmResourcesDto.getId());
v.setAvatar(dmResourcesDto.getUrl());
} else {
return output(ResponseCode.FILE_UPLOAD_FAIL, r.getMsg()).toJSON();
}
@@ -108,6 +109,7 @@ public class DmStaffInnerApiController extends BaseApiController {
if (r.getData() instanceof DmResourcesDto) {
DmResourcesDto dmResourcesDto = (DmResourcesDto) r.getData();
staffPo.setResourceId(dmResourcesDto.getId());
staffPo.setAvatar(dmResourcesDto.getUrl());
} else {
return output(ResponseCode.FILE_UPLOAD_FAIL, r.getMsg()).toJSON();
}


Загрузка…
Отмена
Сохранить