mirror of
https://gitcode.com/ageerle/ruoyi-ai.git
synced 2026-04-08 01:07:31 +00:00
Compare commits
29 Commits
v2.0.1
...
2b8a92c7d6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b8a92c7d6 | ||
|
|
adb4538317 | ||
|
|
2509099146 | ||
|
|
3be9005f95 | ||
|
|
be6d027cad | ||
|
|
3d679f8749 | ||
|
|
5a5a48e153 | ||
|
|
e5da648941 | ||
|
|
d2755f00bc | ||
|
|
00f362acf1 | ||
|
|
65d479458e | ||
|
|
57e17e0dda | ||
|
|
691d1735fc | ||
|
|
360984bc4b | ||
|
|
0153f004f4 | ||
|
|
cc23508527 | ||
|
|
c884f4f2d3 | ||
|
|
fab6de1f5c | ||
|
|
c02f66636d | ||
|
|
c1162148b1 | ||
|
|
f76fdbf3ad | ||
|
|
feca08b3ec | ||
|
|
72675b17c4 | ||
|
|
9ea5186f49 | ||
|
|
d0a2eadc38 | ||
|
|
ae141a6591 | ||
|
|
d3f4d7b8ca | ||
|
|
b8e7a406d3 | ||
|
|
412e8bdc10 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,6 +1,9 @@
|
||||
######################################################################
|
||||
# Build Tools
|
||||
|
||||
|
||||
|
||||
|
||||
.gradle
|
||||
/build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
@@ -8,6 +11,8 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
ruoyi-modules/ruoyi-generator/src/main/resources/vm/vben5
|
||||
|
||||
######################################################################
|
||||
# IDE
|
||||
|
||||
|
||||
11
README.md
11
README.md
@@ -59,7 +59,7 @@
|
||||
- 演示地址: https://web.pandarobot.chat
|
||||
- 后台管理: https://admin.pandarobot.chat
|
||||
- 用户名: admin 密码:admin123
|
||||
-
|
||||
|
||||
### gitcode源码地址
|
||||
- https://gitcode.com/ageerle/ruoyi-ai
|
||||
- https://gitcode.com/ageerle/ruoyi-web
|
||||
@@ -168,16 +168,11 @@ RuoYi-AI
|
||||
|
||||
该项目使用了MIT授权许可,详情请参阅 [LICENSE.txt](https://github.com/ageerle/ruoyi-ai/blob/main/LICENSE)
|
||||
|
||||
|
||||
### 作者寄语
|
||||
|
||||
最近,我们的项目意外地受到了广泛关注,甚至被许多人误以为是一个已经成熟且能够快速落地的项目。然而,事实并非如此。这个项目是我个人在业余时间进行的研究,主要目的是学习和探索。它是一个以人工智能(AI)为核心的平台,旨在帮助企业通过配置的方式快速构建AI应用。
|
||||
|
||||
#### 项目现状
|
||||
### 项目现状
|
||||
|
||||
目前,项目还处于早期阶段,距离成熟还有很长的路要走。由于个人精力有限,项目的发展速度受到了一定的限制。为了加快项目的进度,我真诚地希望更多人能够参与到项目中来。无论是经验丰富的开发者,还是刚刚入门的小白,我都热烈欢迎你们提交Pull Request(PR)。即使代码修改得很少,或者存在一些错误,都没有关系。我会认真审核每一位贡献者的代码,并和大家一起完善项目。
|
||||
|
||||
#### 开发计划
|
||||
### 开发计划
|
||||
|
||||
- 智能体管理
|
||||
|
||||
|
||||
38
pom.xml
38
pom.xml
@@ -18,6 +18,7 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
<mysql.version>8.0.33</mysql.version>
|
||||
<spring-boot.mybatis>3.0.1</spring-boot.mybatis>
|
||||
<springdoc.version>2.1.0</springdoc.version>
|
||||
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
|
||||
@@ -60,6 +61,7 @@
|
||||
<weixin-java-miniapp.version>4.5.0</weixin-java-miniapp.version>
|
||||
<weixin-java-pay.version>4.6.0</weixin-java-pay.version>
|
||||
<weixin-java-cp.version>4.6.0</weixin-java-cp.version>
|
||||
<weixin-java-cp.version>4.6.0</weixin-java-cp.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
@@ -96,6 +98,12 @@
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${mysql.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot的依赖配置-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -244,18 +252,6 @@
|
||||
<version>${tencent.sms.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>de.codecentric</groupId>-->
|
||||
<!-- <artifactId>spring-boot-admin-starter-server</artifactId>-->
|
||||
<!-- <version>${spring-boot-admin.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>de.codecentric</groupId>-->
|
||||
<!-- <artifactId>spring-boot-admin-starter-client</artifactId>-->
|
||||
<!-- <version>${spring-boot-admin.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!--redisson-->
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||
@@ -317,14 +313,25 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-fusion</artifactId>
|
||||
<artifactId>ruoyi-chat</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-knowledge-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-knowledge</artifactId>
|
||||
<artifactId>ruoyi-chat-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
@@ -344,10 +351,11 @@
|
||||
</dependencyManagement>
|
||||
|
||||
<modules>
|
||||
<module>ruoyi-admin</module>
|
||||
<module>ruoyi-common</module>
|
||||
<module>ruoyi-modules</module>
|
||||
<module>ruoyi-modules-api</module>
|
||||
</modules>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#基础镜像
|
||||
FROM findepi/graalvm:java17-native
|
||||
|
||||
# 设置环境变量
|
||||
ENV LANG C.UTF-8
|
||||
ENV LANGUAGE C.UTF-8
|
||||
ENV LC_ALL C.UTF-8
|
||||
ENV SERVER_PORT=6039
|
||||
|
||||
MAINTAINER ageerle
|
||||
|
||||
RUN mkdir -p /ruoyi/server/logs \
|
||||
/ruoyi/server/temp \
|
||||
/ruoyi/skywalking/agent
|
||||
|
||||
|
||||
#工作空间
|
||||
WORKDIR /ruoyi/server
|
||||
|
||||
|
||||
|
||||
EXPOSE ${SERVER_PORT}
|
||||
|
||||
ADD ./target/ruoyi-admin.jar ./app.jar
|
||||
|
||||
|
||||
ENTRYPOINT ["java", \
|
||||
"-Djava.security.egd=file:/dev/./urandom", \
|
||||
"-Dserver.port=${SERVER_PORT}", \
|
||||
# 应用名称 如果想区分集群节点监控 改成不同的名称即可
|
||||
# "-Dskywalking.agent.service_name=ruoyi-server", \
|
||||
# "-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar", \
|
||||
"-jar", "app.jar"]
|
||||
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi-ai</artifactId>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>ruoyi-admin</artifactId>
|
||||
|
||||
<description>
|
||||
web服务入口
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- Mysql驱动包 -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Oracle -->
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.jdbc</groupId>
|
||||
<artifactId>ojdbc8</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- PostgreSql -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SqlServer -->
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-doc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-fusion</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-knowledge</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-generator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- demo模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-demo</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 添加thumbnailator依赖 -->
|
||||
<dependency>
|
||||
<groupId>net.coobird</groupId>
|
||||
<artifactId>thumbnailator</artifactId>
|
||||
<version>0.4.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.ollama4j</groupId>
|
||||
<artifactId>ollama4j</artifactId>
|
||||
<version>1.0.79</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>${maven-jar-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>${maven-war-plugin.version}</version>
|
||||
<configuration>
|
||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||
<warName>${project.artifactId}</warName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -1,208 +0,0 @@
|
||||
package org.ruoyi.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.ruoyi.common.chat.config.ChatConfig;
|
||||
import org.ruoyi.common.chat.domain.request.ChatRequest;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
|
||||
import org.ruoyi.common.chat.entity.chat.Message;
|
||||
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
|
||||
import org.ruoyi.common.core.domain.R;
|
||||
import org.ruoyi.common.core.validate.AddGroup;
|
||||
import org.ruoyi.common.excel.utils.ExcelUtil;
|
||||
import org.ruoyi.common.log.annotation.Log;
|
||||
import org.ruoyi.common.log.enums.BusinessType;
|
||||
import org.ruoyi.common.mybatis.core.page.PageQuery;
|
||||
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
|
||||
import org.ruoyi.common.satoken.utils.LoginHelper;
|
||||
import org.ruoyi.common.web.core.BaseController;
|
||||
import org.ruoyi.knowledge.domain.bo.KnowledgeAttachBo;
|
||||
import org.ruoyi.knowledge.domain.bo.KnowledgeFragmentBo;
|
||||
import org.ruoyi.knowledge.domain.bo.KnowledgeInfoBo;
|
||||
import org.ruoyi.knowledge.domain.req.KnowledgeInfoUploadRequest;
|
||||
import org.ruoyi.knowledge.domain.vo.KnowledgeAttachVo;
|
||||
import org.ruoyi.knowledge.domain.vo.KnowledgeFragmentVo;
|
||||
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
|
||||
import org.ruoyi.knowledge.service.EmbeddingService;
|
||||
import org.ruoyi.knowledge.service.IKnowledgeAttachService;
|
||||
import org.ruoyi.knowledge.service.IKnowledgeFragmentService;
|
||||
import org.ruoyi.knowledge.service.IKnowledgeInfoService;
|
||||
import org.ruoyi.system.listener.SSEEventSourceListener;
|
||||
import org.ruoyi.system.service.ISseService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.ruoyi.knowledge.chain.vectorstore.VectorStore;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 知识库
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2024-10-21
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/knowledge")
|
||||
public class KnowledgeController extends BaseController {
|
||||
|
||||
private final IKnowledgeInfoService knowledgeInfoService;
|
||||
|
||||
private final VectorStore vectorStore;
|
||||
|
||||
private final IKnowledgeAttachService attachService;
|
||||
|
||||
private final IKnowledgeFragmentService fragmentService;
|
||||
|
||||
private final EmbeddingService embeddingService;
|
||||
|
||||
private OpenAiStreamClient openAiStreamClient;
|
||||
|
||||
private final ChatConfig chatConfig;
|
||||
|
||||
private final ISseService sseService;
|
||||
|
||||
/**
|
||||
* 知识库对话
|
||||
*/
|
||||
@PostMapping("/send")
|
||||
public SseEmitter send(@RequestBody @Valid ChatRequest chatRequest) {
|
||||
|
||||
openAiStreamClient = chatConfig.getOpenAiStreamClient();
|
||||
SseEmitter sseEmitter = new SseEmitter(0L);
|
||||
SSEEventSourceListener openAIEventSourceListener = new SSEEventSourceListener(sseEmitter);
|
||||
List<Message> messages = chatRequest.getMessages();
|
||||
String content = messages.get(messages.size() - 1).getContent().toString();
|
||||
List<String> nearestList;
|
||||
List<Double> queryVector = embeddingService.getQueryVector(content, chatRequest.getKid());
|
||||
nearestList = vectorStore.nearest(queryVector,chatRequest.getKid());
|
||||
for (String prompt : nearestList) {
|
||||
Message sysMessage = Message.builder().content(prompt).role(Message.Role.USER).build();
|
||||
messages.add(sysMessage);
|
||||
}
|
||||
Message userMessage = Message.builder().content(content + (nearestList.size() > 0 ? "\n\n注意:回答问题时,须严格根据我给你的系统上下文内容原文进行回答,请不要自己发挥,回答时保持原来文本的段落层级" : "") ).role(Message.Role.USER).build();
|
||||
messages.add(userMessage);
|
||||
if (chatRequest.getModel().startsWith("ollama")) {
|
||||
return sseService.ollamaChat(chatRequest);
|
||||
}
|
||||
|
||||
ChatCompletion completion = ChatCompletion
|
||||
.builder()
|
||||
.messages(messages)
|
||||
.model(chatRequest.getModel())
|
||||
.temperature(chatRequest.getTemperature())
|
||||
.topP(chatRequest.getTop_p())
|
||||
.stream(true)
|
||||
.build();
|
||||
openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener);
|
||||
|
||||
return sseEmitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户信息查询本地知识库
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<KnowledgeInfoVo> list(KnowledgeInfoBo bo, PageQuery pageQuery) {
|
||||
if(!StpUtil.isLogin()){
|
||||
return null;
|
||||
}
|
||||
bo.setUid(LoginHelper.getUserId());
|
||||
return knowledgeInfoService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增知识库
|
||||
*/
|
||||
@Log(title = "知识库", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/save")
|
||||
public R<Void> save(@Validated(AddGroup.class) @RequestBody KnowledgeInfoBo bo) {
|
||||
knowledgeInfoService.saveOne(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除知识库
|
||||
*/
|
||||
@PostMapping("/remove/{id}")
|
||||
public R<String> remove(@PathVariable String id){
|
||||
knowledgeInfoService.removeKnowledge(id);
|
||||
return R.ok("删除知识库成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改知识库
|
||||
*/
|
||||
@Log(title = "知识库", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/edit")
|
||||
public R<Void> edit( @RequestBody KnowledgeInfoBo bo) {
|
||||
return toAjax(knowledgeInfoService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出知识库列表
|
||||
*/
|
||||
@Log(title = "知识库", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(KnowledgeInfoBo bo, HttpServletResponse response) {
|
||||
List<KnowledgeInfoVo> list = knowledgeInfoService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "知识库", KnowledgeInfoVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询知识附件信息
|
||||
*/
|
||||
@GetMapping("/detail/{kid}")
|
||||
public TableDataInfo<KnowledgeAttachVo> attach(KnowledgeAttachBo bo, PageQuery pageQuery,@PathVariable String kid){
|
||||
bo.setKid(kid);
|
||||
return attachService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传知识库附件
|
||||
*/
|
||||
@PostMapping(value = "/attach/upload")
|
||||
public R<String> upload(KnowledgeInfoUploadRequest request){
|
||||
knowledgeInfoService.upload(request);
|
||||
return R.ok("上传知识库附件成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取知识库附件详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@GetMapping("attach/info/{id}")
|
||||
public R<KnowledgeAttachVo> getAttachInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(attachService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除知识库附件
|
||||
*
|
||||
*/
|
||||
@PostMapping("attach/remove/{docId}")
|
||||
public R<Void> removeAttach(@NotEmpty(message = "主键不能为空") @PathVariable String docId) {
|
||||
attachService.removeKnowledgeAttach(docId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询知识片段
|
||||
*/
|
||||
@GetMapping("/fragment/list/{docId}")
|
||||
public TableDataInfo<KnowledgeFragmentVo> fragmentList(KnowledgeFragmentBo bo, PageQuery pageQuery, @PathVariable String docId) {
|
||||
bo.setDocId(docId);
|
||||
return fragmentService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,13 +2,20 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ruoyi-ai</artifactId>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<description>
|
||||
common 通用模块
|
||||
</description>
|
||||
|
||||
<modules>
|
||||
<module>ruoyi-common-bom</module>
|
||||
@@ -32,15 +39,6 @@
|
||||
<module>ruoyi-common-encrypt</module>
|
||||
<module>ruoyi-common-tenant</module>
|
||||
<module>ruoyi-common-chat</module>
|
||||
<module>ruoyi-common-pay</module>
|
||||
<module>ruoyi-common-wechat</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<description>
|
||||
common 通用模块
|
||||
</description>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -159,29 +159,14 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 微信模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-wechat</artifactId>
|
||||
<artifactId>ruoyi-chat</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- AI绘画 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-fusion</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- 支付模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-pay</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</dependencyManagement>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
|
||||
<properties>
|
||||
<retrofit2.version>2.9.0</retrofit2.version>
|
||||
<azure.version>1.0.0-beta.12</azure.version>
|
||||
<chatglm.version>release-V4-2.3.0</chatglm.version>
|
||||
<okhttp.version>2.7.5</okhttp.version>
|
||||
<jtokkit.version>0.5.0</jtokkit.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -26,38 +30,22 @@
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 序列化模块 -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.33</version>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- redis模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-ai-openai</artifactId>
|
||||
<version>1.0.0-beta.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.ollama4j</groupId>
|
||||
<artifactId>ollama4j</artifactId>
|
||||
<version>1.0.79</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 序列化模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-json</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-satoken</artifactId>
|
||||
<version>${azure.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -79,13 +67,7 @@
|
||||
<dependency>
|
||||
<groupId>com.knuddels</groupId>
|
||||
<artifactId>jtokkit</artifactId>
|
||||
<version>0.5.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.12</version>
|
||||
<version>${jtokkit.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -98,21 +80,18 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.bigmodel.openapi</groupId>
|
||||
<artifactId>oapi-java-sdk</artifactId>
|
||||
<version>release-V4-2.3.0</version>
|
||||
<version>${chatglm.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>2.7.5</version>
|
||||
<scope>compile</scope>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -12,6 +12,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@Data
|
||||
public class WebSocketProperties {
|
||||
|
||||
/**
|
||||
* 是否开启
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okhttp3.sse.EventSource;
|
||||
import okhttp3.sse.EventSourceListener;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* 描述: sse
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-06-15
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConsoleEventSourceListenerV2 extends EventSourceListener {
|
||||
@Getter
|
||||
String args = "";
|
||||
final CountDownLatch countDownLatch;
|
||||
|
||||
public ConsoleEventSourceListenerV2(CountDownLatch countDownLatch) {
|
||||
this.countDownLatch = countDownLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(EventSource eventSource, Response response) {
|
||||
log.info("OpenAI建立sse连接...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(EventSource eventSource, String id, String type, String data) {
|
||||
log.info("OpenAI返回数据:{}", data);
|
||||
if (data.equals("[DONE]")) {
|
||||
log.info("OpenAI返回数据结束了");
|
||||
countDownLatch.countDown();
|
||||
return;
|
||||
}
|
||||
ChatCompletionResponse chatCompletionResponse = JSONUtil.toBean(data, ChatCompletionResponse.class);
|
||||
if(Objects.nonNull(chatCompletionResponse.getChoices().get(0).getDelta().getFunctionCall())){
|
||||
args += chatCompletionResponse.getChoices().get(0).getDelta().getFunctionCall().getArguments();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(EventSource eventSource) {
|
||||
log.info("OpenAI关闭sse连接...");
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void onFailure(EventSource eventSource, Throwable t, Response response) {
|
||||
if(Objects.isNull(response)){
|
||||
log.error("OpenAI sse连接异常:{}", t);
|
||||
eventSource.cancel();
|
||||
return;
|
||||
}
|
||||
ResponseBody body = response.body();
|
||||
if (Objects.nonNull(body)) {
|
||||
log.error("OpenAI sse连接异常data:{},异常:{}", body.string(), t);
|
||||
} else {
|
||||
log.error("OpenAI sse连接异常data:{},异常:{}", response, t);
|
||||
}
|
||||
eventSource.cancel();
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okhttp3.sse.EventSource;
|
||||
import okhttp3.sse.EventSourceListener;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse;
|
||||
import org.ruoyi.common.chat.entity.chat.Message;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolCallFunction;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolCalls;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* 描述: demo测试实现类,仅供思路参考
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-11-12
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConsoleEventSourceListenerV3 extends EventSourceListener {
|
||||
@Getter
|
||||
List<ToolCalls> choices = new ArrayList<>();
|
||||
@Getter
|
||||
ToolCalls toolCalls = new ToolCalls();
|
||||
@Getter
|
||||
ToolCallFunction toolCallFunction = ToolCallFunction.builder().name("").arguments("").build();
|
||||
final CountDownLatch countDownLatch;
|
||||
|
||||
public ConsoleEventSourceListenerV3(CountDownLatch countDownLatch) {
|
||||
this.countDownLatch = countDownLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(EventSource eventSource, Response response) {
|
||||
log.info("OpenAI建立sse连接...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(EventSource eventSource, String id, String type, String data) {
|
||||
log.info("OpenAI返回数据:{}", data);
|
||||
if (data.equals("[DONE]")) {
|
||||
log.info("OpenAI返回数据结束了");
|
||||
return;
|
||||
}
|
||||
ChatCompletionResponse chatCompletionResponse = JSONUtil.toBean(data, ChatCompletionResponse.class);
|
||||
Message delta = chatCompletionResponse.getChoices().get(0).getDelta();
|
||||
if (CollectionUtil.isNotEmpty(delta.getToolCalls())) {
|
||||
choices.addAll(delta.getToolCalls());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(EventSource eventSource) {
|
||||
if(CollectionUtil.isNotEmpty(choices)){
|
||||
toolCalls.setId(choices.get(0).getId());
|
||||
toolCalls.setType(choices.get(0).getType());
|
||||
choices.forEach(e -> {
|
||||
toolCallFunction.setName(e.getFunction().getName());
|
||||
toolCallFunction.setArguments(toolCallFunction.getArguments() + e.getFunction().getArguments());
|
||||
toolCalls.setFunction(toolCallFunction);
|
||||
});
|
||||
}
|
||||
log.info("OpenAI关闭sse连接...");
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void onFailure(EventSource eventSource, Throwable t, Response response) {
|
||||
if(Objects.isNull(response)){
|
||||
log.error("OpenAI sse连接异常:{}", t);
|
||||
eventSource.cancel();
|
||||
return;
|
||||
}
|
||||
ResponseBody body = response.body();
|
||||
if (Objects.nonNull(body)) {
|
||||
log.error("OpenAI sse连接异常data:{},异常:{}", body.string(), t);
|
||||
} else {
|
||||
log.error("OpenAI sse连接异常data:{},异常:{}", response, t);
|
||||
}
|
||||
eventSource.cancel();
|
||||
}
|
||||
}
|
||||
@@ -1,417 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.ruoyi.common.chat.entity.chat.*;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolCallFunction;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolCalls;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.Tools;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolsFunction;
|
||||
import org.ruoyi.common.chat.openai.OpenAiClient;
|
||||
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
|
||||
import org.ruoyi.common.chat.openai.function.KeyRandomStrategy;
|
||||
import org.ruoyi.common.chat.openai.interceptor.DynamicKeyOpenAiAuthInterceptor;
|
||||
import org.ruoyi.common.chat.openai.interceptor.OpenAILogger;
|
||||
import org.ruoyi.common.chat.openai.interceptor.OpenAiResponseInterceptor;
|
||||
import org.ruoyi.common.chat.openai.plugin.PluginAbstract;
|
||||
import org.ruoyi.common.chat.plugin.CmdPlugin;
|
||||
import org.ruoyi.common.chat.plugin.CmdReq;
|
||||
import org.ruoyi.common.chat.sse.ConsoleEventSourceListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author ageerle@163.com
|
||||
* date 2025/3/8
|
||||
*/
|
||||
@Slf4j
|
||||
public class PluginTest {
|
||||
|
||||
private OpenAiClient openAiClient;
|
||||
private OpenAiStreamClient openAiStreamClient;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
//可以为null
|
||||
// Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890));
|
||||
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new OpenAILogger());
|
||||
//!!!!千万别再生产或者测试环境打开BODY级别日志!!!!
|
||||
//!!!生产或者测试环境建议设置为这三种级别:NONE,BASIC,HEADERS,!!!
|
||||
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
|
||||
OkHttpClient okHttpClient = new OkHttpClient
|
||||
.Builder()
|
||||
// .proxy(proxy)
|
||||
.addInterceptor(httpLoggingInterceptor)
|
||||
.addInterceptor(new OpenAiResponseInterceptor())
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.writeTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.build();
|
||||
openAiClient = OpenAiClient.builder()
|
||||
//支持多key传入,请求时候随机选择
|
||||
.apiKey(Arrays.asList("sk-xx"))
|
||||
//自定义key的获取策略:默认KeyRandomStrategy
|
||||
//.keyStrategy(new KeyRandomStrategy())
|
||||
.keyStrategy(new KeyRandomStrategy())
|
||||
.okHttpClient(okHttpClient)
|
||||
//自己做了代理就传代理地址,没有可不不传,(关注公众号回复:openai ,获取免费的测试代理地址)
|
||||
.apiHost("https://api.pandarobot.chat/")
|
||||
.build();
|
||||
|
||||
openAiStreamClient = OpenAiStreamClient.builder()
|
||||
//支持多key传入,请求时候随机选择
|
||||
.apiKey(Arrays.asList("sk-xx"))
|
||||
//自定义key的获取策略:默认KeyRandomStrategy
|
||||
.keyStrategy(new KeyRandomStrategy())
|
||||
.authInterceptor(new DynamicKeyOpenAiAuthInterceptor())
|
||||
.okHttpClient(okHttpClient)
|
||||
//自己做了代理就传代理地址,没有可不不传,(关注公众号回复:openai ,获取免费的测试代理地址)
|
||||
.apiHost("https://api.pandarobot.chat/")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void chatFunction() {
|
||||
//模型:GPT_3_5_TURBO_16K_0613
|
||||
Message message = Message.builder().role(Message.Role.USER).content("给我输出一个长度为2的中文词语,并解释下词语对应物品的用途").build();
|
||||
//属性一
|
||||
JSONObject wordLength = new JSONObject();
|
||||
wordLength.put("type", "number");
|
||||
wordLength.put("description", "词语的长度");
|
||||
//属性二
|
||||
JSONObject language = new JSONObject();
|
||||
language.put("type", "string");
|
||||
language.put("enum", Arrays.asList("zh", "en"));
|
||||
language.put("description", "语言类型,例如:zh代表中文、en代表英语");
|
||||
//参数
|
||||
JSONObject properties = new JSONObject();
|
||||
properties.put("wordLength", wordLength);
|
||||
properties.put("language", language);
|
||||
|
||||
Parameters parameters = Parameters.builder()
|
||||
.type("object")
|
||||
.properties(properties)
|
||||
.required(Collections.singletonList("wordLength")).build();
|
||||
Functions functions = Functions.builder()
|
||||
.name("getOneWord")
|
||||
.description("获取一个指定长度和语言类型的词语")
|
||||
.parameters(parameters)
|
||||
.build();
|
||||
|
||||
ChatCompletion chatCompletion = ChatCompletion
|
||||
.builder()
|
||||
.messages(Collections.singletonList(message))
|
||||
.functions(Collections.singletonList(functions))
|
||||
.functionCall("auto")
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
|
||||
|
||||
ChatChoice chatChoice = chatCompletionResponse.getChoices().get(0);
|
||||
log.info("构造的方法值:{}", chatChoice.getMessage().getFunctionCall());
|
||||
log.info("构造的方法名称:{}", chatChoice.getMessage().getFunctionCall().getName());
|
||||
log.info("构造的方法参数:{}", chatChoice.getMessage().getFunctionCall().getArguments());
|
||||
WordParam wordParam = JSONUtil.toBean(chatChoice.getMessage().getFunctionCall().getArguments(), WordParam.class);
|
||||
String oneWord = getOneWord(wordParam);
|
||||
|
||||
FunctionCall functionCall = FunctionCall.builder()
|
||||
.arguments(chatChoice.getMessage().getFunctionCall().getArguments())
|
||||
.name("getOneWord")
|
||||
.build();
|
||||
Message message2 = Message.builder().role(Message.Role.ASSISTANT).content("方法参数").functionCall(functionCall).build();
|
||||
String content
|
||||
= "{ " +
|
||||
"\"wordLength\": \"3\", " +
|
||||
"\"language\": \"zh\", " +
|
||||
"\"word\": \"" + oneWord + "\"," +
|
||||
"\"用途\": [\"直接吃\", \"做沙拉\", \"售卖\"]" +
|
||||
"}";
|
||||
Message message3 = Message.builder().role(Message.Role.FUNCTION).name("getOneWord").content(content).build();
|
||||
List<Message> messageList = Arrays.asList(message, message2, message3);
|
||||
ChatCompletion chatCompletionV2 = ChatCompletion
|
||||
.builder()
|
||||
.messages(messageList)
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponseV2 = openAiClient.chatCompletion(chatCompletionV2);
|
||||
log.info("自定义的方法返回值:{}",chatCompletionResponseV2.getChoices().get(0).getMessage().getContent());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void plugin() {
|
||||
CmdPlugin plugin = new CmdPlugin(CmdReq.class);
|
||||
// 插件名称
|
||||
plugin.setName("命令行工具");
|
||||
// 方法名称
|
||||
plugin.setFunction("openCmd");
|
||||
// 方法说明
|
||||
plugin.setDescription("提供一个命令行指令,比如<记事本>,指令使用中文,以function返回结果为准");
|
||||
|
||||
PluginAbstract.Arg arg = new PluginAbstract.Arg();
|
||||
// 参数名称
|
||||
arg.setName("cmd");
|
||||
// 参数说明
|
||||
arg.setDescription("命令行指令");
|
||||
// 参数类型
|
||||
arg.setType("string");
|
||||
arg.setRequired(true);
|
||||
plugin.setArgs(Collections.singletonList(arg));
|
||||
|
||||
Message message2 = Message.builder().role(Message.Role.USER).content("帮我打开计算器,结合上下文判断指令是否执行成功,只用回复成功或者失败").build();
|
||||
List<Message> messages = new ArrayList<>();
|
||||
messages.add(message2);
|
||||
//有四个重载方法,都可以使用
|
||||
ChatCompletionResponse response = openAiClient.chatCompletionWithPlugin(messages,"gpt-4o-mini",plugin);
|
||||
log.info("自定义的方法返回值:{}", response.getChoices().get(0).getMessage().getContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义返回数据格式
|
||||
*/
|
||||
@Test
|
||||
public void diyReturnDataModelChat() {
|
||||
Message message = Message.builder().role(Message.Role.USER).content("随机输出10个单词,使用json输出").build();
|
||||
ChatCompletion chatCompletion = ChatCompletion
|
||||
.builder()
|
||||
.messages(Collections.singletonList(message))
|
||||
.responseFormat(ResponseFormat.builder().type(ResponseFormat.Type.JSON_OBJECT.getName()).build())
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
|
||||
chatCompletionResponse.getChoices().forEach(e -> System.out.println(e.getMessage()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void streamPlugin() {
|
||||
WeatherPlugin plugin = new WeatherPlugin(WeatherReq.class);
|
||||
plugin.setName("知心天气");
|
||||
plugin.setFunction("getLocationWeather");
|
||||
plugin.setDescription("提供一个地址,方法将会获取该地址的天气的实时温度信息。");
|
||||
PluginAbstract.Arg arg = new PluginAbstract.Arg();
|
||||
arg.setName("location");
|
||||
arg.setDescription("地名");
|
||||
arg.setType("string");
|
||||
arg.setRequired(true);
|
||||
plugin.setArgs(Collections.singletonList(arg));
|
||||
|
||||
// Message message1 = Message.builder().role(Message.Role.USER).content("秦始皇统一了哪六国。").build();
|
||||
Message message2 = Message.builder().role(Message.Role.USER).content("获取上海市的天气现在多少度,然后再给出3个推荐的户外运动。").build();
|
||||
List<Message> messages = new ArrayList<>();
|
||||
// messages.add(message1);
|
||||
messages.add(message2);
|
||||
//默认模型:GPT_3_5_TURBO_16K_0613
|
||||
//有四个重载方法,都可以使用
|
||||
openAiStreamClient.streamChatCompletionWithPlugin(messages, ChatCompletion.Model.GPT_4_1106_PREVIEW.getName(), new ConsoleEventSourceListener(), plugin);
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
try {
|
||||
countDownLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tools使用示例
|
||||
*/
|
||||
@Test
|
||||
public void toolsChat() {
|
||||
Message message = Message.builder().role(Message.Role.USER).content("给我输出一个长度为2的中文词语,并解释下词语对应物品的用途").build();
|
||||
//属性一
|
||||
JSONObject wordLength = new JSONObject();
|
||||
wordLength.put("type", "number");
|
||||
wordLength.put("description", "词语的长度");
|
||||
//属性二
|
||||
JSONObject language = new JSONObject();
|
||||
language.put("type", "string");
|
||||
language.put("enum", Arrays.asList("zh", "en"));
|
||||
language.put("description", "语言类型,例如:zh代表中文、en代表英语");
|
||||
//参数
|
||||
JSONObject properties = new JSONObject();
|
||||
properties.put("wordLength", wordLength);
|
||||
properties.put("language", language);
|
||||
Parameters parameters = Parameters.builder()
|
||||
.type("object")
|
||||
.properties(properties)
|
||||
.required(Collections.singletonList("wordLength")).build();
|
||||
Tools tools = Tools.builder()
|
||||
.type(Tools.Type.FUNCTION.getName())
|
||||
.function(ToolsFunction.builder().name("getOneWord").description("获取一个指定长度和语言类型的词语").parameters(parameters).build())
|
||||
.build();
|
||||
|
||||
ChatCompletion chatCompletion = ChatCompletion
|
||||
.builder()
|
||||
.messages(Collections.singletonList(message))
|
||||
.tools(Collections.singletonList(tools))
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
|
||||
|
||||
ChatChoice chatChoice = chatCompletionResponse.getChoices().get(0);
|
||||
log.info("构造的方法值:{}", chatChoice.getMessage().getToolCalls());
|
||||
|
||||
ToolCalls openAiReturnToolCalls = chatChoice.getMessage().getToolCalls().get(0);
|
||||
WordParam wordParam = JSONUtil.toBean(openAiReturnToolCalls.getFunction().getArguments(), WordParam.class);
|
||||
String oneWord = getOneWord(wordParam);
|
||||
|
||||
|
||||
ToolCallFunction tcf = ToolCallFunction.builder().name("getOneWord").arguments(openAiReturnToolCalls.getFunction().getArguments()).build();
|
||||
ToolCalls tc = ToolCalls.builder().id(openAiReturnToolCalls.getId()).type(ToolCalls.Type.FUNCTION.getName()).function(tcf).build();
|
||||
//构造tool call
|
||||
Message message2 = Message.builder().role(Message.Role.ASSISTANT).content("方法参数").toolCalls(Collections.singletonList(tc)).build();
|
||||
String content
|
||||
= "{ " +
|
||||
"\"wordLength\": \"3\", " +
|
||||
"\"language\": \"zh\", " +
|
||||
"\"word\": \"" + oneWord + "\"," +
|
||||
"\"用途\": [\"直接吃\", \"做沙拉\", \"售卖\"]" +
|
||||
"}";
|
||||
Message message3 = Message.builder().toolCallId(openAiReturnToolCalls.getId()).role(Message.Role.TOOL).name("getOneWord").content(content).build();
|
||||
List<Message> messageList = Arrays.asList(message, message2, message3);
|
||||
ChatCompletion chatCompletionV2 = ChatCompletion
|
||||
.builder()
|
||||
.messages(messageList)
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponseV2 = openAiClient.chatCompletion(chatCompletionV2);
|
||||
log.info("自定义的方法返回值:{}", chatCompletionResponseV2.getChoices().get(0).getMessage().getContent());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* tools流式输出使用示例
|
||||
*/
|
||||
@Test
|
||||
public void streamToolsChat() {
|
||||
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
ConsoleEventSourceListenerV3 eventSourceListener = new ConsoleEventSourceListenerV3(countDownLatch);
|
||||
|
||||
Message message = Message.builder().role(Message.Role.USER).content("给我输出一个长度为2的中文词语,并解释下词语对应物品的用途").build();
|
||||
//属性一
|
||||
JSONObject wordLength = new JSONObject();
|
||||
wordLength.put("type", "number");
|
||||
wordLength.put("description", "词语的长度");
|
||||
//属性二
|
||||
JSONObject language = new JSONObject();
|
||||
language.put("type", "string");
|
||||
language.put("enum", Arrays.asList("zh", "en"));
|
||||
language.put("description", "语言类型,例如:zh代表中文、en代表英语");
|
||||
//参数
|
||||
JSONObject properties = new JSONObject();
|
||||
properties.put("wordLength", wordLength);
|
||||
properties.put("language", language);
|
||||
Parameters parameters = Parameters.builder()
|
||||
.type("object")
|
||||
.properties(properties)
|
||||
.required(Collections.singletonList("wordLength")).build();
|
||||
Tools tools = Tools.builder()
|
||||
.type(Tools.Type.FUNCTION.getName())
|
||||
.function(ToolsFunction.builder().name("getOneWord").description("获取一个指定长度和语言类型的词语").parameters(parameters).build())
|
||||
.build();
|
||||
|
||||
ChatCompletion chatCompletion = ChatCompletion
|
||||
.builder()
|
||||
.messages(Collections.singletonList(message))
|
||||
.tools(Collections.singletonList(tools))
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
openAiStreamClient.streamChatCompletion(chatCompletion, eventSourceListener);
|
||||
|
||||
try {
|
||||
countDownLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
ToolCalls openAiReturnToolCalls = eventSourceListener.getToolCalls();
|
||||
WordParam wordParam = JSONUtil.toBean(openAiReturnToolCalls.getFunction().getArguments(), WordParam.class);
|
||||
String oneWord = getOneWord(wordParam);
|
||||
|
||||
|
||||
ToolCallFunction tcf = ToolCallFunction.builder().name("getOneWord").arguments(openAiReturnToolCalls.getFunction().getArguments()).build();
|
||||
ToolCalls tc = ToolCalls.builder().id(openAiReturnToolCalls.getId()).type(ToolCalls.Type.FUNCTION.getName()).function(tcf).build();
|
||||
//构造tool call
|
||||
Message message2 = Message.builder().role(Message.Role.ASSISTANT).content("方法参数").toolCalls(Collections.singletonList(tc)).build();
|
||||
String content
|
||||
= "{ " +
|
||||
"\"wordLength\": \"3\", " +
|
||||
"\"language\": \"zh\", " +
|
||||
"\"word\": \"" + oneWord + "\"," +
|
||||
"\"用途\": [\"直接吃\", \"做沙拉\", \"售卖\"]" +
|
||||
"}";
|
||||
Message message3 = Message.builder().toolCallId(openAiReturnToolCalls.getId()).role(Message.Role.TOOL).name("getOneWord").content(content).build();
|
||||
List<Message> messageList = Arrays.asList(message, message2, message3);
|
||||
ChatCompletion chatCompletionV2 = ChatCompletion
|
||||
.builder()
|
||||
.messages(messageList)
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
|
||||
|
||||
CountDownLatch countDownLatch1 = new CountDownLatch(1);
|
||||
openAiStreamClient.streamChatCompletion(chatCompletionV2, new ConsoleEventSourceListenerV3(countDownLatch));
|
||||
try {
|
||||
countDownLatch1.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
countDownLatch1.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
static class WordParam {
|
||||
private int wordLength;
|
||||
@Builder.Default
|
||||
private String language = "zh";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取一个词语(根据语言和字符长度查询)
|
||||
* @param wordParam
|
||||
* @return
|
||||
*/
|
||||
public String getOneWord(WordParam wordParam) {
|
||||
|
||||
List<String> zh = Arrays.asList("大香蕉", "哈密瓜", "苹果");
|
||||
List<String> en = Arrays.asList("apple", "banana", "cantaloupe");
|
||||
if (wordParam.getLanguage().equals("zh")) {
|
||||
for (String e : zh) {
|
||||
if (e.length() == wordParam.getWordLength()) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wordParam.getLanguage().equals("en")) {
|
||||
for (String e : en) {
|
||||
if (e.length() == wordParam.getWordLength()) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "西瓜";
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
|
||||
import org.ruoyi.common.chat.openai.plugin.PluginAbstract;
|
||||
|
||||
public class WeatherPlugin extends PluginAbstract<WeatherReq, WeatherResp> {
|
||||
|
||||
public WeatherPlugin(Class<?> r) {
|
||||
super(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeatherResp func(WeatherReq args) {
|
||||
WeatherResp weatherResp = new WeatherResp();
|
||||
weatherResp.setTemp("25到28摄氏度");
|
||||
weatherResp.setLevel(3);
|
||||
return weatherResp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String content(WeatherResp weatherResp) {
|
||||
return "当前天气温度:" + weatherResp.getTemp() + ",风力等级:" + weatherResp.getLevel();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import org.ruoyi.common.chat.openai.plugin.PluginParam;
|
||||
|
||||
@Data
|
||||
public class WeatherReq extends PluginParam {
|
||||
/**
|
||||
* 城市
|
||||
*/
|
||||
private String location;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WeatherResp {
|
||||
/**
|
||||
* 温度
|
||||
*/
|
||||
private String temp;
|
||||
/**
|
||||
* 风力等级
|
||||
*/
|
||||
private Integer level;
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.zhipu.oapi.ClientV4;
|
||||
import com.zhipu.oapi.Constants;
|
||||
import com.zhipu.oapi.service.v4.tools.*;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
|
||||
import com.zhipu.oapi.service.v4.model.*;
|
||||
import io.reactivex.Flowable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class WebSearchToolsTest {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(WebSearchToolsTest.class);
|
||||
private static final String API_SECRET_KEY = "xx";
|
||||
|
||||
private static final ClientV4 client = new ClientV4.Builder(API_SECRET_KEY)
|
||||
.networkConfig(300, 100, 100, 100, TimeUnit.SECONDS)
|
||||
.connectionPool(new okhttp3.ConnectionPool(8, 1, TimeUnit.SECONDS))
|
||||
.build();
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
// 请自定义自己的业务id
|
||||
private static final String requestIdTemplate = "mycompany-%d";
|
||||
|
||||
|
||||
@Test
|
||||
public void test1() throws JsonProcessingException {
|
||||
|
||||
// json 转换 ArrayList<SearchChatMessage>
|
||||
String jsonString = "[\n" +
|
||||
" {\n" +
|
||||
" \"content\": \"今天武汉天气怎么样\",\n" +
|
||||
" \"role\": \"user\"\n" +
|
||||
" }\n" +
|
||||
" ]";
|
||||
|
||||
ArrayList<SearchChatMessage> messages = new ObjectMapper().readValue(jsonString, new TypeReference<ArrayList<SearchChatMessage>>() {
|
||||
});
|
||||
|
||||
|
||||
String requestId = String.format(requestIdTemplate, System.currentTimeMillis());
|
||||
WebSearchParamsRequest chatCompletionRequest = WebSearchParamsRequest.builder()
|
||||
.model("web-search-pro")
|
||||
.stream(Boolean.TRUE)
|
||||
.messages(messages)
|
||||
.requestId(requestId)
|
||||
.build();
|
||||
WebSearchApiResponse webSearchApiResponse = client.webSearchProStreamingInvoke(chatCompletionRequest);
|
||||
if (webSearchApiResponse.isSuccess()) {
|
||||
AtomicBoolean isFirst = new AtomicBoolean(true);
|
||||
List<ChoiceDelta> choices = new ArrayList<>();
|
||||
AtomicReference<WebSearchPro> lastAccumulator = new AtomicReference<>();
|
||||
|
||||
webSearchApiResponse.getFlowable().map(result -> result)
|
||||
.doOnNext(accumulator -> {
|
||||
{
|
||||
if (isFirst.getAndSet(false)) {
|
||||
logger.info("Response: ");
|
||||
}
|
||||
ChoiceDelta delta = accumulator.getChoices().get(0).getDelta();
|
||||
if (delta != null && delta.getToolCalls() != null) {
|
||||
logger.info("tool_calls: {}", mapper.writeValueAsString(delta.getToolCalls()));
|
||||
}
|
||||
choices.add(delta);
|
||||
lastAccumulator.set(accumulator);
|
||||
|
||||
}
|
||||
})
|
||||
.doOnComplete(() -> System.out.println("Stream completed."))
|
||||
.doOnError(throwable -> System.err.println("Error: " + throwable)) // Handle errors
|
||||
.blockingSubscribe();// Use blockingSubscribe instead of blockingGet()
|
||||
|
||||
WebSearchPro chatMessageAccumulator = lastAccumulator.get();
|
||||
|
||||
webSearchApiResponse.setFlowable(null);// 打印前置空
|
||||
webSearchApiResponse.setData(chatMessageAccumulator);
|
||||
}
|
||||
logger.info("model output: {}", mapper.writeValueAsString(webSearchApiResponse));
|
||||
client.getConfig().getHttpClient().dispatcher().executorService().shutdown();
|
||||
|
||||
client.getConfig().getHttpClient().connectionPool().evictAll();
|
||||
// List all active threads
|
||||
for (Thread t : Thread.getAllStackTraces().keySet()) {
|
||||
logger.info("Thread: " + t.getName() + " State: " + t.getState());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test2() throws JsonProcessingException {
|
||||
|
||||
// json 转换 ArrayList<SearchChatMessage>
|
||||
String jsonString = "[\n" +
|
||||
" {\n" +
|
||||
" \"content\": \"今天天气怎么样\",\n" +
|
||||
" \"role\": \"user\"\n" +
|
||||
" }\n" +
|
||||
" ]";
|
||||
|
||||
ArrayList<SearchChatMessage> messages = new ObjectMapper().readValue(jsonString, new TypeReference<ArrayList<SearchChatMessage>>() {
|
||||
});
|
||||
|
||||
|
||||
String requestId = String.format(requestIdTemplate, System.currentTimeMillis());
|
||||
WebSearchParamsRequest chatCompletionRequest = WebSearchParamsRequest.builder()
|
||||
.model("web-search-pro")
|
||||
.stream(Boolean.FALSE)
|
||||
.messages(messages)
|
||||
.requestId(requestId)
|
||||
.build();
|
||||
WebSearchApiResponse webSearchApiResponse = client.invokeWebSearchPro(chatCompletionRequest);
|
||||
|
||||
logger.info("model output: {}", mapper.writeValueAsString(webSearchApiResponse));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFunctionSSE() throws JsonProcessingException {
|
||||
List<ChatMessage> messages = new ArrayList<>();
|
||||
ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), "成都到北京要多久,天气如何");
|
||||
messages.add(chatMessage);
|
||||
String requestId = String.format(requestIdTemplate, System.currentTimeMillis());
|
||||
// 函数调用参数构建部分
|
||||
List<ChatTool> chatToolList = new ArrayList<>();
|
||||
ChatTool chatTool = new ChatTool();
|
||||
|
||||
chatTool.setType(ChatToolType.FUNCTION.value());
|
||||
ChatFunctionParameters chatFunctionParameters = new ChatFunctionParameters();
|
||||
chatFunctionParameters.setType("object");
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("location", new HashMap<String, Object>() {{
|
||||
put("type", "string");
|
||||
put("description", "城市,如:北京");
|
||||
}});
|
||||
properties.put("unit", new HashMap<String, Object>() {{
|
||||
put("type", "string");
|
||||
put("enum", new ArrayList<String>() {{
|
||||
add("celsius");
|
||||
add("fahrenheit");
|
||||
}});
|
||||
}});
|
||||
chatFunctionParameters.setProperties(properties);
|
||||
ChatFunction chatFunction = ChatFunction.builder()
|
||||
.name("get_weather")
|
||||
.description("Get the current weather of a location")
|
||||
.parameters(chatFunctionParameters)
|
||||
.build();
|
||||
chatTool.setFunction(chatFunction);
|
||||
chatToolList.add(chatTool);
|
||||
HashMap<String, Object> extraJson = new HashMap<>();
|
||||
extraJson.put("temperature", 0.5);
|
||||
extraJson.put("max_tokens", 50);
|
||||
|
||||
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
|
||||
.model(Constants.ModelChatGLM4)
|
||||
.stream(Boolean.TRUE)
|
||||
.messages(messages)
|
||||
.requestId(requestId)
|
||||
.tools(chatToolList)
|
||||
.toolChoice("auto")
|
||||
.extraJson(extraJson)
|
||||
.build();
|
||||
ModelApiResponse sseModelApiResp = client.invokeModelApi(chatCompletionRequest);
|
||||
if (sseModelApiResp.isSuccess()) {
|
||||
AtomicBoolean isFirst = new AtomicBoolean(true);
|
||||
List<Choice> choices = new ArrayList<>();
|
||||
ChatMessageAccumulator chatMessageAccumulator = mapStreamToAccumulator(sseModelApiResp.getFlowable())
|
||||
.doOnNext(accumulator -> {
|
||||
{
|
||||
if (isFirst.getAndSet(false)) {
|
||||
logger.info("Response: ");
|
||||
}
|
||||
if (accumulator.getDelta() != null && accumulator.getDelta().getTool_calls() != null) {
|
||||
String jsonString = mapper.writeValueAsString(accumulator.getDelta().getTool_calls());
|
||||
logger.info("tool_calls: {}", jsonString);
|
||||
}
|
||||
if (accumulator.getDelta() != null && accumulator.getDelta().getContent() != null) {
|
||||
logger.info(accumulator.getDelta().getContent());
|
||||
}
|
||||
choices.add(accumulator.getChoice());
|
||||
}
|
||||
})
|
||||
.doOnComplete(System.out::println)
|
||||
.lastElement()
|
||||
.blockingGet();
|
||||
|
||||
|
||||
ModelData data = new ModelData();
|
||||
data.setChoices(choices);
|
||||
data.setUsage(chatMessageAccumulator.getUsage());
|
||||
data.setId(chatMessageAccumulator.getId());
|
||||
data.setCreated(chatMessageAccumulator.getCreated());
|
||||
data.setRequestId(chatCompletionRequest.getRequestId());
|
||||
sseModelApiResp.setFlowable(null);// 打印前置空
|
||||
sseModelApiResp.setData(data);
|
||||
}
|
||||
logger.info("model output: {}", mapper.writeValueAsString(sseModelApiResp));
|
||||
}
|
||||
|
||||
public static Flowable<ChatMessageAccumulator> mapStreamToAccumulator(Flowable<ModelData> flowable) {
|
||||
return flowable.map(chunk -> {
|
||||
return new ChatMessageAccumulator(chunk.getChoices().get(0).getDelta(), null, chunk.getChoices().get(0), chunk.getUsage(), chunk.getCreated(), chunk.getId());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package org.ruoyi.common.chat.domain.request;
|
||||
|
||||
import org.ruoyi.common.chat.entity.chat.Message;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @sine 2023-04-08
|
||||
*/
|
||||
@Data
|
||||
public class ChatRequest {
|
||||
|
||||
|
||||
private String frequency_penalty;
|
||||
|
||||
private String max_tokens;
|
||||
|
||||
@NotEmpty(message = "对话消息不能为空")
|
||||
List<Message> messages;
|
||||
|
||||
@NotEmpty(message = "传入的模型不能为空")
|
||||
private String model;
|
||||
|
||||
private String presence_penalty;
|
||||
|
||||
private String stream;
|
||||
|
||||
private double temperature;
|
||||
|
||||
private double top_p = 1;
|
||||
|
||||
/**
|
||||
* 知识库id
|
||||
*/
|
||||
private String kid;
|
||||
|
||||
private String userId;
|
||||
//
|
||||
|
||||
//
|
||||
// /**
|
||||
// * gpt的默认设置
|
||||
// */
|
||||
// private String systemMessage = "";
|
||||
//
|
||||
//
|
||||
//
|
||||
// private double temperature = 0.2;
|
||||
//
|
||||
// /**
|
||||
// * 上下文的条数
|
||||
// */
|
||||
// private Integer contentNumber = 10;
|
||||
//
|
||||
// /**
|
||||
// * 是否携带上下文
|
||||
// */
|
||||
// private Boolean usingContext = Boolean.TRUE;
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package org.ruoyi.common.chat.domain.request;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @sine 2023-04-08
|
||||
*/
|
||||
@Data
|
||||
public class Dall3Request {
|
||||
|
||||
@NotEmpty(message = "传入的模型不能为空")
|
||||
private String model;
|
||||
|
||||
@NotEmpty(message = "提示词不能为空")
|
||||
private String prompt;
|
||||
|
||||
/** 图片大小 */
|
||||
@NotEmpty(message = "图片大小不能为空")
|
||||
private String size ;
|
||||
|
||||
/** 图片质量 */
|
||||
@NotEmpty(message = "图片质量不能为空")
|
||||
private String quality;
|
||||
|
||||
/** 图片风格 */
|
||||
@NotEmpty(message = "图片风格不能为空")
|
||||
private String style;
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package org.ruoyi.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolCalls;
|
||||
|
||||
@@ -20,6 +21,8 @@ import java.util.List;
|
||||
public class Message extends BaseMessage implements Serializable {
|
||||
|
||||
private Object content;
|
||||
@JsonProperty("reasoning_content")
|
||||
private String reasoningContent;
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.ruoyi.common.chat.handler;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.ruoyi.common.chat.config.LocalCache;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
|
||||
@@ -12,7 +11,6 @@ import org.ruoyi.common.chat.listener.WebSocketEventListener;
|
||||
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
|
||||
import org.ruoyi.common.chat.utils.WebSocketUtils;
|
||||
import org.ruoyi.common.core.utils.SpringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.socket.*;
|
||||
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
|
||||
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
package org.ruoyi.common.chat.localModels;
|
||||
|
||||
import io.micrometer.common.util.StringUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.ruoyi.common.chat.entity.models.LocalModelsSearchRequest;
|
||||
import org.ruoyi.common.chat.entity.models.LocalModelsSearchResponse;
|
||||
import org.springframework.stereotype.Service;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.jackson.JacksonConverterFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class LocalModelsofitClient {
|
||||
private static final String BASE_URL = "http://127.0.0.1:5000"; // Flask 服务的 URL
|
||||
private static Retrofit retrofit = null;
|
||||
|
||||
// 获取 Retrofit 实例
|
||||
public static Retrofit getRetrofitInstance() {
|
||||
if (retrofit == null) {
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.build();
|
||||
|
||||
retrofit = new Retrofit.Builder()
|
||||
.baseUrl(BASE_URL)
|
||||
.client(client)
|
||||
.addConverterFactory(JacksonConverterFactory.create()) // 使用 Jackson 处理 JSON 转换
|
||||
.build();
|
||||
}
|
||||
return retrofit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 向 Flask 服务发送文本向量化请求
|
||||
*
|
||||
* @param queries 查询文本列表
|
||||
* @param modelName 模型名称
|
||||
* @param delimiter 文本分隔符
|
||||
* @param topK 返回的结果数
|
||||
* @param blockSize 文本块大小
|
||||
* @param overlapChars 重叠字符数
|
||||
* @return 返回计算得到的 Top K 嵌入向量列表
|
||||
*/
|
||||
|
||||
public static List<List<Double>> getTopKEmbeddings(
|
||||
List<String> queries,
|
||||
String modelName,
|
||||
String delimiter,
|
||||
int topK,
|
||||
int blockSize,
|
||||
int overlapChars) {
|
||||
|
||||
modelName = (!StringUtils.isEmpty(modelName)) ? modelName : "msmarco-distilbert-base-tas-b"; // 默认模型名称
|
||||
delimiter = (!StringUtils.isEmpty(delimiter) ) ? delimiter : "."; // 默认分隔符
|
||||
topK = (topK > 0) ? topK : 3; // 默认返回 3 个结果
|
||||
blockSize = (blockSize > 0) ? blockSize : 500; // 默认文本块大小为 500
|
||||
overlapChars = (overlapChars > 0) ? overlapChars : 50; // 默认重叠字符数为 50
|
||||
|
||||
// 创建 Retrofit 实例
|
||||
Retrofit retrofit = getRetrofitInstance();
|
||||
|
||||
// 创建 SearchService 接口
|
||||
SearchService service = retrofit.create(SearchService.class);
|
||||
|
||||
// 创建请求对象 LocalModelsSearchRequest
|
||||
LocalModelsSearchRequest request = new LocalModelsSearchRequest(
|
||||
queries, // 查询文本列表
|
||||
modelName, // 模型名称
|
||||
delimiter, // 文本分隔符
|
||||
topK, // 返回的结果数
|
||||
blockSize, // 文本块大小
|
||||
overlapChars // 重叠字符数
|
||||
);
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1); // 创建一个 CountDownLatch
|
||||
final List<List<Double>>[] topKEmbeddings = new List[]{null}; // 使用数组来存储结果(因为 Java 不支持直接修改 List)
|
||||
|
||||
// 发起异步请求
|
||||
service.vectorize(request).enqueue(new Callback<LocalModelsSearchResponse>() {
|
||||
@Override
|
||||
public void onResponse(Call<LocalModelsSearchResponse> call, Response<LocalModelsSearchResponse> response) {
|
||||
if (response.isSuccessful()) {
|
||||
LocalModelsSearchResponse searchResponse = response.body();
|
||||
if (searchResponse != null) {
|
||||
topKEmbeddings[0] = searchResponse.getTopKEmbeddings().get(0); // 获取结果
|
||||
log.info("Successfully retrieved embeddings");
|
||||
} else {
|
||||
log.error("Response body is null");
|
||||
}
|
||||
} else {
|
||||
log.error("Request failed. HTTP error code: " + response.code());
|
||||
}
|
||||
latch.countDown(); // 请求完成,减少计数
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<LocalModelsSearchResponse> call, Throwable t) {
|
||||
t.printStackTrace();
|
||||
log.error("Request failed: ", t);
|
||||
latch.countDown(); // 请求失败,减少计数
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
latch.await(); // 等待请求完成
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return topKEmbeddings[0]; // 返回结果
|
||||
}
|
||||
|
||||
// public static void main(String[] args) {
|
||||
// // 示例调用
|
||||
// List<String> queries = Arrays.asList("What is artificial intelligence?", "AI is transforming industries.");
|
||||
// String modelName = "msmarco-distilbert-base-tas-b";
|
||||
// String delimiter = ".";
|
||||
// int topK = 3;
|
||||
// int blockSize = 500;
|
||||
// int overlapChars = 50;
|
||||
//
|
||||
// List<List<Double>> topKEmbeddings = getTopKEmbeddings(queries, modelName, delimiter, topK, blockSize, overlapChars);
|
||||
//
|
||||
// // 打印结果
|
||||
// if (topKEmbeddings != null) {
|
||||
// System.out.println("Top K embeddings: ");
|
||||
// for (List<Double> embedding : topKEmbeddings) {
|
||||
// System.out.println(embedding);
|
||||
// }
|
||||
// } else {
|
||||
// System.out.println("No embeddings returned.");
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// public static void main(String[] args) {
|
||||
// // 创建 Retrofit 实例
|
||||
// Retrofit retrofit = LocalModelsofitClient.getRetrofitInstance();
|
||||
//
|
||||
// // 创建 SearchService 接口
|
||||
// SearchService service = retrofit.create(SearchService.class);
|
||||
//
|
||||
// // 创建请求对象 LocalModelsSearchRequest
|
||||
// LocalModelsSearchRequest request = new LocalModelsSearchRequest(
|
||||
// Arrays.asList("What is artificial intelligence?", "AI is transforming industries."), // 查询文本列表
|
||||
// "msmarco-distilbert-base-tas-b", // 模型名称
|
||||
// ".", // 分隔符
|
||||
// 3, // 返回的结果数
|
||||
// 500, // 文本块大小
|
||||
// 50 // 重叠字符数
|
||||
// );
|
||||
//
|
||||
// // 发起请求
|
||||
// service.vectorize(request).enqueue(new Callback<LocalModelsSearchResponse>() {
|
||||
// @Override
|
||||
// public void onResponse(Call<LocalModelsSearchResponse> call, Response<LocalModelsSearchResponse> response) {
|
||||
// if (response.isSuccessful()) {
|
||||
// LocalModelsSearchResponse searchResponse = response.body();
|
||||
// System.out.println("Response Body: " + response.body()); // Print the whole response body for debugging
|
||||
//
|
||||
// if (searchResponse != null) {
|
||||
// // If the response is not null, process it.
|
||||
// // Example: Extract the embeddings and print them
|
||||
// List<List<List<Double>>> topKEmbeddings = searchResponse.getTopKEmbeddings();
|
||||
// if (topKEmbeddings != null) {
|
||||
// // Print the Top K embeddings
|
||||
//
|
||||
// } else {
|
||||
// System.err.println("Top K embeddings are null");
|
||||
// }
|
||||
//
|
||||
// // If there is more information you want to process, handle it here
|
||||
//
|
||||
// } else {
|
||||
// System.err.println("Response body is null");
|
||||
// }
|
||||
// } else {
|
||||
// System.err.println("Request failed. HTTP error code: " + response.code());
|
||||
// log.error("Failed to retrieve data. HTTP error code: " + response.code());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onFailure(Call<LocalModelsSearchResponse> call, Throwable t) {
|
||||
// // 请求失败,打印错误
|
||||
// t.printStackTrace();
|
||||
// log.error("Request failed: ", t);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package org.ruoyi.common.chat.localModels;
|
||||
|
||||
|
||||
|
||||
import org.ruoyi.common.chat.entity.models.LocalModelsSearchRequest;
|
||||
import org.ruoyi.common.chat.entity.models.LocalModelsSearchResponse;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.POST;
|
||||
/**
|
||||
* @program: RUOYIAI
|
||||
* @ClassName SearchService
|
||||
* @description: 请求模型
|
||||
* @author: hejh
|
||||
* @create: 2025-03-15 17:27
|
||||
* @Version 1.0
|
||||
**/
|
||||
|
||||
|
||||
public interface SearchService {
|
||||
@POST("/vectorize") // 与 Flask 服务中的路由匹配
|
||||
Call<LocalModelsSearchResponse> vectorize(@Body LocalModelsSearchRequest request);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package org.ruoyi.common.chat.plugin;
|
||||
|
||||
import org.ruoyi.common.chat.openai.plugin.PluginAbstract;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class CmdPlugin extends PluginAbstract<CmdReq, CmdResp> {
|
||||
|
||||
public CmdPlugin(Class<?> r) {
|
||||
super(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CmdResp func(CmdReq args) {
|
||||
try {
|
||||
if("计算器".equals(args.getCmd())){
|
||||
Runtime.getRuntime().exec("calc");
|
||||
}else if("记事本".equals(args.getCmd())){
|
||||
Runtime.getRuntime().exec("notepad");
|
||||
}else if("命令行".equals(args.getCmd())){
|
||||
String [] cmd={"cmd","/C","start copy exel exe2"};
|
||||
Runtime.getRuntime().exec(cmd);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("指令执行失败");
|
||||
}
|
||||
CmdResp resp = new CmdResp();
|
||||
resp.setResult(args.getCmd()+"指令执行成功!");
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String content(CmdResp resp) {
|
||||
return resp.getResult();
|
||||
}
|
||||
}
|
||||
@@ -2,31 +2,39 @@ package org.ruoyi.common.chat.request;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
import org.ruoyi.common.chat.entity.chat.Content;
|
||||
import org.ruoyi.common.chat.entity.chat.Message;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
* 描述:对话请求对象
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @author ageerle
|
||||
* @sine 2023-04-08
|
||||
*/
|
||||
@Data
|
||||
public class ChatRequest {
|
||||
|
||||
@NotEmpty(message = "传入的模型不能为空")
|
||||
private String model;
|
||||
|
||||
@NotEmpty(message = "对话消息不能为空")
|
||||
List<Message> messages;
|
||||
|
||||
List<Content> imageContent;
|
||||
@NotEmpty(message = "传入的模型不能为空")
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 提示词
|
||||
*/
|
||||
private String prompt;
|
||||
|
||||
private String userId;
|
||||
/**
|
||||
* 是否开启流式对话
|
||||
*/
|
||||
private Boolean stream = Boolean.TRUE;
|
||||
|
||||
/**
|
||||
* 是否开启联网搜索(0关闭 1开启)
|
||||
*/
|
||||
private Boolean search = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 知识库id
|
||||
@@ -34,13 +42,14 @@ public class ChatRequest {
|
||||
private String kid;
|
||||
|
||||
/**
|
||||
* gpt的默认设置
|
||||
* 用户id
|
||||
*/
|
||||
private String systemMessage = "";
|
||||
private String userId;
|
||||
|
||||
private double top_p = 1;
|
||||
|
||||
private double temperature = 0.2;
|
||||
/**
|
||||
* 应用ID
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 上下文的条数
|
||||
@@ -52,4 +61,5 @@ public class ChatRequest {
|
||||
*/
|
||||
private Boolean usingContext = Boolean.TRUE;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ public class ConsoleEventSourceListener extends EventSourceListener {
|
||||
log.info("OpenAI返回数据:{}", data);
|
||||
if ("[DONE]".equals(data)) {
|
||||
log.info("OpenAI返回数据结束了");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import okhttp3.ResponseBody;
|
||||
import okhttp3.sse.EventSource;
|
||||
import okhttp3.sse.EventSourceListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.ruoyi.common.chat.constant.OpenAIConst;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse;
|
||||
import org.ruoyi.common.chat.entity.chat.FunctionCall;
|
||||
|
||||
@@ -47,25 +47,11 @@
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- hutool工具模块 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-extra</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-json</artifactId>
|
||||
<scope>provided</scope>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -73,18 +59,6 @@
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-cp</artifactId>
|
||||
<version>${weixin-java-miniapp.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-cp</artifactId>
|
||||
<version>${weixin-java-cp.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 自动生成YML配置关联JSON文件 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -108,6 +82,11 @@
|
||||
<artifactId>ip2region</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-cp</artifactId>
|
||||
<version>${weixin-java-cp.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
|
||||
@@ -7,8 +7,7 @@ import org.ruoyi.common.core.service.ConfigService;
|
||||
import org.ruoyi.common.mail.utils.MailAccount;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
|
||||
/**
|
||||
* JavaMail 配置
|
||||
@@ -22,10 +21,9 @@ import org.springframework.scheduling.annotation.Scheduled;
|
||||
public class MailConfig {
|
||||
|
||||
private final ConfigService configService;
|
||||
private MailAccount account; // 缓存MailAccount实例
|
||||
private MailAccount account;
|
||||
|
||||
@Bean
|
||||
@Scope("singleton")
|
||||
public MailAccount mailAccount() {
|
||||
if (account == null) {
|
||||
account = new MailAccount();
|
||||
@@ -34,7 +32,6 @@ public class MailConfig {
|
||||
return account;
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 10000) // 每10秒检查一次
|
||||
public void updateMailAccount() {
|
||||
account.setHost(getKey("host"));
|
||||
account.setPort(NumberUtils.toInt(getKey("port"), 465));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.ruoyi.common.mail.config.properties;
|
||||
package org.ruoyi.common.mail.properties;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -12,6 +12,8 @@ import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据库助手
|
||||
@@ -69,4 +71,10 @@ public class DataBaseHelper {
|
||||
// find_in_set(100 , '0,100,101')
|
||||
return "find_in_set('%s' , %s) <> 0".formatted(var, var2);
|
||||
}
|
||||
/**
|
||||
* 获取当前加载的数据库名
|
||||
*/
|
||||
public static List<String> getDataSourceNameList() {
|
||||
return new ArrayList<>(DS.getDataSources().keySet());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package org.ruoyi.common.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 支付配置信息
|
||||
*
|
||||
* @author Admin
|
||||
*/
|
||||
@Data
|
||||
public class PayConfig {
|
||||
|
||||
/**
|
||||
* 商户ID
|
||||
*/
|
||||
private String pid;
|
||||
|
||||
/**
|
||||
* 接口地址
|
||||
*/
|
||||
private String payUrl;
|
||||
|
||||
/**
|
||||
* 私钥
|
||||
*/
|
||||
private String key ;
|
||||
|
||||
/**
|
||||
* 服务器异步通知地址
|
||||
*/
|
||||
private String notify_url;
|
||||
|
||||
/**
|
||||
* 页面跳转通知地址
|
||||
*/
|
||||
private String return_url;
|
||||
|
||||
/**
|
||||
* 支付方式
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
private String device;
|
||||
|
||||
/**
|
||||
* 加密方式默认MD5
|
||||
*/
|
||||
private String sign_type;
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package org.ruoyi.common.config;
|
||||
|
||||
import org.ruoyi.common.core.service.ConfigService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
/**
|
||||
* 支付配置信息
|
||||
*
|
||||
* @author Admin
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class PayInit {
|
||||
|
||||
private final ConfigService configService;
|
||||
|
||||
private PayConfig payConfig;
|
||||
|
||||
@Bean
|
||||
@Scope("singleton")
|
||||
public PayConfig payConfig() {
|
||||
if (payConfig == null) {
|
||||
payConfig = new PayConfig();
|
||||
updatePayConfig();
|
||||
}
|
||||
return payConfig;
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 10000) // 每10秒检查一次
|
||||
public void updatePayConfig() {
|
||||
payConfig.setType("wxpay");
|
||||
payConfig.setDevice("pc");
|
||||
payConfig.setSign_type("MD5");
|
||||
payConfig.setPid(getKey("pid"));
|
||||
payConfig.setKey(getKey("key"));
|
||||
payConfig.setPayUrl(getKey("payUrl"));
|
||||
payConfig.setNotify_url(getKey("notify_url"));
|
||||
payConfig.setReturn_url(getKey("return_url"));
|
||||
}
|
||||
|
||||
public String getKey(String key){
|
||||
return configService.getConfigValue("pay", key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package org.ruoyi.common.config;
|
||||
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.service.WxPayService;
|
||||
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
|
||||
|
||||
import org.ruoyi.common.core.service.ConfigService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Binary Wang
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class WxPayConfiguration {
|
||||
|
||||
private final ConfigService configService;
|
||||
|
||||
private WxPayService wxPayService;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
WxPayConfig payConfig = new WxPayConfig();
|
||||
payConfig.setAppId(StringUtils.trimToNull(getKey("appId")));
|
||||
payConfig.setMchId(StringUtils.trimToNull(getKey("mchId")));
|
||||
payConfig.setMchKey(StringUtils.trimToNull(getKey("appSecret")));
|
||||
payConfig.setUseSandboxEnv(false);
|
||||
wxPayService = new WxPayServiceImpl();
|
||||
wxPayService.setConfig(payConfig);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public WxPayService wxService() {
|
||||
return wxPayService;
|
||||
}
|
||||
|
||||
public String getKey(String key) {
|
||||
return configService.getConfigValue("weixin", key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.ruoyi.common.listener;
|
||||
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.service.WxPayService;
|
||||
import org.ruoyi.common.core.event.ConfigChangeEvent;
|
||||
import org.ruoyi.common.core.service.ConfigService;
|
||||
import org.ruoyi.common.core.utils.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 描述:创建一个监听器,用于处理配置变化事件
|
||||
*
|
||||
* @author ageerle@163.com
|
||||
* date 2024/5/19
|
||||
*/
|
||||
@Component
|
||||
public class ConfigChangeListener implements ApplicationListener<ConfigChangeEvent> {
|
||||
private final WxPayService wxPayService;
|
||||
private final ConfigService configService;
|
||||
|
||||
public ConfigChangeListener(WxPayService wxPayService, ConfigService configService) {
|
||||
this.wxPayService = wxPayService;
|
||||
this.configService = configService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(@NotNull ConfigChangeEvent event) {
|
||||
WxPayConfig newConfig = new WxPayConfig();
|
||||
newConfig.setAppId(StringUtils.trimToNull(configService.getConfigValue("weixin", "appId")));
|
||||
newConfig.setMchId(StringUtils.trimToNull(configService.getConfigValue("weixin", "mchId")));
|
||||
newConfig.setMchKey(StringUtils.trimToNull(configService.getConfigValue("weixin", "mchKey")));
|
||||
newConfig.setUseSandboxEnv(false);
|
||||
wxPayService.setConfig(newConfig);
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package org.ruoyi.common.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 支付结果响应
|
||||
*
|
||||
* @author: wangle
|
||||
* @date: 2023/7/3
|
||||
*/
|
||||
@Data
|
||||
public class PayResponse {
|
||||
|
||||
/**
|
||||
* 商户ID
|
||||
*/
|
||||
private String pid;
|
||||
|
||||
/**
|
||||
* 易支付订单号
|
||||
*/
|
||||
|
||||
@JsonProperty("trade_no")
|
||||
private String trade_no;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
@JsonProperty("out_trade_no")
|
||||
private String out_trade_no;
|
||||
|
||||
/**
|
||||
* 支付方式
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 商品名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 商品金额
|
||||
*/
|
||||
private String money;
|
||||
|
||||
/**
|
||||
* 支付状态
|
||||
*/
|
||||
@JsonProperty("trade_status")
|
||||
private String trade_status;
|
||||
|
||||
/**
|
||||
* 业务扩展参数
|
||||
*/
|
||||
private String param;
|
||||
|
||||
/**
|
||||
* 签名字符串
|
||||
*/
|
||||
private String sign;
|
||||
|
||||
/**
|
||||
* 签名类型
|
||||
*/
|
||||
@JsonProperty("sign_type")
|
||||
private String signType;
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package org.ruoyi.common.service;
|
||||
|
||||
/**
|
||||
* 支付服务
|
||||
*
|
||||
* @author: wangle
|
||||
* @date: 2023/7/3
|
||||
*/
|
||||
public interface PayService {
|
||||
|
||||
/**
|
||||
* 获取支付地址
|
||||
*
|
||||
* @Date 2023/7/3
|
||||
* @param orderNo
|
||||
* @param name
|
||||
* @param money
|
||||
* @param clientIp
|
||||
* @return String
|
||||
**/
|
||||
String getPayUrl(String orderNo, String name, double money, String clientIp);
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package org.ruoyi.common.service.impl;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
|
||||
import org.ruoyi.common.config.PayConfig;
|
||||
import org.ruoyi.common.service.PayService;
|
||||
import org.ruoyi.common.utils.MD5Util;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 支付服务
|
||||
* @author Admin
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class PayServiceImpl implements PayService {
|
||||
|
||||
private final PayConfig payConfig;
|
||||
|
||||
@Override
|
||||
public String getPayUrl(String orderNo, String name, double money, String clientIp) {
|
||||
String out_trade_no = orderNo, sign = "";
|
||||
//封装请求参数
|
||||
String mdString = "clientip=" + clientIp + "&device=" + payConfig.getDevice() + "&money=" + money + "&name=" + name + "&" +
|
||||
"notify_url=" + payConfig.getNotify_url() + "&out_trade_no=" + out_trade_no + "&pid=" + payConfig.getPid() + "&return_url=" + payConfig.getReturn_url() +
|
||||
"&type=" + payConfig.getType() + payConfig.getKey();
|
||||
sign = MD5Util.GetMD5Code(mdString);
|
||||
Map<String, Object> map = new HashMap<>(10);
|
||||
map.put("clientip", clientIp);
|
||||
map.put("device", payConfig.getDevice());
|
||||
map.put("money", money);
|
||||
map.put("name", name);
|
||||
map.put("notify_url", payConfig.getNotify_url());
|
||||
map.put("out_trade_no", out_trade_no);
|
||||
map.put("pid", payConfig.getPid());
|
||||
map.put("return_url", payConfig.getReturn_url());
|
||||
map.put("sign_type", payConfig.getSign_type());
|
||||
map.put("type", payConfig.getType());
|
||||
map.put("sign", sign);
|
||||
String body = HttpUtil.post(payConfig.getPayUrl(), map);
|
||||
log.info("支付返回信息:{},配置信息: {}",body,payConfig);
|
||||
JSONObject jsonObject = new JSONObject(body);
|
||||
return (String) jsonObject.get("qrcode");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package org.ruoyi.common.utils;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* MD5 算法
|
||||
*
|
||||
* @author Admin
|
||||
*/
|
||||
public class MD5Util {
|
||||
|
||||
/**
|
||||
* 全局数组
|
||||
*/
|
||||
public final static String[] strDigits = { "0", "1", "2", "3", "4", "5",
|
||||
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
|
||||
|
||||
public MD5Util() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回形式为数字跟字符串
|
||||
*
|
||||
* @Date 2023/7/3
|
||||
* @param bByte
|
||||
* @return String
|
||||
**/
|
||||
public static String byteToArrayString(byte bByte) {
|
||||
int iRet = bByte;
|
||||
if (iRet < 0) {
|
||||
iRet += 256;
|
||||
}
|
||||
int iD1 = iRet / 16;
|
||||
int iD2 = iRet % 16;
|
||||
return strDigits[iD1] + strDigits[iD2];
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换字节数组为16进制字串
|
||||
*
|
||||
* @Date 2023/7/3
|
||||
* @param bByte
|
||||
* @return String
|
||||
**/
|
||||
public static String byteToString(byte[] bByte) {
|
||||
StringBuffer sBuffer = new StringBuffer();
|
||||
for (int i = 0; i < bByte.length; i++) {
|
||||
sBuffer.append(byteToArrayString(bByte[i]));
|
||||
}
|
||||
return sBuffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成md5代码
|
||||
*
|
||||
* @Date 2023/7/3
|
||||
* @param strObj
|
||||
* @return String
|
||||
**/
|
||||
public static String GetMD5Code(String strObj) {
|
||||
String resultString = null;
|
||||
try {
|
||||
resultString = new String(strObj);
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
resultString = byteToString(md.digest(strObj.getBytes()));
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return resultString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装签名的字段
|
||||
*
|
||||
* @param params 参数
|
||||
* @param urlEncoder 是否urlEncoder
|
||||
* @return {String}
|
||||
*/
|
||||
public static String packageSign(Map<String, Object> params, boolean urlEncoder) {
|
||||
// 先将参数以其参数名的字典序升序进行排序
|
||||
TreeMap<String, Object> sortedParams = new TreeMap<String, Object>(params);
|
||||
// 遍历排序后的字典,将所有参数按"key=value"格式拼接在一起
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, Object> param : sortedParams.entrySet()) {
|
||||
String value = String.valueOf(param.getValue());
|
||||
if (StrUtil.isBlank(value)) {
|
||||
continue;
|
||||
}
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append("&");
|
||||
}
|
||||
sb.append(param.getKey()).append("=");
|
||||
sb.append(value);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package org.ruoyi.common.satoken.utils;
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
@@ -73,8 +74,11 @@ public class LoginHelper {
|
||||
if (loginUser != null) {
|
||||
return loginUser;
|
||||
}
|
||||
loginUser = (LoginUser) StpUtil.getTokenSession().get(LOGIN_USER_KEY);
|
||||
SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser);
|
||||
SaSession tokenSession = StpUtil.getTokenSession();
|
||||
if (tokenSession != null) {
|
||||
loginUser = (LoginUser) tokenSession.get(LOGIN_USER_KEY);
|
||||
SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser);
|
||||
};
|
||||
return loginUser;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,11 @@ public enum SensitiveStrategy {
|
||||
*/
|
||||
ID_CARD(s -> DesensitizedUtil.idCardNum(s, 3, 4)),
|
||||
|
||||
/**
|
||||
* 密钥脱敏
|
||||
*/
|
||||
SKY(s -> DesensitizedUtil.idCardNum(s, 0, 1)),
|
||||
|
||||
/**
|
||||
* 手机号脱敏
|
||||
*/
|
||||
|
||||
@@ -36,20 +36,6 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
||||
String url = request.getMethod() + " " + request.getRequestURI();
|
||||
String domainName = request.getServerName();
|
||||
log.info("域名信息:{}",domainName);
|
||||
|
||||
String requestURI = request.getRequestURI();
|
||||
List<String> urls = whitelistUrls();
|
||||
boolean isWhitelisted = urls.stream().anyMatch(requestURI::startsWith);
|
||||
|
||||
if (!isWhitelisted){
|
||||
// 根据授权编号查询激活状态
|
||||
// ConfigService configService = SpringUtils.context().getBean(ConfigService.class);
|
||||
// String authNo = configService.getConfigValue("sys", "authcode");
|
||||
// if(!configService.checkAuth(authNo,domainName)){
|
||||
// throw new BaseException("系统未激活,请联系管理员授权");
|
||||
// }
|
||||
}
|
||||
|
||||
// 打印请求参数
|
||||
if (isJsonRequest(request)) {
|
||||
String jsonParam = "";
|
||||
@@ -67,7 +53,6 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
||||
log.debug("[PLUS]开始请求 => URL[{}],无参数", url);
|
||||
}
|
||||
}
|
||||
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
invokeTimeTL.set(stopWatch);
|
||||
stopWatch.start();
|
||||
@@ -99,15 +84,4 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 授权白名单
|
||||
public List<String> whitelistUrls() {
|
||||
return Arrays.asList(
|
||||
"/chat/config",
|
||||
"/pay",
|
||||
"/weixin",
|
||||
"/user/qrcode",
|
||||
"/user/login/qrcode"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>ruoyi-common-wechat</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<description>ruoyi-common-wechat 微信服务</description>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.jfinal</groupId>
|
||||
<artifactId>jfinal</artifactId>
|
||||
<version>3.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jfinal</groupId>
|
||||
<artifactId>cos</artifactId>
|
||||
<version>2017.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.jfinal</groupId>
|
||||
<artifactId>jfinal-undertow</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.0.29</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.vdurmont</groupId>
|
||||
<artifactId>emoji-java</artifactId>
|
||||
<version>3.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>activation</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.mamoe</groupId>
|
||||
<artifactId>mirai-core-jvm</artifactId>
|
||||
<version>2.16.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.31</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,352 +0,0 @@
|
||||
package org.ruoyi.common.wechat.itchat4j.api;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.Consts;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.ruoyi.common.wechat.itchat4j.core.Core;
|
||||
import org.ruoyi.common.wechat.itchat4j.core.CoreManage;
|
||||
import org.ruoyi.common.wechat.itchat4j.utils.LogInterface;
|
||||
import org.ruoyi.common.wechat.itchat4j.utils.enums.StorageLoginInfoEnum;
|
||||
import org.ruoyi.common.wechat.itchat4j.utils.enums.URLEnum;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 微信小工具,如获好友列表,根据昵称查找好友或群等
|
||||
*
|
||||
* @author https://github.com/yaphone
|
||||
* @date 创建时间:2017年5月4日 下午10:49:16
|
||||
* @version 1.0
|
||||
*
|
||||
* @author WesleyOne 修改
|
||||
*/
|
||||
public class WechatTools implements LogInterface {
|
||||
|
||||
/**
|
||||
* 返回好友昵称列表
|
||||
* @param uniqueKey
|
||||
* @return
|
||||
*/
|
||||
public static List<String> getContactNickNameList(String uniqueKey) {
|
||||
Core core = CoreManage.getInstance(uniqueKey);
|
||||
List<String> contactNickNameList = new ArrayList<String>();
|
||||
for (JSONObject o : core.getContactList()) {
|
||||
contactNickNameList.add(o.getString("NickName"));
|
||||
// 顺便刷下缓存
|
||||
core.getUserInfoMap().put(o.getString("NickName"),o);
|
||||
core.getUserInfoMap().put(o.getString("UserName"),o);
|
||||
}
|
||||
return contactNickNameList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回好友完整信息列表
|
||||
* @param uniqueKey
|
||||
* @return
|
||||
*/
|
||||
public static List<JSONObject> getContactList(String uniqueKey) {
|
||||
Core core = CoreManage.getInstance(uniqueKey);
|
||||
return core.getContactList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回群列表
|
||||
* @param uniqueKey
|
||||
* @return
|
||||
*/
|
||||
public static List<JSONObject> getGroupList(String uniqueKey) {
|
||||
Core core = CoreManage.getInstance(uniqueKey);
|
||||
return core.getGroupList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群NickName列表
|
||||
* @param uniqueKey
|
||||
* @return
|
||||
*/
|
||||
public static List<String> getGroupNickNameList(String uniqueKey) {
|
||||
Core core = CoreManage.getInstance(uniqueKey);
|
||||
List<String> groupNickNameList = new ArrayList<String>();
|
||||
for (JSONObject o : core.getGroupList()) {
|
||||
groupNickNameList.add(o.getString("NickName"));
|
||||
}
|
||||
return groupNickNameList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群所有成员信息
|
||||
* @param groupId
|
||||
* @param uniqueKey
|
||||
* @return
|
||||
*/
|
||||
public static JSONArray getGroupMemberByGroupId(String groupId, String uniqueKey){
|
||||
Core core = CoreManage.getInstance(uniqueKey);
|
||||
JSONObject jsonObject = core.getGroupInfoMap().get(groupId);
|
||||
if (jsonObject == null){
|
||||
return new JSONArray();
|
||||
}
|
||||
return jsonObject.getJSONArray("MemberList");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过群成员ID获取昵称
|
||||
* @param groupId
|
||||
* @param uniqueKey
|
||||
* @param memberId
|
||||
* @return
|
||||
*/
|
||||
public static String getMemberNickName(String groupId, String uniqueKey, String memberId){
|
||||
JSONArray members = getGroupMemberByGroupId(groupId, uniqueKey);
|
||||
int size = members.size();
|
||||
if (size > 0){
|
||||
for (int i=0;i<size;i++){
|
||||
JSONObject jsonObject = members.getJSONObject(i);
|
||||
if (memberId.equals(jsonObject.getString("UserName"))){
|
||||
return jsonObject.getString("NickName");
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出微信
|
||||
*
|
||||
* @author https://github.com/yaphone
|
||||
* @date 2017年5月18日 下午11:56:54
|
||||
*/
|
||||
public static void logout(String uniqueKey) {
|
||||
webWxLogout(uniqueKey);
|
||||
}
|
||||
|
||||
private static boolean webWxLogout(String uniqueKey) {
|
||||
Core core = CoreManage.getInstance(uniqueKey);
|
||||
String url = String.format(URLEnum.WEB_WX_LOGOUT.getUrl(),
|
||||
core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()));
|
||||
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
|
||||
params.add(new BasicNameValuePair("redirect", "1"));
|
||||
params.add(new BasicNameValuePair("type", "1"));
|
||||
params.add(
|
||||
new BasicNameValuePair("skey", (String) core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey())));
|
||||
try {
|
||||
HttpEntity entity = core.getMyHttpClient().doGet(url, params, false, null);
|
||||
String text = EntityUtils.toString(entity, Consts.UTF_8);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.debug(e.getMessage());
|
||||
} finally {
|
||||
// 强制退出,提示相关线程退出
|
||||
core.setAlive(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void setUserInfo(String uniqueKey) {
|
||||
Core core = CoreManage.getInstance(uniqueKey);
|
||||
for (JSONObject o : core.getContactList()) {
|
||||
core.getUserInfoMap().put(o.getString("NickName"), o);
|
||||
core.getUserInfoMap().put(o.getString("UserName"), o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 根据用户昵称设置备注名称
|
||||
*
|
||||
* @date 2017年5月27日 上午12:21:40
|
||||
* @param nickName
|
||||
* @param remName
|
||||
*/
|
||||
public static void remarkNameByNickName(String nickName, String remName, String uniqueKey) {
|
||||
Core core = CoreManage.getInstance(uniqueKey);
|
||||
String url = String.format(URLEnum.WEB_WX_REMARKNAME.getUrl(), core.getLoginInfo().get("url"),
|
||||
core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
|
||||
Map<String, Object> msgMap = new HashMap<String, Object>(8);
|
||||
Map<String, Object> msgMap_BaseRequest = new HashMap<String, Object>(8);
|
||||
msgMap.put("CmdId", 2);
|
||||
msgMap.put("RemarkName", remName);
|
||||
msgMap.put("UserName", core.getUserInfoMap().get(nickName).get("UserName"));
|
||||
msgMap_BaseRequest.put("Uin", core.getLoginInfo().get(StorageLoginInfoEnum.wxuin.getKey()));
|
||||
msgMap_BaseRequest.put("Sid", core.getLoginInfo().get(StorageLoginInfoEnum.wxsid.getKey()));
|
||||
msgMap_BaseRequest.put("Skey", core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey()));
|
||||
msgMap_BaseRequest.put("DeviceID", core.getLoginInfo().get(StorageLoginInfoEnum.deviceid.getKey()));
|
||||
msgMap.put("BaseRequest", msgMap_BaseRequest);
|
||||
try {
|
||||
String paramStr = JSON.toJSONString(msgMap);
|
||||
HttpEntity entity = core.getMyHttpClient().doPost(url, paramStr);
|
||||
// String result = EntityUtils.toString(entity, Consts.UTF_8);
|
||||
LOG.info("修改备注" + remName);
|
||||
} catch (Exception e) {
|
||||
LOG.error("remarkNameByUserName", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信在线状态
|
||||
*
|
||||
* @date 2017年6月16日 上午12:47:46
|
||||
* @return
|
||||
*/
|
||||
public static boolean getWechatStatus(String uniqueKey) {
|
||||
Core core = CoreManage.getInstance(uniqueKey);
|
||||
return core.isAlive();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param userName
|
||||
* @param nickName
|
||||
* @return
|
||||
*/
|
||||
private static JSONObject getContactByNickNameAndUserName(String userName, String nickName, String uniqueKey){
|
||||
Core core = CoreManage.getInstance(uniqueKey);
|
||||
// 通过userName查询
|
||||
if (StringUtils.isNotEmpty(userName) && StringUtils.isEmpty(nickName)){
|
||||
for (JSONObject contact:core.getContactList()){
|
||||
if (userName.equals(contact.getString("UserName"))){
|
||||
return contact;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通过群昵称查询
|
||||
if (StringUtils.isNotEmpty(nickName) && StringUtils.isEmpty(userName)){
|
||||
for (JSONObject contact:core.getContactList()){
|
||||
if (nickName.equals(contact.getString("NickName"))){
|
||||
return contact;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通过userName和昵称联合查
|
||||
if (StringUtils.isNotEmpty(userName) && StringUtils.isNotEmpty(nickName)){
|
||||
for (JSONObject contact:core.getContactList()){
|
||||
if (nickName.equals(contact.getString("NickName")) && userName.equals(contact.getString("UserName"))){
|
||||
return contact;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过群id查找群昵称
|
||||
* @param userName
|
||||
* @return
|
||||
*/
|
||||
public static String getContactNickNameByUserName(String userName, String uniqueKey){
|
||||
JSONObject contact = getContactByNickNameAndUserName(userName,null, uniqueKey);
|
||||
if (contact!=null && StringUtils.isNotEmpty(contact.getString("NickName"))){
|
||||
return contact.getString("NickName");
|
||||
}else{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过群昵称查找群id
|
||||
* @param nickName
|
||||
* @return
|
||||
*/
|
||||
public static String getContactUserNameByNickName(String nickName, String uniqueKey){
|
||||
JSONObject contact = getContactByNickNameAndUserName(null,nickName,uniqueKey);
|
||||
if (contact!=null && StringUtils.isNotEmpty(contact.getString("UserName"))){
|
||||
return contact.getString("UserName");
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过userName或昵称查找群信息
|
||||
* @param userName
|
||||
* @return
|
||||
*/
|
||||
private static JSONObject getGroupByNickNameAndUserName(String userName, String nickName, String uniqueKey){
|
||||
Core core = CoreManage.getInstance(uniqueKey);
|
||||
// 通过userName查询
|
||||
if (StringUtils.isNotEmpty(userName) && StringUtils.isEmpty(nickName)){
|
||||
for (JSONObject group:core.getGroupList()){
|
||||
if (userName.equals(group.getString("UserName"))){
|
||||
return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通过群昵称查询
|
||||
if (StringUtils.isNotEmpty(nickName) && StringUtils.isEmpty(userName)){
|
||||
for (JSONObject group:core.getGroupList()){
|
||||
if (nickName.equals(group.getString("NickName"))){
|
||||
return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通过userName和昵称联合查
|
||||
if (StringUtils.isNotEmpty(userName) && StringUtils.isNotEmpty(nickName)){
|
||||
for (JSONObject group:core.getGroupList()){
|
||||
if (nickName.equals(group.getString("NickName")) && userName.equals(group.getString("UserName"))){
|
||||
return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过群id查找群昵称
|
||||
* @param userName
|
||||
* @return
|
||||
*/
|
||||
public static String getGroupNickNameByUserName(String userName, String uniqueKey){
|
||||
JSONObject group = getGroupByNickNameAndUserName(userName,null,uniqueKey);
|
||||
if (group!=null && StringUtils.isNotEmpty(group.getString("NickName"))){
|
||||
return group.getString("NickName");
|
||||
}else{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过群昵称查找群id
|
||||
* @param nickName
|
||||
* @return
|
||||
*/
|
||||
public static String getGroupUserNameByNickName(String nickName, String uniqueKey){
|
||||
JSONObject group = getGroupByNickNameAndUserName(null,nickName, uniqueKey);
|
||||
if (group!=null && StringUtils.isNotEmpty(group.getString("UserName"))){
|
||||
return group.getString("UserName");
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过UserName查找NickName
|
||||
* 只查群名和好友名
|
||||
* @param userName
|
||||
* @param uniqueKey
|
||||
* @return
|
||||
*/
|
||||
public static String getNickNameByUserName(String userName, String uniqueKey){
|
||||
if (userName.startsWith("@@")){
|
||||
return getGroupNickNameByUserName(userName,uniqueKey);
|
||||
}else if (userName.startsWith("@")){
|
||||
return getContactNickNameByUserName(userName,uniqueKey);
|
||||
}else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.ruoyi.common.wechat.itchat4j.beans;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* AppInfo
|
||||
*
|
||||
* @author https://github.com/yaphone
|
||||
* @date 创建时间:2017年7月3日 下午10:38:14
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
public class AppInfo implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private int type;
|
||||
private String appId;
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,330 +0,0 @@
|
||||
package org.ruoyi.common.wechat.itchat4j.beans;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 收到的微信消息
|
||||
*
|
||||
* @author https://github.com/yaphone
|
||||
* @date 创建时间:2017年7月3日 下午10:28:06
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
public class BaseMsg implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private int subMsgType;
|
||||
private int voiceLength;
|
||||
private String fileName;
|
||||
private int imgHeight;
|
||||
private String toUserName;
|
||||
private int hasProductId;
|
||||
private int imgStatus;
|
||||
private String url;
|
||||
private int imgWidth;
|
||||
private int forwardFlag;
|
||||
private int status;
|
||||
private String Ticket;
|
||||
/** 推荐消息报文 **/
|
||||
private RecommendInfo recommendInfo;
|
||||
private long createTime;
|
||||
private String newMsgId;
|
||||
/** 文本消息内容 **/
|
||||
private String text;
|
||||
/** 消息类型 **/
|
||||
private int msgType;
|
||||
/** 是否为群消息 **/
|
||||
private boolean groupMsg;
|
||||
private String msgId;
|
||||
private int statusNotifyCode;
|
||||
private AppInfo appInfo;
|
||||
private int appMsgType;
|
||||
private String Type;
|
||||
private int playLength;
|
||||
private String mediaId;
|
||||
private String content;
|
||||
private String statusNotifyUserName;
|
||||
private boolean atMe;
|
||||
// 群发送者ID昵称
|
||||
private String sendMemberId;
|
||||
private String memberNickname;
|
||||
/** 消息发送者ID **/
|
||||
private String fromUserName;
|
||||
private String oriContent;
|
||||
private String fileSize;
|
||||
private String fromNickName;
|
||||
|
||||
public int getSubMsgType() {
|
||||
return subMsgType;
|
||||
}
|
||||
|
||||
public void setSubMsgType(int subMsgType) {
|
||||
this.subMsgType = subMsgType;
|
||||
}
|
||||
|
||||
public int getVoiceLength() {
|
||||
return voiceLength;
|
||||
}
|
||||
|
||||
public void setVoiceLength(int voiceLength) {
|
||||
this.voiceLength = voiceLength;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public int getImgHeight() {
|
||||
return imgHeight;
|
||||
}
|
||||
|
||||
public void setImgHeight(int imgHeight) {
|
||||
this.imgHeight = imgHeight;
|
||||
}
|
||||
|
||||
public String getToUserName() {
|
||||
return toUserName;
|
||||
}
|
||||
|
||||
public void setToUserName(String toUserName) {
|
||||
this.toUserName = toUserName;
|
||||
}
|
||||
|
||||
public int getHasProductId() {
|
||||
return hasProductId;
|
||||
}
|
||||
|
||||
public void setHasProductId(int hasProductId) {
|
||||
this.hasProductId = hasProductId;
|
||||
}
|
||||
|
||||
public int getImgStatus() {
|
||||
return imgStatus;
|
||||
}
|
||||
|
||||
public void setImgStatus(int imgStatus) {
|
||||
this.imgStatus = imgStatus;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public int getImgWidth() {
|
||||
return imgWidth;
|
||||
}
|
||||
|
||||
public void setImgWidth(int imgWidth) {
|
||||
this.imgWidth = imgWidth;
|
||||
}
|
||||
|
||||
public int getForwardFlag() {
|
||||
return forwardFlag;
|
||||
}
|
||||
|
||||
public void setForwardFlag(int forwardFlag) {
|
||||
this.forwardFlag = forwardFlag;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getTicket() {
|
||||
return Ticket;
|
||||
}
|
||||
|
||||
public void setTicket(String ticket) {
|
||||
Ticket = ticket;
|
||||
}
|
||||
|
||||
public RecommendInfo getRecommendInfo() {
|
||||
return recommendInfo;
|
||||
}
|
||||
|
||||
public void setRecommendInfo(RecommendInfo recommendInfo) {
|
||||
this.recommendInfo = recommendInfo;
|
||||
}
|
||||
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(long createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public String getNewMsgId() {
|
||||
return newMsgId;
|
||||
}
|
||||
|
||||
public void setNewMsgId(String newMsgId) {
|
||||
this.newMsgId = newMsgId;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public int getMsgType() {
|
||||
return msgType;
|
||||
}
|
||||
|
||||
public void setMsgType(int msgType) {
|
||||
this.msgType = msgType;
|
||||
}
|
||||
|
||||
public boolean isGroupMsg() {
|
||||
return groupMsg;
|
||||
}
|
||||
|
||||
public void setGroupMsg(boolean groupMsg) {
|
||||
this.groupMsg = groupMsg;
|
||||
}
|
||||
|
||||
public String getMsgId() {
|
||||
return msgId;
|
||||
}
|
||||
|
||||
public void setMsgId(String msgId) {
|
||||
this.msgId = msgId;
|
||||
}
|
||||
|
||||
public int getStatusNotifyCode() {
|
||||
return statusNotifyCode;
|
||||
}
|
||||
|
||||
public void setStatusNotifyCode(int statusNotifyCode) {
|
||||
this.statusNotifyCode = statusNotifyCode;
|
||||
}
|
||||
|
||||
public AppInfo getAppInfo() {
|
||||
return appInfo;
|
||||
}
|
||||
|
||||
public void setAppInfo(AppInfo appInfo) {
|
||||
this.appInfo = appInfo;
|
||||
}
|
||||
|
||||
public int getAppMsgType() {
|
||||
return appMsgType;
|
||||
}
|
||||
|
||||
public void setAppMsgType(int appMsgType) {
|
||||
this.appMsgType = appMsgType;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return Type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public int getPlayLength() {
|
||||
return playLength;
|
||||
}
|
||||
|
||||
public void setPlayLength(int playLength) {
|
||||
this.playLength = playLength;
|
||||
}
|
||||
|
||||
public String getMediaId() {
|
||||
return mediaId;
|
||||
}
|
||||
|
||||
public void setMediaId(String mediaId) {
|
||||
this.mediaId = mediaId;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getStatusNotifyUserName() {
|
||||
return statusNotifyUserName;
|
||||
}
|
||||
|
||||
public void setStatusNotifyUserName(String statusNotifyUserName) {
|
||||
this.statusNotifyUserName = statusNotifyUserName;
|
||||
}
|
||||
|
||||
public String getFromUserName() {
|
||||
return fromUserName;
|
||||
}
|
||||
|
||||
public void setFromUserName(String fromUserName) {
|
||||
this.fromUserName = fromUserName;
|
||||
}
|
||||
|
||||
public String getOriContent() {
|
||||
return oriContent;
|
||||
}
|
||||
|
||||
public void setOriContent(String oriContent) {
|
||||
this.oriContent = oriContent;
|
||||
}
|
||||
|
||||
public String getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public void setFileSize(String fileSize) {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
public String getMemberNickname() {
|
||||
return memberNickname;
|
||||
}
|
||||
|
||||
public void setMemberNickname(String memberNickname) {
|
||||
this.memberNickname = memberNickname;
|
||||
}
|
||||
|
||||
public String getFromNickName() {
|
||||
return fromNickName;
|
||||
}
|
||||
|
||||
public void setFromNickName(String fromNickName) {
|
||||
this.fromNickName = fromNickName;
|
||||
}
|
||||
|
||||
public String getSendMemberId() {
|
||||
return sendMemberId;
|
||||
}
|
||||
|
||||
public void setSendMemberId(String sendMemberId) {
|
||||
this.sendMemberId = sendMemberId;
|
||||
}
|
||||
|
||||
public boolean isAtMe() {
|
||||
return atMe;
|
||||
}
|
||||
|
||||
public void setAtMe(boolean atMe) {
|
||||
this.atMe = atMe;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package org.ruoyi.common.wechat.itchat4j.beans;
|
||||
|
||||
/**
|
||||
* @author WesleyOne
|
||||
* @create 2018/12/21
|
||||
*/
|
||||
@Deprecated
|
||||
public class BaseResponse {
|
||||
|
||||
private Integer Ret;
|
||||
private String ErrMsg;
|
||||
|
||||
public Integer getRet() {
|
||||
return Ret;
|
||||
}
|
||||
|
||||
public void setRet(Integer ret) {
|
||||
Ret = ret;
|
||||
}
|
||||
|
||||
public String getErrMsg() {
|
||||
return ErrMsg;
|
||||
}
|
||||
|
||||
public void setErrMsg(String errMsg) {
|
||||
ErrMsg = errMsg;
|
||||
}
|
||||
}
|
||||
@@ -1,306 +0,0 @@
|
||||
package org.ruoyi.common.wechat.itchat4j.beans;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 成员信息对象
|
||||
*
|
||||
* 来自获取好友列表
|
||||
* /cgi-bin/mmwebwx-bin/webwxgetcontact
|
||||
* MemberList中单体
|
||||
* @author WesleyOne
|
||||
* @create 2018/12/21
|
||||
*/
|
||||
@Deprecated
|
||||
public class Member {
|
||||
|
||||
private String Alias;
|
||||
private Integer AppAccountFlag;
|
||||
private Integer AttrStatus;
|
||||
private Integer ChatRoomId;
|
||||
private String City;
|
||||
private Integer ContactFlag;
|
||||
/**
|
||||
* 群昵称
|
||||
*/
|
||||
private String DisplayName;
|
||||
private String EncryChatRoomId;
|
||||
private String HeadImgUrl;
|
||||
private Integer HideInputBarFlag;
|
||||
private Integer IsOwner;
|
||||
private String KeyWord;
|
||||
private Integer MemberCount;
|
||||
private List<Member> MemberList;
|
||||
private String NickName;
|
||||
private Integer OwnerUin;
|
||||
private String PYInitial;
|
||||
private String PYQuanPin;
|
||||
private String Province;
|
||||
/**
|
||||
* 备注名、首拼、全拼
|
||||
*/
|
||||
private String RemarkName;
|
||||
private String RemarkPYInitial;
|
||||
private String RemarkPYQuanPin;
|
||||
|
||||
private Integer Sex;
|
||||
private String Signature;
|
||||
private Integer SnsFlag;
|
||||
private Integer StarFriend;
|
||||
private Integer Statues;
|
||||
private Integer Uin;
|
||||
private Integer UniFriend;
|
||||
private String UserName;
|
||||
/**
|
||||
* 用来判断是否是公众号或服务号的字段
|
||||
*/
|
||||
private String VerifyFlag;
|
||||
|
||||
public String getAlias() {
|
||||
return Alias;
|
||||
}
|
||||
|
||||
public void setAlias(String alias) {
|
||||
Alias = alias;
|
||||
}
|
||||
|
||||
public Integer getAppAccountFlag() {
|
||||
return AppAccountFlag;
|
||||
}
|
||||
|
||||
public void setAppAccountFlag(Integer appAccountFlag) {
|
||||
AppAccountFlag = appAccountFlag;
|
||||
}
|
||||
|
||||
public Integer getAttrStatus() {
|
||||
return AttrStatus;
|
||||
}
|
||||
|
||||
public void setAttrStatus(Integer attrStatus) {
|
||||
AttrStatus = attrStatus;
|
||||
}
|
||||
|
||||
public Integer getChatRoomId() {
|
||||
return ChatRoomId;
|
||||
}
|
||||
|
||||
public void setChatRoomId(Integer chatRoomId) {
|
||||
ChatRoomId = chatRoomId;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return City;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
City = city;
|
||||
}
|
||||
|
||||
public Integer getContactFlag() {
|
||||
return ContactFlag;
|
||||
}
|
||||
|
||||
public void setContactFlag(Integer contactFlag) {
|
||||
ContactFlag = contactFlag;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return DisplayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
DisplayName = displayName;
|
||||
}
|
||||
|
||||
public String getEncryChatRoomId() {
|
||||
return EncryChatRoomId;
|
||||
}
|
||||
|
||||
public void setEncryChatRoomId(String encryChatRoomId) {
|
||||
EncryChatRoomId = encryChatRoomId;
|
||||
}
|
||||
|
||||
public String getHeadImgUrl() {
|
||||
return HeadImgUrl;
|
||||
}
|
||||
|
||||
public void setHeadImgUrl(String headImgUrl) {
|
||||
HeadImgUrl = headImgUrl;
|
||||
}
|
||||
|
||||
public Integer getHideInputBarFlag() {
|
||||
return HideInputBarFlag;
|
||||
}
|
||||
|
||||
public void setHideInputBarFlag(Integer hideInputBarFlag) {
|
||||
HideInputBarFlag = hideInputBarFlag;
|
||||
}
|
||||
|
||||
public Integer getIsOwner() {
|
||||
return IsOwner;
|
||||
}
|
||||
|
||||
public void setIsOwner(Integer isOwner) {
|
||||
IsOwner = isOwner;
|
||||
}
|
||||
|
||||
public String getKeyWord() {
|
||||
return KeyWord;
|
||||
}
|
||||
|
||||
public void setKeyWord(String keyWord) {
|
||||
KeyWord = keyWord;
|
||||
}
|
||||
|
||||
public Integer getMemberCount() {
|
||||
return MemberCount;
|
||||
}
|
||||
|
||||
public void setMemberCount(Integer memberCount) {
|
||||
MemberCount = memberCount;
|
||||
}
|
||||
|
||||
public List<Member> getMemberList() {
|
||||
return MemberList;
|
||||
}
|
||||
|
||||
public void setMemberList(List<Member> memberList) {
|
||||
MemberList = memberList;
|
||||
}
|
||||
|
||||
public String getNickName() {
|
||||
return NickName;
|
||||
}
|
||||
|
||||
public void setNickName(String nickName) {
|
||||
NickName = nickName;
|
||||
}
|
||||
|
||||
public Integer getOwnerUin() {
|
||||
return OwnerUin;
|
||||
}
|
||||
|
||||
public void setOwnerUin(Integer ownerUin) {
|
||||
OwnerUin = ownerUin;
|
||||
}
|
||||
|
||||
public String getPYInitial() {
|
||||
return PYInitial;
|
||||
}
|
||||
|
||||
public void setPYInitial(String PYInitial) {
|
||||
this.PYInitial = PYInitial;
|
||||
}
|
||||
|
||||
public String getPYQuanPin() {
|
||||
return PYQuanPin;
|
||||
}
|
||||
|
||||
public void setPYQuanPin(String PYQuanPin) {
|
||||
this.PYQuanPin = PYQuanPin;
|
||||
}
|
||||
|
||||
public String getProvince() {
|
||||
return Province;
|
||||
}
|
||||
|
||||
public void setProvince(String province) {
|
||||
Province = province;
|
||||
}
|
||||
|
||||
public String getRemarkName() {
|
||||
return RemarkName;
|
||||
}
|
||||
|
||||
public void setRemarkName(String remarkName) {
|
||||
RemarkName = remarkName;
|
||||
}
|
||||
|
||||
public String getRemarkPYInitial() {
|
||||
return RemarkPYInitial;
|
||||
}
|
||||
|
||||
public void setRemarkPYInitial(String remarkPYInitial) {
|
||||
RemarkPYInitial = remarkPYInitial;
|
||||
}
|
||||
|
||||
public String getRemarkPYQuanPin() {
|
||||
return RemarkPYQuanPin;
|
||||
}
|
||||
|
||||
public void setRemarkPYQuanPin(String remarkPYQuanPin) {
|
||||
RemarkPYQuanPin = remarkPYQuanPin;
|
||||
}
|
||||
|
||||
public Integer getSex() {
|
||||
return Sex;
|
||||
}
|
||||
|
||||
public void setSex(Integer sex) {
|
||||
Sex = sex;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return Signature;
|
||||
}
|
||||
|
||||
public void setSignature(String signature) {
|
||||
Signature = signature;
|
||||
}
|
||||
|
||||
public Integer getSnsFlag() {
|
||||
return SnsFlag;
|
||||
}
|
||||
|
||||
public void setSnsFlag(Integer snsFlag) {
|
||||
SnsFlag = snsFlag;
|
||||
}
|
||||
|
||||
public Integer getStarFriend() {
|
||||
return StarFriend;
|
||||
}
|
||||
|
||||
public void setStarFriend(Integer starFriend) {
|
||||
StarFriend = starFriend;
|
||||
}
|
||||
|
||||
public Integer getStatues() {
|
||||
return Statues;
|
||||
}
|
||||
|
||||
public void setStatues(Integer statues) {
|
||||
Statues = statues;
|
||||
}
|
||||
|
||||
public Integer getUin() {
|
||||
return Uin;
|
||||
}
|
||||
|
||||
public void setUin(Integer uin) {
|
||||
Uin = uin;
|
||||
}
|
||||
|
||||
public Integer getUniFriend() {
|
||||
return UniFriend;
|
||||
}
|
||||
|
||||
public void setUniFriend(Integer uniFriend) {
|
||||
UniFriend = uniFriend;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return UserName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
UserName = userName;
|
||||
}
|
||||
|
||||
public String getVerifyFlag() {
|
||||
return VerifyFlag;
|
||||
}
|
||||
|
||||
public void setVerifyFlag(String verifyFlag) {
|
||||
VerifyFlag = verifyFlag;
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
package org.ruoyi.common.wechat.itchat4j.beans;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* RecommendInfo
|
||||
*
|
||||
* @author https://github.com/yaphone
|
||||
* @date 创建时间:2017年7月3日 下午10:35:14
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
public class RecommendInfo implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String ticket;
|
||||
private String userName;
|
||||
private int sex;
|
||||
private int attrStatus;
|
||||
private String city;
|
||||
private String nickName;
|
||||
private int scene;
|
||||
private String province;
|
||||
private String content;
|
||||
private String alias;
|
||||
private String signature;
|
||||
private int opCode;
|
||||
private int qQNum;
|
||||
private int verifyFlag;
|
||||
|
||||
public String getTicket() {
|
||||
return ticket;
|
||||
}
|
||||
|
||||
public void setTicket(String ticket) {
|
||||
this.ticket = ticket;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public int getSex() {
|
||||
return sex;
|
||||
}
|
||||
|
||||
public void setSex(int sex) {
|
||||
this.sex = sex;
|
||||
}
|
||||
|
||||
public int getAttrStatus() {
|
||||
return attrStatus;
|
||||
}
|
||||
|
||||
public void setAttrStatus(int attrStatus) {
|
||||
this.attrStatus = attrStatus;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getNickName() {
|
||||
return nickName;
|
||||
}
|
||||
|
||||
public void setNickName(String nickName) {
|
||||
this.nickName = nickName;
|
||||
}
|
||||
|
||||
public int getScene() {
|
||||
return scene;
|
||||
}
|
||||
|
||||
public void setScene(int scene) {
|
||||
this.scene = scene;
|
||||
}
|
||||
|
||||
public String getProvince() {
|
||||
return province;
|
||||
}
|
||||
|
||||
public void setProvince(String province) {
|
||||
this.province = province;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public void setAlias(String alias) {
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public int getOpCode() {
|
||||
return opCode;
|
||||
}
|
||||
|
||||
public void setOpCode(int opCode) {
|
||||
this.opCode = opCode;
|
||||
}
|
||||
|
||||
public int getqQNum() {
|
||||
return qQNum;
|
||||
}
|
||||
|
||||
public void setqQNum(int qQNum) {
|
||||
this.qQNum = qQNum;
|
||||
}
|
||||
|
||||
public int getVerifyFlag() {
|
||||
return verifyFlag;
|
||||
}
|
||||
|
||||
public void setVerifyFlag(int verifyFlag) {
|
||||
this.verifyFlag = verifyFlag;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user