feat(知识库): 增加知识库模块
392
application.yml
@@ -1,392 +0,0 @@
|
|||||||
# 项目相关配置
|
|
||||||
ruoyi:
|
|
||||||
# 名称
|
|
||||||
name: "xmzs"
|
|
||||||
# 版本
|
|
||||||
version: ${revision}
|
|
||||||
# 版权年份
|
|
||||||
copyrightYear: 2023
|
|
||||||
# 实例演示开关
|
|
||||||
demoEnabled: true
|
|
||||||
# 获取ip地址开关
|
|
||||||
addressEnabled: false
|
|
||||||
|
|
||||||
captcha:
|
|
||||||
enable: false
|
|
||||||
# 页面 <参数设置> 可开启关闭 验证码校验
|
|
||||||
# 验证码类型 math 数组计算 char 字符验证
|
|
||||||
type: MATH
|
|
||||||
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
|
|
||||||
category: CIRCLE
|
|
||||||
# 数字验证码位数
|
|
||||||
numberLength: 1
|
|
||||||
# 字符验证码长度
|
|
||||||
charLength: 4
|
|
||||||
|
|
||||||
# 开发环境配置
|
|
||||||
server:
|
|
||||||
# 服务器的HTTP端口,默认为8080
|
|
||||||
port: 6039
|
|
||||||
servlet:
|
|
||||||
# 应用的访问路径
|
|
||||||
context-path: /
|
|
||||||
# undertow 配置
|
|
||||||
undertow:
|
|
||||||
# HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的
|
|
||||||
max-http-post-size: -1
|
|
||||||
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
|
|
||||||
# 每块buffer的空间大小,越小的空间被利用越充分
|
|
||||||
buffer-size: 512
|
|
||||||
# 是否分配的直接内存
|
|
||||||
direct-buffers: true
|
|
||||||
threads:
|
|
||||||
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
|
|
||||||
io: 8
|
|
||||||
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
|
|
||||||
worker: 256
|
|
||||||
|
|
||||||
# 日志配置
|
|
||||||
logging:
|
|
||||||
level:
|
|
||||||
com.xmzs: @logging.level@
|
|
||||||
org.springframework: warn
|
|
||||||
config: classpath:logback-plus.xml
|
|
||||||
|
|
||||||
# 用户配置
|
|
||||||
user:
|
|
||||||
password:
|
|
||||||
# 密码最大错误次数
|
|
||||||
maxRetryCount: 5
|
|
||||||
# 密码锁定时间(默认10分钟)
|
|
||||||
lockTime: 10
|
|
||||||
|
|
||||||
# Spring配置
|
|
||||||
spring:
|
|
||||||
application:
|
|
||||||
name: ${ruoyi.name}
|
|
||||||
# 资源信息
|
|
||||||
messages:
|
|
||||||
# 国际化资源文件路径
|
|
||||||
basename: i18n/messages
|
|
||||||
profiles:
|
|
||||||
active: @profiles.active@
|
|
||||||
# 文件上传
|
|
||||||
servlet:
|
|
||||||
multipart:
|
|
||||||
# 单个文件大小
|
|
||||||
max-file-size: 10MB
|
|
||||||
# 设置总上传的文件大小
|
|
||||||
max-request-size: 20MB
|
|
||||||
mvc:
|
|
||||||
format:
|
|
||||||
date-time: yyyy-MM-dd HH:mm:ss
|
|
||||||
jackson:
|
|
||||||
# 日期格式化
|
|
||||||
date-format: yyyy-MM-dd HH:mm:ss
|
|
||||||
serialization:
|
|
||||||
# 格式化输出
|
|
||||||
indent_output: false
|
|
||||||
# 忽略无法转换的对象
|
|
||||||
fail_on_empty_beans: false
|
|
||||||
deserialization:
|
|
||||||
# 允许对象忽略json中不存在的属性
|
|
||||||
fail_on_unknown_properties: false
|
|
||||||
|
|
||||||
# Sa-Token配置
|
|
||||||
sa-token:
|
|
||||||
# token名称 (同时也是cookie名称)
|
|
||||||
token-name: Authorization
|
|
||||||
# token有效期 设为7天 (必定过期) 单位: 秒
|
|
||||||
timeout: 604800
|
|
||||||
# token临时有效期 (指定时间无操作就过期) 单位: 秒
|
|
||||||
activity-timeout: 604800
|
|
||||||
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
|
||||||
is-concurrent: true
|
|
||||||
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
|
||||||
is-share: false
|
|
||||||
# 是否尝试从header里读取token
|
|
||||||
is-read-header: true
|
|
||||||
# 是否尝试从cookie里读取token
|
|
||||||
is-read-cookie: false
|
|
||||||
# token前缀
|
|
||||||
token-prefix: "Bearer"
|
|
||||||
# jwt秘钥
|
|
||||||
jwt-secret-key: abcdefghijklmnopqrstuvwxyz
|
|
||||||
|
|
||||||
# security配置
|
|
||||||
security:
|
|
||||||
# 排除路径
|
|
||||||
excludes:
|
|
||||||
# 修改用户头像
|
|
||||||
- /system/user/edit/avatar
|
|
||||||
- /pay/returnUrl
|
|
||||||
- /pay/notifyUrl
|
|
||||||
# 上传文件
|
|
||||||
- /resource/oss/upload
|
|
||||||
# 重置密码
|
|
||||||
- /auth/reset/password
|
|
||||||
# 聊天接口
|
|
||||||
- /chat
|
|
||||||
# 静态资源
|
|
||||||
- /*.html
|
|
||||||
- /**/*.html
|
|
||||||
- /**/*.css
|
|
||||||
- /**/*.js
|
|
||||||
# 公共路径
|
|
||||||
- /favicon.ico
|
|
||||||
- /error
|
|
||||||
# swagger 文档配置
|
|
||||||
- /*/api-docs
|
|
||||||
- /*/api-docs/**
|
|
||||||
# actuator 监控配置
|
|
||||||
- /actuator
|
|
||||||
- /actuator/**
|
|
||||||
# 多租户配置
|
|
||||||
tenant:
|
|
||||||
# 是否开启
|
|
||||||
enable: false
|
|
||||||
# 排除表
|
|
||||||
excludes:
|
|
||||||
- sys_menu
|
|
||||||
- sys_tenant
|
|
||||||
- sys_tenant_package
|
|
||||||
- sys_role_dept
|
|
||||||
- sys_role_menu
|
|
||||||
- sys_user_post
|
|
||||||
- sys_user_role
|
|
||||||
|
|
||||||
# MyBatisPlus配置
|
|
||||||
# https://baomidou.com/config/
|
|
||||||
mybatis-plus:
|
|
||||||
# 不支持多包, 如有需要可在注解配置 或 提升扫包等级
|
|
||||||
# 例如 com.**.**.mapper
|
|
||||||
mapperPackage: com.xmzs.**.mapper
|
|
||||||
# 对应的 XML 文件位置
|
|
||||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
|
||||||
# 实体扫描,多个package用逗号或者分号分隔
|
|
||||||
typeAliasesPackage: com.xmzs.**.domain
|
|
||||||
# 启动时是否检查 MyBatis XML 文件的存在,默认不检查
|
|
||||||
checkConfigLocation: false
|
|
||||||
configuration:
|
|
||||||
# 自动驼峰命名规则(camel case)映射
|
|
||||||
mapUnderscoreToCamelCase: true
|
|
||||||
# MyBatis 自动映射策略
|
|
||||||
# NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射
|
|
||||||
autoMappingBehavior: FULL
|
|
||||||
# MyBatis 自动映射时未知列或未知属性处理策
|
|
||||||
# NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
|
|
||||||
autoMappingUnknownColumnBehavior: NONE
|
|
||||||
# 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
|
|
||||||
# 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
|
|
||||||
# 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
|
|
||||||
logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
|
|
||||||
global-config:
|
|
||||||
# 是否打印 Logo banner
|
|
||||||
banner: true
|
|
||||||
dbConfig:
|
|
||||||
# 主键类型
|
|
||||||
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
|
|
||||||
idType: ASSIGN_ID
|
|
||||||
# 逻辑已删除值
|
|
||||||
logicDeleteValue: 2
|
|
||||||
# 逻辑未删除值
|
|
||||||
logicNotDeleteValue: 0
|
|
||||||
# 字段验证策略之 insert,在 insert 的时候的字段验证策略
|
|
||||||
# IGNORED 忽略 NOT_NULL 非NULL NOT_EMPTY 非空 DEFAULT 默认 NEVER 不加入 SQL
|
|
||||||
insertStrategy: NOT_NULL
|
|
||||||
# 字段验证策略之 update,在 update 的时候的字段验证策略
|
|
||||||
updateStrategy: NOT_NULL
|
|
||||||
# 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件
|
|
||||||
where-strategy: NOT_NULL
|
|
||||||
|
|
||||||
# 数据加密
|
|
||||||
mybatis-encryptor:
|
|
||||||
# 是否开启加密
|
|
||||||
enable: false
|
|
||||||
# 默认加密算法
|
|
||||||
algorithm: BASE64
|
|
||||||
# 编码方式 BASE64/HEX。默认BASE64
|
|
||||||
encode: BASE64
|
|
||||||
# 安全秘钥 对称算法的秘钥 如:AES,SM4
|
|
||||||
password:
|
|
||||||
# 公私钥 非对称算法的公私钥 如:SM2,RSA
|
|
||||||
publicKey:
|
|
||||||
privateKey:
|
|
||||||
|
|
||||||
# Swagger配置
|
|
||||||
swagger:
|
|
||||||
info:
|
|
||||||
# 标题
|
|
||||||
title: '标题:${ruoyi.name}多租户管理系统_接口文档'
|
|
||||||
# 描述
|
|
||||||
description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
|
|
||||||
# 版本
|
|
||||||
version: '版本号: ${ruoyi.version}'
|
|
||||||
# 作者信息
|
|
||||||
contact:
|
|
||||||
name: ageerle
|
|
||||||
email: ageerle@163.com
|
|
||||||
url: https://gitee.com/ageerle/ruoyi-ai
|
|
||||||
components:
|
|
||||||
# 鉴权方式配置
|
|
||||||
security-schemes:
|
|
||||||
apiKey:
|
|
||||||
type: APIKEY
|
|
||||||
in: HEADER
|
|
||||||
name: ${sa-token.token-name}
|
|
||||||
|
|
||||||
springdoc:
|
|
||||||
api-docs:
|
|
||||||
# 是否开启接口文档
|
|
||||||
enabled: true
|
|
||||||
swagger-ui:
|
|
||||||
# 持久化认证数据
|
|
||||||
persistAuthorization: true
|
|
||||||
#这里定义了两个分组,可定义多个,也可以不定义
|
|
||||||
group-configs:
|
|
||||||
- group: 1.演示模块
|
|
||||||
packages-to-scan: com.xmzs.demo
|
|
||||||
- group: 2.通用模块
|
|
||||||
packages-to-scan: com.xmzs.web
|
|
||||||
- group: 3.系统模块
|
|
||||||
packages-to-scan: com.xmzs.system
|
|
||||||
- group: 4.代码生成模块
|
|
||||||
packages-to-scan: com.xmzs.generator
|
|
||||||
|
|
||||||
# 防止XSS攻击
|
|
||||||
xss:
|
|
||||||
# 过滤开关
|
|
||||||
enabled: true
|
|
||||||
# 排除链接(多个用逗号分隔)
|
|
||||||
excludes: /system/notice
|
|
||||||
# 匹配链接
|
|
||||||
urlPatterns: /system/*,/monitor/*,/tool/*
|
|
||||||
|
|
||||||
# 全局线程池相关配置
|
|
||||||
thread-pool:
|
|
||||||
# 是否开启线程池
|
|
||||||
enabled: false
|
|
||||||
# 队列最大长度
|
|
||||||
queueCapacity: 128
|
|
||||||
# 线程池维护线程所允许的空闲时间
|
|
||||||
keepAliveSeconds: 300
|
|
||||||
|
|
||||||
--- # 分布式锁 lock4j 全局配置
|
|
||||||
lock4j:
|
|
||||||
# 获取分布式锁超时时间,默认为 3000 毫秒
|
|
||||||
acquire-timeout: 3000
|
|
||||||
# 分布式锁的超时时间,默认为 30 秒
|
|
||||||
expire: 30000
|
|
||||||
|
|
||||||
--- # Actuator 监控端点的配置项
|
|
||||||
management:
|
|
||||||
endpoints:
|
|
||||||
web:
|
|
||||||
exposure:
|
|
||||||
include: '*'
|
|
||||||
endpoint:
|
|
||||||
health:
|
|
||||||
show-details: ALWAYS
|
|
||||||
logfile:
|
|
||||||
external-file: ./logs/sys-console.log
|
|
||||||
|
|
||||||
--- # websocket
|
|
||||||
websocket:
|
|
||||||
enabled: false
|
|
||||||
# 路径
|
|
||||||
path: ''
|
|
||||||
# 设置访问源地址
|
|
||||||
allowedOrigins: '*'
|
|
||||||
|
|
||||||
# 微信小程序配置信息
|
|
||||||
wx:
|
|
||||||
miniapp:
|
|
||||||
configs:
|
|
||||||
- appid: # 你的appid
|
|
||||||
secret: # 你的secret
|
|
||||||
token: #微信小程序消息服务器配置的token
|
|
||||||
aesKey: #微信小程序消息服务器配置的EncodingAESKey
|
|
||||||
msgDataFormat: JSON
|
|
||||||
baidu:
|
|
||||||
# 是否开启文本审核
|
|
||||||
enabled: false
|
|
||||||
# 文本审核
|
|
||||||
textReview:
|
|
||||||
apiKey: '' # apiKey
|
|
||||||
secretKey: '' # secretKey
|
|
||||||
appKey: xxxxxxxxxxxxxxxxx
|
|
||||||
secretKey: xxxxxxxxxxxxxxxxxxxxxxx
|
|
||||||
|
|
||||||
wechat:
|
|
||||||
# 是否使用微信 true/false
|
|
||||||
enable: true
|
|
||||||
# 生成的登录二维码路径 默认与项目同级
|
|
||||||
qrPath: "./"
|
|
||||||
|
|
||||||
keyword:
|
|
||||||
# 重置会话指令
|
|
||||||
reset: "重置会话"
|
|
||||||
# ai画图指令(DALL·E模型 https://platform.openai.com/docs/models/dall-e)
|
|
||||||
# generation 根据关键词生成图片(https://platform.openai.com/docs/guides/images/generations)
|
|
||||||
image: "ai画图"
|
|
||||||
# ai语音指令(TTS模型 https://platform.openai.com/docs/api-reference/audio)
|
|
||||||
audio: "ai语音"
|
|
||||||
|
|
||||||
mj:
|
|
||||||
api-secret: 'sk-xx'
|
|
||||||
task-store:
|
|
||||||
type: in_memory
|
|
||||||
timeout: 30d
|
|
||||||
translate-way: gpt
|
|
||||||
# proxy:
|
|
||||||
# host: 127.0.0.1
|
|
||||||
# port: 10809
|
|
||||||
ng-discord:
|
|
||||||
server: 'https://xxx.pandarobot.chat/'
|
|
||||||
cdn: 'https://xxx.pandarobot.chat/'
|
|
||||||
wss: 'https://xxx.pandarobot.chat/'
|
|
||||||
openai:
|
|
||||||
gpt-api-url: 'https://api.pandarobot.chat/'
|
|
||||||
gpt-api-key: 'sk-xx'
|
|
||||||
accounts:
|
|
||||||
- guild-id: 'xx'
|
|
||||||
channel-id: 'xx'
|
|
||||||
user-token: 'xx'
|
|
||||||
|
|
||||||
--- # mail 邮件发送
|
|
||||||
mail:
|
|
||||||
enabled: true
|
|
||||||
host: smtp.163.com
|
|
||||||
port: 465
|
|
||||||
# 是否需要用户名密码验证
|
|
||||||
auth: true
|
|
||||||
# 发送方,遵循RFC-822标准
|
|
||||||
from: ageerle@163.com
|
|
||||||
# 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
|
|
||||||
user: ageerle@163.com
|
|
||||||
# 密码(填写授权码)
|
|
||||||
pass: TOGXBVPYFVPFRQMQ
|
|
||||||
# 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
|
|
||||||
starttlsEnable: true
|
|
||||||
# 使用SSL安全连接
|
|
||||||
sslEnable: true
|
|
||||||
# SMTP超时时长,单位毫秒,缺省值不超时
|
|
||||||
timeout: 0
|
|
||||||
# Socket连接超时值,单位毫秒,缺省值不超时
|
|
||||||
connectionTimeout: 0
|
|
||||||
|
|
||||||
# chatgpt配置信息
|
|
||||||
chat:
|
|
||||||
apiKey: 'sk-xxx'
|
|
||||||
apiHost: 'https://api.pandarobot.chat/'
|
|
||||||
|
|
||||||
# 支付配置信息
|
|
||||||
pay:
|
|
||||||
pid: 'xxx'
|
|
||||||
key: 'xxx'
|
|
||||||
payUrl: 'https://pay.pandarobot.chat/mapi.php'
|
|
||||||
notify_url: 'https://www.pandarobot.chat/pay/returnUrl'
|
|
||||||
return_url: 'https://www.pandarobot.chat/pay/notifyUrl'
|
|
||||||
type: 'wxpay'
|
|
||||||
device: 'pc'
|
|
||||||
sign_type: 'MD5'
|
|
||||||
@@ -57,7 +57,10 @@
|
|||||||
<artifactId>ruoyi-fusion</artifactId>
|
<artifactId>ruoyi-fusion</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ruoyi</groupId>
|
||||||
|
<artifactId>ruoyi-knowledge</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- demo模块 -->
|
<!-- demo模块 -->
|
||||||
@@ -78,6 +81,12 @@
|
|||||||
<artifactId>thumbnailator</artifactId>
|
<artifactId>thumbnailator</artifactId>
|
||||||
<version>0.4.11</version>
|
<version>0.4.11</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.ollama4j</groupId>
|
||||||
|
<artifactId>ollama4j</artifactId>
|
||||||
|
<version>1.0.79</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
package com.xmzs;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启动程序
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
|
|
||||||
@SpringBootApplication
|
|
||||||
public class PandaApplication {
|
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication application = new SpringApplication(PandaApplication.class);
|
|
||||||
application.setApplicationStartup(new BufferingApplicationStartup(2048));
|
|
||||||
application.run(args);
|
|
||||||
System.out.println("(♥◠‿◠)ノ゙ panda智能助手启动成功 ლ(´ڡ`ლ)゙");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package com.xmzs;
|
|
||||||
|
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
|
||||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* web容器中进行部署
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
public class PandaServletInitializer extends SpringBootServletInitializer {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
|
||||||
return application.sources(PandaApplication.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
package com.xmzs.controller;
|
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaIgnore;
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
|
||||||
import com.xmzs.common.core.constant.Constants;
|
|
||||||
import com.xmzs.common.core.domain.R;
|
|
||||||
import com.xmzs.common.core.domain.model.*;
|
|
||||||
import com.xmzs.common.core.utils.MapstructUtils;
|
|
||||||
import com.xmzs.common.core.utils.StreamUtils;
|
|
||||||
import com.xmzs.common.core.utils.StringUtils;
|
|
||||||
import com.xmzs.common.satoken.utils.LoginHelper;
|
|
||||||
import com.xmzs.common.tenant.helper.TenantHelper;
|
|
||||||
import com.xmzs.system.domain.bo.SysTenantBo;
|
|
||||||
import com.xmzs.system.domain.vo.LoginTenantVo;
|
|
||||||
import com.xmzs.system.domain.vo.SysTenantVo;
|
|
||||||
import com.xmzs.system.domain.vo.TenantListVo;
|
|
||||||
import com.xmzs.system.service.ISysTenantService;
|
|
||||||
|
|
||||||
|
|
||||||
import com.xmzs.system.service.SysLoginService;
|
|
||||||
import com.xmzs.system.service.SysRegisterService;
|
|
||||||
import com.xmzs.web.domain.vo.LoginVo;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 认证
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@SaIgnore
|
|
||||||
@Validated
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/auth")
|
|
||||||
public class AuthController {
|
|
||||||
|
|
||||||
private final SysLoginService loginService;
|
|
||||||
private final SysRegisterService registerService;
|
|
||||||
private final ISysTenantService tenantService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录方法
|
|
||||||
*
|
|
||||||
* @param body 登录信息
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@PostMapping("/login")
|
|
||||||
public R<LoginVo> login(@Validated @RequestBody LoginBody body) {
|
|
||||||
body.setTenantId(Constants.TENANT_ID);
|
|
||||||
LoginVo loginVo = new LoginVo();
|
|
||||||
// 生成令牌
|
|
||||||
String token = loginService.login(
|
|
||||||
body.getTenantId(),
|
|
||||||
body.getUsername(), body.getPassword(),
|
|
||||||
body.getCode(), body.getUuid());
|
|
||||||
loginVo.setToken(token);
|
|
||||||
loginVo.setUserInfo(LoginHelper.getLoginUser());
|
|
||||||
return R.ok(loginVo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 短信登录
|
|
||||||
*
|
|
||||||
* @param body 登录信息
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@PostMapping("/smsLogin")
|
|
||||||
public R<LoginVo> smsLogin(@Validated @RequestBody SmsLoginBody body) {
|
|
||||||
LoginVo loginVo = new LoginVo();
|
|
||||||
// 生成令牌
|
|
||||||
String token = loginService.smsLogin(body.getTenantId(), body.getPhonenumber(), body.getSmsCode());
|
|
||||||
loginVo.setToken(token);
|
|
||||||
return R.ok(loginVo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 邮件登录
|
|
||||||
*
|
|
||||||
* @param body 登录信息
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@PostMapping("/emailLogin")
|
|
||||||
public R<LoginVo> emailLogin(@Validated @RequestBody EmailLoginBody body) {
|
|
||||||
LoginVo loginVo = new LoginVo();
|
|
||||||
// 生成令牌
|
|
||||||
String token = loginService.emailLogin(body.getTenantId(), body.getEmail(), body.getEmailCode());
|
|
||||||
loginVo.setToken(token);
|
|
||||||
return R.ok(loginVo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 游客登录
|
|
||||||
*
|
|
||||||
* @param loginBody
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@PostMapping("/visitorLogin")
|
|
||||||
public R<LoginVo> xcxLogin(@RequestBody VisitorLoginBody loginBody) {
|
|
||||||
return R.ok(loginService.visitorLogin(loginBody));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退出登录
|
|
||||||
*/
|
|
||||||
@PostMapping("/logout")
|
|
||||||
public R<Void> logout() {
|
|
||||||
loginService.logout();
|
|
||||||
return R.ok("退出成功");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户注册
|
|
||||||
*/
|
|
||||||
@PostMapping("/register")
|
|
||||||
public R<Void> register(@Validated @RequestBody RegisterBody user) {
|
|
||||||
registerService.register(user);
|
|
||||||
return R.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重置密码
|
|
||||||
*/
|
|
||||||
@PostMapping("/reset/password")
|
|
||||||
@SaIgnore
|
|
||||||
public R<Void> resetPassWord(@Validated @RequestBody RegisterBody user) {
|
|
||||||
registerService.resetPassWord(user);
|
|
||||||
return R.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录页面租户下拉框
|
|
||||||
*
|
|
||||||
* @return 租户列表
|
|
||||||
*/
|
|
||||||
@GetMapping("/tenant/list")
|
|
||||||
public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception {
|
|
||||||
List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo());
|
|
||||||
List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class);
|
|
||||||
// 获取域名
|
|
||||||
String host = new URL(request.getRequestURL().toString()).getHost();
|
|
||||||
// 根据域名进行筛选
|
|
||||||
List<TenantListVo> list = StreamUtils.filter(voList, vo -> StringUtils.equals(vo.getDomain(), host));
|
|
||||||
// 返回对象
|
|
||||||
LoginTenantVo vo = new LoginTenantVo();
|
|
||||||
vo.setVoList(CollUtil.isNotEmpty(list) ? list : voList);
|
|
||||||
vo.setTenantEnabled(TenantHelper.isEnable());
|
|
||||||
return R.ok(vo);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
package com.xmzs.controller;
|
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaIgnore;
|
|
||||||
import cn.hutool.captcha.AbstractCaptcha;
|
|
||||||
import cn.hutool.captcha.generator.CodeGenerator;
|
|
||||||
import cn.hutool.core.util.IdUtil;
|
|
||||||
import cn.hutool.core.util.RandomUtil;
|
|
||||||
import com.xmzs.common.core.constant.Constants;
|
|
||||||
import com.xmzs.common.core.constant.GlobalConstants;
|
|
||||||
import com.xmzs.common.core.domain.R;
|
|
||||||
import com.xmzs.common.core.utils.SpringUtils;
|
|
||||||
import com.xmzs.common.core.utils.StringUtils;
|
|
||||||
import com.xmzs.common.core.utils.reflect.ReflectUtils;
|
|
||||||
import com.xmzs.common.mail.config.properties.MailProperties;
|
|
||||||
import com.xmzs.common.mail.utils.MailUtils;
|
|
||||||
import com.xmzs.common.redis.utils.RedisUtils;
|
|
||||||
import com.xmzs.common.sms.config.properties.SmsProperties;
|
|
||||||
import com.xmzs.common.sms.core.SmsTemplate;
|
|
||||||
import com.xmzs.common.sms.entity.SmsResult;
|
|
||||||
import com.xmzs.common.web.config.properties.CaptchaProperties;
|
|
||||||
import com.xmzs.common.web.enums.CaptchaType;
|
|
||||||
import com.xmzs.web.domain.request.EmailRequest;
|
|
||||||
import com.xmzs.web.domain.vo.CaptchaVo;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.expression.Expression;
|
|
||||||
import org.springframework.expression.ExpressionParser;
|
|
||||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码操作处理
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@SaIgnore
|
|
||||||
@Slf4j
|
|
||||||
@Validated
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RestController
|
|
||||||
public class CaptchaController {
|
|
||||||
|
|
||||||
private final CaptchaProperties captchaProperties;
|
|
||||||
private final SmsProperties smsProperties;
|
|
||||||
private final MailProperties mailProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 短信验证码
|
|
||||||
*
|
|
||||||
* @param phonenumber 用户手机号
|
|
||||||
*/
|
|
||||||
@GetMapping("/resource/sms/code")
|
|
||||||
public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
|
|
||||||
if (!smsProperties.getEnabled()) {
|
|
||||||
return R.fail("当前系统没有开启短信功能!");
|
|
||||||
}
|
|
||||||
String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber;
|
|
||||||
String code = RandomUtil.randomNumbers(4);
|
|
||||||
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
|
|
||||||
// 验证码模板id 自行处理 (查数据库或写死均可)
|
|
||||||
String templateId = "";
|
|
||||||
Map<String, String> map = new HashMap<>(1);
|
|
||||||
map.put("code", code);
|
|
||||||
SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class);
|
|
||||||
SmsResult result = smsTemplate.send(phonenumber, templateId, map);
|
|
||||||
if (!result.isSuccess()) {
|
|
||||||
log.error("验证码短信发送异常 => {}", result);
|
|
||||||
return R.fail(result.getMessage());
|
|
||||||
}
|
|
||||||
return R.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 邮箱验证码
|
|
||||||
*
|
|
||||||
* @param emailRequest 用户邮箱
|
|
||||||
*/
|
|
||||||
//@PostMapping("/resource/email/code")
|
|
||||||
@PostMapping("/resource/email/code")
|
|
||||||
public R<Void> emailCode(@RequestBody @Valid EmailRequest emailRequest) {
|
|
||||||
if (!mailProperties.getEnabled()) {
|
|
||||||
return R.fail("当前系统没有开启邮箱功能!");
|
|
||||||
}
|
|
||||||
String key = GlobalConstants.CAPTCHA_CODE_KEY + emailRequest.getUsername();
|
|
||||||
String code = RandomUtil.randomNumbers(4);
|
|
||||||
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
|
|
||||||
try {
|
|
||||||
MailUtils.sendText(emailRequest.getUsername(), "【熊猫助手】登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。");
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("验证码短信发送异常 => {}", e.getMessage());
|
|
||||||
return R.fail(e.getMessage());
|
|
||||||
}
|
|
||||||
return R.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成验证码
|
|
||||||
*/
|
|
||||||
@GetMapping("/code")
|
|
||||||
public R<CaptchaVo> getCode() {
|
|
||||||
CaptchaVo captchaVo = new CaptchaVo();
|
|
||||||
boolean captchaEnabled = captchaProperties.getEnable();
|
|
||||||
if (!captchaEnabled) {
|
|
||||||
captchaVo.setCaptchaEnabled(false);
|
|
||||||
return R.ok(captchaVo);
|
|
||||||
}
|
|
||||||
// 保存验证码信息
|
|
||||||
String uuid = IdUtil.simpleUUID();
|
|
||||||
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid;
|
|
||||||
// 生成验证码
|
|
||||||
CaptchaType captchaType = captchaProperties.getType();
|
|
||||||
boolean isMath = CaptchaType.MATH == captchaType;
|
|
||||||
Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
|
|
||||||
CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
|
|
||||||
AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
|
|
||||||
captcha.setGenerator(codeGenerator);
|
|
||||||
captcha.createCode();
|
|
||||||
String code = captcha.getCode();
|
|
||||||
if (isMath) {
|
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
|
||||||
Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
|
|
||||||
code = exp.getValue(String.class);
|
|
||||||
}
|
|
||||||
RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
|
|
||||||
captchaVo.setUuid(uuid);
|
|
||||||
captchaVo.setImg(captcha.getImageBase64());
|
|
||||||
return R.ok(captchaVo);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
package com.xmzs.controller;
|
|
||||||
|
|
||||||
|
|
||||||
import com.xmzs.common.chat.domain.request.ChatRequest;
|
|
||||||
import com.xmzs.common.chat.domain.request.Dall3Request;
|
|
||||||
import com.xmzs.common.chat.entity.Tts.TextToSpeech;
|
|
||||||
import com.xmzs.common.chat.entity.files.UploadFileResponse;
|
|
||||||
import com.xmzs.common.chat.entity.images.Item;
|
|
||||||
import com.xmzs.common.chat.entity.whisper.WhisperResponse;
|
|
||||||
import com.xmzs.common.core.domain.R;
|
|
||||||
import com.xmzs.common.core.domain.model.LoginUser;
|
|
||||||
import com.xmzs.common.core.exception.base.BaseException;
|
|
||||||
import com.xmzs.common.mybatis.core.page.PageQuery;
|
|
||||||
import com.xmzs.common.mybatis.core.page.TableDataInfo;
|
|
||||||
import com.xmzs.common.satoken.utils.LoginHelper;
|
|
||||||
import com.xmzs.system.domain.bo.ChatMessageBo;
|
|
||||||
import com.xmzs.system.domain.vo.ChatMessageVo;
|
|
||||||
import com.xmzs.system.service.IChatMessageService;
|
|
||||||
import com.xmzs.system.service.ISseService;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 描述:
|
|
||||||
*
|
|
||||||
* @author https:www.unfbx.com
|
|
||||||
* @date 2023-03-01
|
|
||||||
*/
|
|
||||||
@Controller
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ChatController {
|
|
||||||
|
|
||||||
private final ISseService ISseService;
|
|
||||||
|
|
||||||
private final IChatMessageService chatMessageService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 聊天接口
|
|
||||||
*/
|
|
||||||
@PostMapping("/chat")
|
|
||||||
@ResponseBody
|
|
||||||
public SseEmitter sseChat(@RequestBody @Valid ChatRequest chatRequest, HttpServletResponse response) {
|
|
||||||
return ISseService.sseChat(chatRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传文件
|
|
||||||
*/
|
|
||||||
@PostMapping("/v1/upload")
|
|
||||||
@ResponseBody
|
|
||||||
public UploadFileResponse upload(@RequestPart("file") MultipartFile file) {
|
|
||||||
return ISseService.upload(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 语音转文本
|
|
||||||
*
|
|
||||||
* @param file
|
|
||||||
*/
|
|
||||||
@PostMapping("/audio")
|
|
||||||
@ResponseBody
|
|
||||||
public WhisperResponse audio(@RequestParam("file") MultipartFile file) {
|
|
||||||
WhisperResponse whisperResponse = ISseService.speechToTextTranscriptionsV2(file);
|
|
||||||
return whisperResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文本转语音
|
|
||||||
*
|
|
||||||
* @param textToSpeech
|
|
||||||
*/
|
|
||||||
@PostMapping("/speech")
|
|
||||||
@ResponseBody
|
|
||||||
public ResponseEntity<Resource> speech(@RequestBody TextToSpeech textToSpeech) {
|
|
||||||
return ISseService.textToSpeed(textToSpeech);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("/dall3")
|
|
||||||
@ResponseBody
|
|
||||||
public R<List<Item>> dall3(@RequestBody @Valid Dall3Request request) {
|
|
||||||
return R.ok(ISseService.dall3(request));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 聊天记录
|
|
||||||
*/
|
|
||||||
@PostMapping("/chatList")
|
|
||||||
@ResponseBody
|
|
||||||
public R<TableDataInfo<ChatMessageVo>> list(@RequestBody @Valid ChatMessageBo chatRequest, @RequestBody PageQuery pageQuery) {
|
|
||||||
// 默认查询当前登录用户消息记录
|
|
||||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
|
||||||
if (loginUser == null) {
|
|
||||||
throw new BaseException("用户未登录!");
|
|
||||||
}
|
|
||||||
chatRequest.setUserId(loginUser.getUserId());
|
|
||||||
TableDataInfo<ChatMessageVo> chatMessageVoTableDataInfo = chatMessageService.queryPageList(chatRequest, pageQuery);
|
|
||||||
return R.ok(chatMessageVoTableDataInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package com.xmzs.controller;
|
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaIgnore;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 首页
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@SaIgnore
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Controller
|
|
||||||
public class IndexController {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 访问首页,提示语
|
|
||||||
*/
|
|
||||||
@GetMapping("/")
|
|
||||||
public String index() {
|
|
||||||
return "index.html";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
package com.xmzs.controller;
|
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
|
||||||
import cn.hutool.extra.qrcode.QrCodeUtil;
|
|
||||||
import com.xmzs.common.config.PayConfig;
|
|
||||||
import com.xmzs.common.core.domain.R;
|
|
||||||
import com.xmzs.common.core.domain.model.LoginUser;
|
|
||||||
import com.xmzs.common.core.exception.base.BaseException;
|
|
||||||
import com.xmzs.common.core.utils.StringUtils;
|
|
||||||
import com.xmzs.common.oss.core.OssClient;
|
|
||||||
import com.xmzs.common.oss.entity.UploadResult;
|
|
||||||
import com.xmzs.common.oss.factory.OssFactory;
|
|
||||||
import com.xmzs.common.response.PayResponse;
|
|
||||||
import com.xmzs.common.satoken.utils.LoginHelper;
|
|
||||||
import com.xmzs.common.service.PayService;
|
|
||||||
import com.xmzs.common.utils.MD5Util;
|
|
||||||
import com.xmzs.system.domain.bo.PaymentOrdersBo;
|
|
||||||
import com.xmzs.system.domain.bo.SysUserBo;
|
|
||||||
import com.xmzs.system.domain.request.OrderRequest;
|
|
||||||
import com.xmzs.system.domain.vo.PaymentOrdersVo;
|
|
||||||
import com.xmzs.system.domain.vo.SysUserVo;
|
|
||||||
import com.xmzs.system.service.IPaymentOrdersService;
|
|
||||||
import com.xmzs.system.service.ISysUserService;
|
|
||||||
import com.xmzs.system.util.OrderNumberGenerator;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/pay")
|
|
||||||
@Slf4j
|
|
||||||
public class PayController {
|
|
||||||
|
|
||||||
private final PayService payService;
|
|
||||||
|
|
||||||
private final ISysUserService userService;
|
|
||||||
|
|
||||||
private final IPaymentOrdersService paymentOrdersService;
|
|
||||||
|
|
||||||
private final PayConfig payConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取支付二维码
|
|
||||||
*
|
|
||||||
* @Date 2023/7/3
|
|
||||||
* @return void
|
|
||||||
**/
|
|
||||||
@PostMapping("/payUrl")
|
|
||||||
public R<PaymentOrdersVo> payUrl(@RequestBody OrderRequest orderRequest) {
|
|
||||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
|
||||||
// 创建订单
|
|
||||||
PaymentOrdersBo paymentOrders = new PaymentOrdersBo();
|
|
||||||
paymentOrders.setOrderName(orderRequest.getName());
|
|
||||||
paymentOrders.setAmount(new BigDecimal(orderRequest.getMoney()));
|
|
||||||
String orderNo = OrderNumberGenerator.generate();
|
|
||||||
paymentOrders.setOrderNo(orderNo);
|
|
||||||
paymentOrders.setUserId(loginUser.getUserId());
|
|
||||||
// TODO 支付状态默认待支付 - 添加枚举
|
|
||||||
paymentOrders.setPaymentStatus("1");
|
|
||||||
paymentOrdersService.insertByBo(paymentOrders);
|
|
||||||
String payUrl = payService.getPayUrl(orderNo, orderRequest.getName(), Double.parseDouble(orderRequest.getMoney()), "192.168.1.6");
|
|
||||||
byte[] bytes = QrCodeUtil.generatePng(payUrl, 300, 300);
|
|
||||||
OssClient storage = OssFactory.instance();
|
|
||||||
UploadResult upload=storage.upload(bytes, storage.getPath("qrCode",".png"), "image/png");
|
|
||||||
PaymentOrdersVo paymentOrdersVo = new PaymentOrdersVo();
|
|
||||||
BeanUtil.copyProperties(paymentOrders,paymentOrdersVo);
|
|
||||||
paymentOrdersVo.setUrl(upload.getUrl());
|
|
||||||
return R.ok(paymentOrdersVo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 跳转通知地址
|
|
||||||
*
|
|
||||||
* @Date 2023/7/3
|
|
||||||
* @param
|
|
||||||
* @return void
|
|
||||||
**/
|
|
||||||
@PostMapping("/notifyUrl")
|
|
||||||
public void notifyUrl() {
|
|
||||||
log.info("notifyUrl===========");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取订单信息
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@PostMapping("/orderInfo")
|
|
||||||
public R<PaymentOrdersVo> orderInfo(@RequestBody OrderRequest orderRequest) {
|
|
||||||
if(StringUtils.isEmpty(orderRequest.getOrderNo())){
|
|
||||||
throw new BaseException("订单号不能为空!");
|
|
||||||
}
|
|
||||||
PaymentOrdersBo paymentOrdersBo = new PaymentOrdersBo();
|
|
||||||
paymentOrdersBo.setOrderNo(orderRequest.getOrderNo());
|
|
||||||
List<PaymentOrdersVo> paymentOrdersList = paymentOrdersService.queryList(paymentOrdersBo);
|
|
||||||
if (CollectionUtil.isEmpty(paymentOrdersList)){
|
|
||||||
throw new BaseException("订单不存在!");
|
|
||||||
}
|
|
||||||
PaymentOrdersVo paymentOrdersVo = paymentOrdersList.get(0);
|
|
||||||
return R.ok(paymentOrdersVo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 跳转通知地址
|
|
||||||
*
|
|
||||||
* @Date 2023/7/3
|
|
||||||
* @param payResponse
|
|
||||||
* @return void
|
|
||||||
**/
|
|
||||||
@GetMapping("/returnUrl")
|
|
||||||
public String returnUrl(PayResponse payResponse) {
|
|
||||||
// 校验签名
|
|
||||||
String mdString = "money=" + payResponse.getMoney() + "&name=" + payResponse.getName() +
|
|
||||||
"&out_trade_no=" + payResponse.getOut_trade_no() + "&pid=" + payConfig.getPid() +
|
|
||||||
"&trade_no=" + payResponse.getTrade_no() + "&trade_status=" + payResponse.getTrade_status() +
|
|
||||||
"&type=" + payResponse.getType() + payConfig.getKey();
|
|
||||||
String sign = MD5Util.GetMD5Code(mdString);
|
|
||||||
if(!sign.equals(payResponse.getSign())){
|
|
||||||
throw new BaseException("校验签名失败!");
|
|
||||||
}
|
|
||||||
double money = Double.parseDouble(payResponse.getMoney());
|
|
||||||
log.info("支付订单号{}",payResponse);
|
|
||||||
PaymentOrdersBo paymentOrdersBo = new PaymentOrdersBo();
|
|
||||||
paymentOrdersBo.setOrderNo(payResponse.getOut_trade_no());
|
|
||||||
List<PaymentOrdersVo> paymentOrdersList = paymentOrdersService.queryList(paymentOrdersBo);
|
|
||||||
if (CollectionUtil.isEmpty(paymentOrdersList)){
|
|
||||||
throw new BaseException("订单不存在!");
|
|
||||||
}
|
|
||||||
// 订单状态修改为已支付
|
|
||||||
PaymentOrdersVo paymentOrdersVo = paymentOrdersList.get(0);
|
|
||||||
paymentOrdersVo.setPaymentStatus("2");
|
|
||||||
paymentOrdersVo.setPaymentMethod(payResponse.getType());
|
|
||||||
BeanUtil.copyProperties(paymentOrdersVo,paymentOrdersBo);
|
|
||||||
paymentOrdersService.updateByBo(paymentOrdersBo);
|
|
||||||
|
|
||||||
SysUserVo sysUserVo = userService.selectUserById(paymentOrdersVo.getUserId());
|
|
||||||
sysUserVo.setUserBalance(sysUserVo.getUserBalance()+money);
|
|
||||||
SysUserBo sysUserBo = new SysUserBo();
|
|
||||||
BeanUtil.copyProperties(sysUserVo,sysUserBo);
|
|
||||||
// 设置为付费用户
|
|
||||||
sysUserBo.setUserGrade("1");
|
|
||||||
userService.updateUser(sysUserBo);
|
|
||||||
return "success";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package com.xmzs.controller;
|
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaIgnore;
|
|
||||||
import com.xmzs.common.core.domain.R;
|
|
||||||
import com.xmzs.common.wechat.Wechat;
|
|
||||||
import com.xmzs.common.wechat.controller.LoginController;
|
|
||||||
import com.xmzs.common.wechat.core.MsgCenter;
|
|
||||||
import com.xmzs.system.cofing.KeywordConfig;
|
|
||||||
import com.xmzs.system.cofing.WechatConfig;
|
|
||||||
import com.xmzs.system.handler.WechatMessageHandler;
|
|
||||||
import com.xmzs.system.service.ISseService;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 个人微信扩展控制器
|
|
||||||
*
|
|
||||||
* @author WangLe
|
|
||||||
*/
|
|
||||||
@SaIgnore
|
|
||||||
@Slf4j
|
|
||||||
@Validated
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RestController
|
|
||||||
public class WeChatController {
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private Wechat wechatBot;
|
|
||||||
|
|
||||||
private final WechatConfig wechatConfig;
|
|
||||||
|
|
||||||
private final ISseService sseService;
|
|
||||||
|
|
||||||
private final KeywordConfig keywordConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取微信登录二维码
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@GetMapping("/getQr")
|
|
||||||
public R<String> getQr() {
|
|
||||||
//微信
|
|
||||||
if (wechatConfig.getEnable()){
|
|
||||||
log.info("正在登录微信,请按提示操作:");
|
|
||||||
wechatBot = new Wechat(new WechatMessageHandler(sseService, keywordConfig));
|
|
||||||
// 登陆
|
|
||||||
LoginController login = new LoginController();
|
|
||||||
String qrCode = login.login_1();
|
|
||||||
new Thread(login::login_2).start();
|
|
||||||
wechatBot.start();
|
|
||||||
return R.ok(qrCode);
|
|
||||||
}else {
|
|
||||||
return R.fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -10,12 +10,12 @@ import org.springframework.boot.context.metrics.buffering.BufferingApplicationSt
|
|||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class RuoYiApplication {
|
public class RuoYiAIApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication application = new SpringApplication(RuoYiApplication.class);
|
SpringApplication application = new SpringApplication(RuoYiAIApplication.class);
|
||||||
application.setApplicationStartup(new BufferingApplicationStartup(2048));
|
application.setApplicationStartup(new BufferingApplicationStartup(2048));
|
||||||
application.run(args);
|
application.run(args);
|
||||||
System.out.println("(♥◠‿◠)ノ゙ RuoYiAi启动成功 ლ(´ڡ`ლ)゙");
|
System.out.println("(♥◠‿◠)ノ゙ RuoYiAI启动成功 ლ(´ڡ`ლ)゙");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,11 +8,11 @@ import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
public class RuoYiServletInitializer extends SpringBootServletInitializer {
|
public class RuoYiAIServletInitializer extends SpringBootServletInitializer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||||
return application.sources(RuoYiApplication.class);
|
return application.sources(RuoYiAIApplication.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
package org.ruoyi.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.theokanning.openai.completion.chat.ChatMessageRole;
|
||||||
|
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.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.ArrayList;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 知识库对话
|
||||||
|
*/
|
||||||
|
@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);
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
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()){
|
||||||
|
throw new SecurityException("请先去登录!");
|
||||||
|
}
|
||||||
|
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/{kid}")
|
||||||
|
public R<Void> removeAttach(@NotEmpty(message = "主键不能为空")
|
||||||
|
@PathVariable String kid) {
|
||||||
|
attachService.removeKnowledgeAttach(kid);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package org.ruoyi.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import io.github.ollama4j.OllamaAPI;
|
||||||
|
import io.github.ollama4j.exceptions.OllamaBaseException;
|
||||||
|
import io.github.ollama4j.models.chat.OllamaChatMessageRole;
|
||||||
|
import io.github.ollama4j.models.chat.OllamaChatRequestBuilder;
|
||||||
|
import io.github.ollama4j.models.chat.OllamaChatRequestModel;
|
||||||
|
import io.github.ollama4j.models.chat.OllamaChatResult;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 描述:Ollama API调用
|
||||||
|
*
|
||||||
|
* @author ageerle@163.com
|
||||||
|
* date 2024/11/6
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class OllamaController {
|
||||||
|
|
||||||
|
|
||||||
|
@RequestMapping(value = "/qianwen-ai2")
|
||||||
|
private void ollama2(@RequestParam(value = "msg") String msg) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws OllamaBaseException, IOException, InterruptedException {
|
||||||
|
|
||||||
|
String host = "http://localhost:11434/";
|
||||||
|
|
||||||
|
OllamaAPI ollama = new OllamaAPI(host);
|
||||||
|
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance("qwen2.5:7b");
|
||||||
|
// 设置超时时间
|
||||||
|
ollama.setRequestTimeoutSeconds(100);
|
||||||
|
// create first user question
|
||||||
|
String text = "";
|
||||||
|
|
||||||
|
String json = "{\"instruction\": \"解答以下数学问题。\",\"input\": \"计算 2 + 3 的结果。\",\"output\": \"2 + 3 = 5\"}";
|
||||||
|
|
||||||
|
OllamaChatRequestModel requestModel = builder.withMessage
|
||||||
|
(OllamaChatMessageRole.USER, "###文本:"+text+"###,理解文本内容,并且将文本内容转换为:"+json+"输出JSON格式,不要包含其他无关内容,内部使用无需脱敏")
|
||||||
|
.withGetJsonResponse()
|
||||||
|
.withStreaming()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// start conversation with model
|
||||||
|
OllamaChatResult chatResult = ollama.chat(requestModel);
|
||||||
|
|
||||||
|
System.out.println("First answer: " + chatResult.getResponse());
|
||||||
|
|
||||||
|
// create next userQuestion
|
||||||
|
// requestModel = builder.withMessages(chatResult.getChatHistory()).withMessage(OllamaChatMessageRole.USER, "And what is the second largest city?").build();
|
||||||
|
|
||||||
|
// "continue" conversation with model
|
||||||
|
// chatResult = ollamaAPI.chat(requestModel);
|
||||||
|
|
||||||
|
//System.out.println("Second answer: " + chatResult.getResponse());
|
||||||
|
|
||||||
|
// 历史记录
|
||||||
|
//System.out.println("Chat History: " + chatResult.getChatHistory());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,28 +8,6 @@ spring.boot.admin.client:
|
|||||||
username: ruoyi
|
username: ruoyi
|
||||||
password: 123456
|
password: 123456
|
||||||
|
|
||||||
--- # xxl-job 配置
|
|
||||||
xxl.job:
|
|
||||||
# 执行器开关
|
|
||||||
enabled: false
|
|
||||||
# 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。
|
|
||||||
admin-addresses: http://localhost:9100/xxl-job-admin
|
|
||||||
# 执行器通讯TOKEN:非空时启用
|
|
||||||
access-token: xxl-job
|
|
||||||
executor:
|
|
||||||
# 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册
|
|
||||||
appname: xxl-job-executor
|
|
||||||
# 执行器端口号 执行器从9101开始往后写
|
|
||||||
port: 9101
|
|
||||||
# 执行器注册:默认IP:PORT
|
|
||||||
address:
|
|
||||||
# 执行器IP:默认自动获取IP
|
|
||||||
ip:
|
|
||||||
# 执行器运行日志文件存储磁盘路径
|
|
||||||
logpath: ./logs/xxl-job
|
|
||||||
# 执行器日志文件保存天数:大于3生效
|
|
||||||
logretentiondays: 30
|
|
||||||
|
|
||||||
--- # 数据源配置
|
--- # 数据源配置
|
||||||
spring:
|
spring:
|
||||||
datasource:
|
datasource:
|
||||||
@@ -49,7 +27,8 @@ spring:
|
|||||||
driverClassName: com.mysql.cj.jdbc.Driver
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
url: jdbc:mysql://43.139.70.230:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
url: jdbc:mysql://43.139.70.230:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||||
username: ruoyi-ai
|
username: ruoyi-ai
|
||||||
password: TZ7yaGtSRWeeBaBJ
|
password: eCaZ278N62k6fhYj
|
||||||
|
|
||||||
hikari:
|
hikari:
|
||||||
# 最大连接池数量
|
# 最大连接池数量
|
||||||
maxPoolSize: 20
|
maxPoolSize: 20
|
||||||
@@ -78,7 +57,7 @@ spring.data:
|
|||||||
# 数据库索引
|
# 数据库索引
|
||||||
database: 0
|
database: 0
|
||||||
# 密码(如没有密码请注释掉)
|
# 密码(如没有密码请注释掉)
|
||||||
#password:
|
# password: 123456
|
||||||
# 连接超时时间
|
# 连接超时时间
|
||||||
timeout: 10S
|
timeout: 10S
|
||||||
# 是否开启ssl
|
# 是否开启ssl
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ ruoyi:
|
|||||||
# 版本
|
# 版本
|
||||||
version: ${revision}
|
version: ${revision}
|
||||||
# 版权年份
|
# 版权年份
|
||||||
copyrightYear: 2023
|
copyrightYear: 2025
|
||||||
# 实例演示开关
|
# 实例演示开关
|
||||||
demoEnabled: true
|
demoEnabled: true
|
||||||
# 获取ip地址开关
|
# 获取ip地址开关
|
||||||
@@ -294,7 +294,7 @@ management:
|
|||||||
websocket:
|
websocket:
|
||||||
enabled: true
|
enabled: true
|
||||||
# 路径
|
# 路径
|
||||||
path: ''
|
path: '/resource/websocket'
|
||||||
# 设置访问源地址
|
# 设置访问源地址
|
||||||
allowedOrigins: '*'
|
allowedOrigins: '*'
|
||||||
|
|
||||||
@@ -308,28 +308,34 @@ wx:
|
|||||||
aesKey: #微信小程序消息服务器配置的EncodingAESKey
|
aesKey: #微信小程序消息服务器配置的EncodingAESKey
|
||||||
msgDataFormat: JSON
|
msgDataFormat: JSON
|
||||||
|
|
||||||
|
# 企业微信应用
|
||||||
|
wechat:
|
||||||
|
# 是否使用微信 true/false
|
||||||
|
enable: true
|
||||||
|
# 生成的登录二维码路径 默认与项目同级
|
||||||
|
qrPath: "./"
|
||||||
|
# 企业微信应用
|
||||||
|
cp:
|
||||||
|
corpId:
|
||||||
|
appConfigs:
|
||||||
|
- agentId:
|
||||||
|
secret: ''
|
||||||
|
token: ''
|
||||||
|
aesKey: ''
|
||||||
|
|
||||||
# 知识库配置
|
# 知识库配置
|
||||||
chain:
|
chain:
|
||||||
split:
|
split:
|
||||||
chunk:
|
chunk:
|
||||||
endspliter: "<STOP>"
|
endspliter: "<STOP>"
|
||||||
# 分块文本大小
|
# 分块文本大小
|
||||||
size: 500
|
size: 200
|
||||||
overlay: 0
|
overlay: 30
|
||||||
qaspliter: "######"
|
qaspliter: "###"
|
||||||
# 知识库中检索的条数
|
# 知识库中检索的条数
|
||||||
limits: 5
|
limits: 5
|
||||||
vectorization:
|
|
||||||
type: openai
|
|
||||||
openai:
|
|
||||||
model: 'text-embedding-3-small'
|
|
||||||
baidu:
|
|
||||||
model: bge-large-zh
|
|
||||||
zhipu:
|
|
||||||
model: embedding-2
|
|
||||||
# 智普API KEY
|
|
||||||
token: xx
|
|
||||||
vector:
|
vector:
|
||||||
|
model: 'text-embedding-3-small'
|
||||||
store:
|
store:
|
||||||
type: weaviate
|
type: weaviate
|
||||||
weaviate:
|
weaviate:
|
||||||
@@ -341,38 +347,4 @@ chain:
|
|||||||
port: 19530
|
port: 19530
|
||||||
dimension: 1536
|
dimension: 1536
|
||||||
collection: LocalKnowledge
|
collection: LocalKnowledge
|
||||||
llm:
|
|
||||||
openai:
|
|
||||||
token: sk-xx
|
|
||||||
model: gpt-4-1106-preview
|
|
||||||
chatglm:
|
|
||||||
baseurl: http://127.0.0.1:8000/
|
|
||||||
model: chatglm2-6b
|
|
||||||
baidu:
|
|
||||||
appKey: xx
|
|
||||||
secretKey: xx
|
|
||||||
model: ernie_bot
|
|
||||||
zhipu:
|
|
||||||
model: glm-4
|
|
||||||
audio:
|
|
||||||
type: openai
|
|
||||||
text:
|
|
||||||
type: openai
|
|
||||||
function:
|
|
||||||
type: baidu
|
|
||||||
vision:
|
|
||||||
type: openai
|
|
||||||
image:
|
|
||||||
type: openai
|
|
||||||
|
|
||||||
upload:
|
|
||||||
path: /data/upload
|
|
||||||
|
|
||||||
proxy:
|
|
||||||
socket:
|
|
||||||
host: 127.0.0.1
|
|
||||||
port: 7890
|
|
||||||
|
|
||||||
resource:
|
|
||||||
domain: http://127.0.0.1:${server.port}/resources
|
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 469 KiB |
@@ -1,8 +0,0 @@
|
|||||||
@font-face {font-family: "Engravers' Old English BT";
|
|
||||||
src: url("https://unpkg.com/dmego-home-page@latest/assets/fonts/d571b52b60b5617399ce8eab62bf3eb3.eot"); /* IE9*/
|
|
||||||
src: url("https://unpkg.com/dmego-home-page@latest/assets/fonts/d571b52b60b5617399ce8eab62bf3eb3.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
|
|
||||||
url("https://unpkg.com/dmego-home-page@latest/assets/fonts/d571b52b60b5617399ce8eab62bf3eb3.woff2") format("woff2"), /* chrome firefox */
|
|
||||||
url("https://unpkg.com/dmego-home-page@latest/assets/fonts/d571b52b60b5617399ce8eab62bf3eb3.woff") format("woff"), /* chrome firefox */
|
|
||||||
url("https://unpkg.com/dmego-home-page@latest/assets/fonts/d571b52b60b5617399ce8eab62bf3eb3.ttf") format("truetype"), /* chrome firefox opera Safari, Android, iOS 4.2+*/
|
|
||||||
url("https://unpkg.com/dmego-home-page@latest/assets/fonts/d571b52b60b5617399ce8eab62bf3eb3.svg#Engravers' Old English BT") format("svg"); /* iOS 4.1- */
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 251 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 115 KiB |
@@ -1,38 +0,0 @@
|
|||||||
const https = require('https')
|
|
||||||
const fs = require('fs')
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
hostname: 'www.bing.com',
|
|
||||||
port: 443,
|
|
||||||
path: '/HPImageArchive.aspx?format=js&idx=0&n=8',
|
|
||||||
method: 'GET'
|
|
||||||
}
|
|
||||||
|
|
||||||
const req = https.request(options, bing_res => {
|
|
||||||
let bing_body = [], bing_data = {};
|
|
||||||
bing_res.on('data', (chunk) => {
|
|
||||||
bing_body.push(chunk);
|
|
||||||
});
|
|
||||||
bing_res.on('end', () => {
|
|
||||||
bing_body = Buffer.concat(bing_body);
|
|
||||||
bing_data = JSON.parse(bing_body.toString());
|
|
||||||
let img_array = bing_data.images;
|
|
||||||
let img_url = [];
|
|
||||||
img_array.forEach(img => {
|
|
||||||
img_url.push(img.url);
|
|
||||||
});
|
|
||||||
var jsonpStr = "getBingImages(" + JSON.stringify(img_url) + ")";
|
|
||||||
fs.writeFile('./assets/json/images.json', jsonpStr, (err) => {
|
|
||||||
if (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
console.log("JSON data is saved: " + jsonpStr);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
req.on('error', error => {
|
|
||||||
console.error(error)
|
|
||||||
})
|
|
||||||
|
|
||||||
req.end()
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
var iUp = (function () {
|
|
||||||
var time = 0,
|
|
||||||
duration = 150,
|
|
||||||
clean = function () {
|
|
||||||
time = 0;
|
|
||||||
},
|
|
||||||
up = function (element) {
|
|
||||||
setTimeout(function () {
|
|
||||||
element.classList.add("up");
|
|
||||||
}, time);
|
|
||||||
time += duration;
|
|
||||||
},
|
|
||||||
down = function (element) {
|
|
||||||
element.classList.remove("up");
|
|
||||||
},
|
|
||||||
toggle = function (element) {
|
|
||||||
setTimeout(function () {
|
|
||||||
element.classList.toggle("up");
|
|
||||||
}, time);
|
|
||||||
time += duration;
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
clean: clean,
|
|
||||||
up: up,
|
|
||||||
down: down,
|
|
||||||
toggle: toggle
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
||||||
function getBingImages(imgUrls) {
|
|
||||||
/**
|
|
||||||
* 获取Bing壁纸
|
|
||||||
* 先使用 GitHub Action 每天获取 Bing 壁纸 URL 并更新 images.json 文件
|
|
||||||
* 然后读取 images.json 文件中的数据
|
|
||||||
*/
|
|
||||||
var indexName = "bing-image-index";
|
|
||||||
var index = sessionStorage.getItem(indexName);
|
|
||||||
var panel = document.querySelector('#panel');
|
|
||||||
if (isNaN(index) || index == 7) index = 0;
|
|
||||||
else index++;
|
|
||||||
var imgUrl = imgUrls[index];
|
|
||||||
var url = "https://www.cn.bing.com" + imgUrl;
|
|
||||||
panel.style.background = "url('" + url + "') center center no-repeat #666";
|
|
||||||
panel.style.backgroundSize = "cover";
|
|
||||||
sessionStorage.setItem(indexName, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
function decryptEmail(encoded) {
|
|
||||||
var address = atob(encoded);
|
|
||||||
window.location.href = "mailto:" + address;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
// 获取一言数据
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
xhr.onreadystatechange = function () {
|
|
||||||
if (this.readyState == 4 && this.status == 200) {
|
|
||||||
var res = JSON.parse(this.responseText);
|
|
||||||
document.getElementById('description').innerHTML = res.hitokoto + "<br/> -「<strong>" + res.from + "</strong>」";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.open("GET", "https://v1.hitokoto.cn", true);
|
|
||||||
xhr.send();
|
|
||||||
|
|
||||||
var iUpElements = document.querySelectorAll(".iUp");
|
|
||||||
iUpElements.forEach(function (element) {
|
|
||||||
iUp.up(element);
|
|
||||||
});
|
|
||||||
|
|
||||||
var avatarElement = document.querySelector(".js-avatar");
|
|
||||||
avatarElement.addEventListener('load', function () {
|
|
||||||
avatarElement.classList.add("show");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var btnMobileMenu = document.querySelector('.btn-mobile-menu__icon');
|
|
||||||
var navigationWrapper = document.querySelector('.navigation-wrapper');
|
|
||||||
|
|
||||||
btnMobileMenu.addEventListener('click', function () {
|
|
||||||
if (navigationWrapper.style.display == "block") {
|
|
||||||
navigationWrapper.addEventListener('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {
|
|
||||||
navigationWrapper.classList.toggle('visible');
|
|
||||||
navigationWrapper.classList.toggle('animated');
|
|
||||||
navigationWrapper.classList.toggle('bounceOutUp');
|
|
||||||
navigationWrapper.removeEventListener('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', arguments.callee);
|
|
||||||
});
|
|
||||||
navigationWrapper.classList.toggle('animated');
|
|
||||||
navigationWrapper.classList.toggle('bounceInDown');
|
|
||||||
navigationWrapper.classList.toggle('animated');
|
|
||||||
navigationWrapper.classList.toggle('bounceOutUp');
|
|
||||||
} else {
|
|
||||||
navigationWrapper.classList.toggle('visible');
|
|
||||||
navigationWrapper.classList.toggle('animated');
|
|
||||||
navigationWrapper.classList.toggle('bounceInDown');
|
|
||||||
}
|
|
||||||
btnMobileMenu.classList.toggle('social');
|
|
||||||
btnMobileMenu.classList.toggle('iconfont');
|
|
||||||
btnMobileMenu.classList.toggle('icon-list');
|
|
||||||
btnMobileMenu.classList.toggle('social');
|
|
||||||
btnMobileMenu.classList.toggle('iconfont');
|
|
||||||
btnMobileMenu.classList.toggle('icon-angleup');
|
|
||||||
btnMobileMenu.classList.toggle('animated');
|
|
||||||
btnMobileMenu.classList.toggle('fadeIn');
|
|
||||||
});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
getBingImages(["/th?id=OHR.TheRoachesPeakDistrict_EN-US9733115206_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp","/th?id=OHR.SanMiguelAllende_EN-US9621237021_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp","/th?id=OHR.JediMonastery_EN-US9398447907_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp","/th?id=OHR.SonoranSpring_EN-US9207877073_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp","/th?id=OHR.CratersOfTheMoon_EN-US6516727783_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp","/th?id=OHR.HawaiianLei_EN-US6290126556_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp","/th?id=OHR.CheetahRain_EN-US6179670004_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp","/th?id=OHR.TulouFujian_EN-US6009679228_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp"])
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1714852590465" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1571" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M263.1 844.8h497.7c22.9 0 41.5 18.6 41.5 41.5s-18.6 41.5-41.5 41.5H263.1c-22.9 0-41.5-18.6-41.5-41.5s18.6-41.5 41.5-41.5zM138.7 98.2h746.6c22.9 0 41.5 18.6 41.5 41.5v580.7c0 11-4.4 21.6-12.1 29.3-7.8 7.8-18.3 12.1-29.3 12.1H138.7c-11 0-21.6-4.4-29.3-12.1-7.8-7.8-12.1-18.3-12.1-29.3V139.7c-0.1-22.9 18.5-41.5 41.4-41.5z m331.8 478.9v60.4h83v-60.3c8.5-5.8 17.4-12.8 26.5-20.5l49.4 49.4 58.7-58.7-49.5-49.4c7.7-9 14.6-18 20.5-26.5h60.3v-83h-60.3c-6.4-9.1-13.3-18-20.5-26.5l49.4-49.4-58.7-58.6-49.4 49.4c-8.5-7.3-17.3-14.1-26.5-20.5v-60.3h-83V283c-8.5 5.8-17.4 12.8-26.5 20.5l-49.4-49.4-58.5 58.6 49.4 49.4c-7.2 8.5-14.1 17.3-20.5 26.5h-60.3v83h60.3c5.8 8.5 12.8 17.4 20.5 26.5L336 547.3l58.7 58.7 49.4-49.4c9.1 7.7 18 14.6 26.4 20.5z m0 0" p-id="1572"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,45 +0,0 @@
|
|||||||
package com.xmzs.test;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.DisplayName;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 断言单元测试案例
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@DisplayName("断言单元测试案例")
|
|
||||||
public class AssertUnitTest {
|
|
||||||
|
|
||||||
@DisplayName("测试 assertEquals 方法")
|
|
||||||
@Test
|
|
||||||
public void testAssertEquals() {
|
|
||||||
Assertions.assertEquals("666", new String("666"));
|
|
||||||
Assertions.assertNotEquals("666", new String("666"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("测试 assertSame 方法")
|
|
||||||
@Test
|
|
||||||
public void testAssertSame() {
|
|
||||||
Object obj = new Object();
|
|
||||||
Object obj1 = obj;
|
|
||||||
Assertions.assertSame(obj, obj1);
|
|
||||||
Assertions.assertNotSame(obj, obj1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("测试 assertTrue 方法")
|
|
||||||
@Test
|
|
||||||
public void testAssertTrue() {
|
|
||||||
Assertions.assertTrue(true);
|
|
||||||
Assertions.assertFalse(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("测试 assertNull 方法")
|
|
||||||
@Test
|
|
||||||
public void testAssertNull() {
|
|
||||||
Assertions.assertNull(null);
|
|
||||||
Assertions.assertNotNull(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
package com.xmzs.test;
|
|
||||||
|
|
||||||
import com.xmzs.common.core.config.RuoYiConfig;
|
|
||||||
import org.junit.jupiter.api.*;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 单元测试案例
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@SpringBootTest // 此注解只能在 springboot 主包下使用 需包含 main 方法与 yml 配置文件
|
|
||||||
@DisplayName("单元测试案例")
|
|
||||||
public class DemoUnitTest {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RuoYiConfig ruoYiConfig;
|
|
||||||
|
|
||||||
@DisplayName("测试 @SpringBootTest @Test @DisplayName 注解")
|
|
||||||
@Test
|
|
||||||
public void testTest() {
|
|
||||||
System.out.println(ruoYiConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Disabled
|
|
||||||
@DisplayName("测试 @Disabled 注解")
|
|
||||||
@Test
|
|
||||||
public void testDisabled() {
|
|
||||||
System.out.println(ruoYiConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Timeout(value = 2L, unit = TimeUnit.SECONDS)
|
|
||||||
@DisplayName("测试 @Timeout 注解")
|
|
||||||
@Test
|
|
||||||
public void testTimeout() throws InterruptedException {
|
|
||||||
Thread.sleep(3000);
|
|
||||||
System.out.println(ruoYiConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@DisplayName("测试 @RepeatedTest 注解")
|
|
||||||
@RepeatedTest(3)
|
|
||||||
public void testRepeatedTest() {
|
|
||||||
System.out.println(666);
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
public static void testBeforeAll() {
|
|
||||||
System.out.println("@BeforeAll ==================");
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void testBeforeEach() {
|
|
||||||
System.out.println("@BeforeEach ==================");
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void testAfterEach() {
|
|
||||||
System.out.println("@AfterEach ==================");
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void testAfterAll() {
|
|
||||||
System.out.println("@AfterAll ==================");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package com.xmzs.test;
|
|
||||||
|
|
||||||
import com.xmzs.common.core.enums.UserType;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.DisplayName;
|
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
|
||||||
import org.junit.jupiter.params.provider.EnumSource;
|
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
|
||||||
import org.junit.jupiter.params.provider.NullSource;
|
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 带参数单元测试案例
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@DisplayName("带参数单元测试案例")
|
|
||||||
public class ParamUnitTest {
|
|
||||||
|
|
||||||
@DisplayName("测试 @ValueSource 注解")
|
|
||||||
@ParameterizedTest
|
|
||||||
@ValueSource(strings = {"t1", "t2", "t3"})
|
|
||||||
public void testValueSource(String str) {
|
|
||||||
System.out.println(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("测试 @NullSource 注解")
|
|
||||||
@ParameterizedTest
|
|
||||||
@NullSource
|
|
||||||
public void testNullSource(String str) {
|
|
||||||
System.out.println(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("测试 @EnumSource 注解")
|
|
||||||
@ParameterizedTest
|
|
||||||
@EnumSource(UserType.class)
|
|
||||||
public void testEnumSource(UserType type) {
|
|
||||||
System.out.println(type.getUserType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("测试 @MethodSource 注解")
|
|
||||||
@ParameterizedTest
|
|
||||||
@MethodSource("getParam")
|
|
||||||
public void testMethodSource(String str) {
|
|
||||||
System.out.println(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Stream<String> getParam() {
|
|
||||||
List<String> list = new ArrayList<>();
|
|
||||||
list.add("t1");
|
|
||||||
list.add("t2");
|
|
||||||
list.add("t3");
|
|
||||||
return list.stream();
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void testBeforeEach() {
|
|
||||||
System.out.println("@BeforeEach ==================");
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void testAfterEach() {
|
|
||||||
System.out.println("@AfterEach ==================");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package com.xmzs.test;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.*;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标签单元测试案例
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@SpringBootTest
|
|
||||||
@DisplayName("标签单元测试案例")
|
|
||||||
public class TagUnitTest {
|
|
||||||
|
|
||||||
@Tag("dev")
|
|
||||||
@DisplayName("测试 @Tag dev")
|
|
||||||
@Test
|
|
||||||
public void testTagDev() {
|
|
||||||
System.out.println("dev");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Tag("prod")
|
|
||||||
@DisplayName("测试 @Tag prod")
|
|
||||||
@Test
|
|
||||||
public void testTagProd() {
|
|
||||||
System.out.println("prod");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Tag("local")
|
|
||||||
@DisplayName("测试 @Tag local")
|
|
||||||
@Test
|
|
||||||
public void testTagLocal() {
|
|
||||||
System.out.println("local");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Tag("exclude")
|
|
||||||
@DisplayName("测试 @Tag exclude")
|
|
||||||
@Test
|
|
||||||
public void testTagExclude() {
|
|
||||||
System.out.println("exclude");
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void testBeforeEach() {
|
|
||||||
System.out.println("@BeforeEach ==================");
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void testAfterEach() {
|
|
||||||
System.out.println("@AfterEach ==================");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
<module>ruoyi-common-tenant</module>
|
<module>ruoyi-common-tenant</module>
|
||||||
<module>ruoyi-common-chat</module>
|
<module>ruoyi-common-chat</module>
|
||||||
<module>ruoyi-common-pay</module>
|
<module>ruoyi-common-pay</module>
|
||||||
|
<module>ruoyi-common-wechat</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<artifactId>ruoyi-common</artifactId>
|
<artifactId>ruoyi-common</artifactId>
|
||||||
|
|||||||
@@ -159,6 +159,13 @@
|
|||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 微信模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ruoyi</groupId>
|
||||||
|
<artifactId>ruoyi-common-wechat</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- AI绘画 -->
|
<!-- AI绘画 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.ruoyi</groupId>
|
<groupId>org.ruoyi</groupId>
|
||||||
|
|||||||
@@ -26,6 +26,18 @@
|
|||||||
<artifactId>ruoyi-common-core</artifactId>
|
<artifactId>ruoyi-common-core</artifactId>
|
||||||
</dependency>
|
</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>
|
<dependency>
|
||||||
<groupId>org.ruoyi</groupId>
|
<groupId>org.ruoyi</groupId>
|
||||||
@@ -42,11 +54,6 @@
|
|||||||
<artifactId>ruoyi-common-satoken</artifactId>
|
<artifactId>ruoyi-common-satoken</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.squareup.retrofit2</groupId>
|
<groupId>com.squareup.retrofit2</groupId>
|
||||||
<artifactId>retrofit</artifactId>
|
<artifactId>retrofit</artifactId>
|
||||||
@@ -74,5 +81,16 @@
|
|||||||
<artifactId>hutool-all</artifactId>
|
<artifactId>hutool-all</artifactId>
|
||||||
<version>5.8.12</version>
|
<version>5.8.12</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
package com.xmzs.common.chat.config;
|
|
||||||
|
|
||||||
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.logging.HttpLoggingInterceptor;
|
|
||||||
import com.xmzs.common.chat.openai.OpenAiStreamClient;
|
|
||||||
import com.xmzs.common.chat.openai.function.KeyRandomStrategy;
|
|
||||||
import com.xmzs.common.chat.openai.interceptor.OpenAILogger;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* chat配置类
|
|
||||||
*
|
|
||||||
* @author: wangle
|
|
||||||
* @date: 2023/5/16
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class ChatConfig {
|
|
||||||
@Value("${chat.apiKey}")
|
|
||||||
private List<String> apiKey;
|
|
||||||
@Value("${chat.apiHost}")
|
|
||||||
private String apiHost;
|
|
||||||
|
|
||||||
@Bean(name = "openAiStreamClient")
|
|
||||||
public OpenAiStreamClient openAiStreamClient() {
|
|
||||||
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new OpenAILogger());
|
|
||||||
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
|
|
||||||
OkHttpClient okHttpClient = new OkHttpClient
|
|
||||||
.Builder()
|
|
||||||
.addInterceptor(httpLoggingInterceptor)
|
|
||||||
.connectTimeout(30, TimeUnit.SECONDS)
|
|
||||||
.writeTimeout(600, TimeUnit.SECONDS)
|
|
||||||
.readTimeout(600, TimeUnit.SECONDS)
|
|
||||||
.build();
|
|
||||||
return OpenAiStreamClient
|
|
||||||
.builder()
|
|
||||||
.apiHost(apiHost)
|
|
||||||
.apiKey(apiKey)
|
|
||||||
//自定义key使用策略 默认随机策略
|
|
||||||
.keyStrategy(new KeyRandomStrategy())
|
|
||||||
.okHttpClient(okHttpClient)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package com.xmzs.common.chat.config;
|
|
||||||
|
|
||||||
import cn.hutool.cache.CacheUtil;
|
|
||||||
import cn.hutool.cache.impl.TimedCache;
|
|
||||||
import cn.hutool.core.date.DateUnit;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 描述:
|
|
||||||
*
|
|
||||||
* @author https:www.unfbx.com
|
|
||||||
* @date 2023-03-10
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class LocalCache {
|
|
||||||
/**
|
|
||||||
* 缓存时长
|
|
||||||
*/
|
|
||||||
public static final long TIMEOUT = 30 * DateUnit.MINUTE.getMillis();
|
|
||||||
/**
|
|
||||||
* 清理间隔
|
|
||||||
*/
|
|
||||||
private static final long CLEAN_TIMEOUT = 30 * DateUnit.MINUTE.getMillis();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 缓存对象
|
|
||||||
*/
|
|
||||||
public static final TimedCache<String, Object> CACHE = CacheUtil.newTimedCache(TIMEOUT);
|
|
||||||
|
|
||||||
|
|
||||||
static {
|
|
||||||
//启动定时任务
|
|
||||||
CACHE.schedulePrune(CLEAN_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package com.xmzs.common.chat.config;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.xmzs.common.chat.config.properties.WebSocketProperties;
|
|
||||||
import com.xmzs.common.chat.handler.PlusWebSocketHandler;
|
|
||||||
import com.xmzs.common.chat.interceptor.PlusWebSocketInterceptor;
|
|
||||||
import com.xmzs.common.chat.listener.WebSocketTopicListener;
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
|
|
||||||
import org.springframework.web.socket.WebSocketHandler;
|
|
||||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
|
||||||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
|
||||||
import org.springframework.web.socket.server.HandshakeInterceptor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WebSocket 配置
|
|
||||||
*
|
|
||||||
* @author zendwang
|
|
||||||
*/
|
|
||||||
@AutoConfiguration
|
|
||||||
@ConditionalOnProperty(value = "websocket.enabled", havingValue = "true")
|
|
||||||
@EnableConfigurationProperties(WebSocketProperties.class)
|
|
||||||
@EnableWebSocket
|
|
||||||
public class WebSocketConfig {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public WebSocketConfigurer webSocketConfigurer(HandshakeInterceptor handshakeInterceptor,
|
|
||||||
WebSocketHandler webSocketHandler,
|
|
||||||
WebSocketProperties webSocketProperties) {
|
|
||||||
if (StrUtil.isBlank(webSocketProperties.getPath())) {
|
|
||||||
webSocketProperties.setPath("/websocket");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StrUtil.isBlank(webSocketProperties.getAllowedOrigins())) {
|
|
||||||
webSocketProperties.setAllowedOrigins("*");
|
|
||||||
}
|
|
||||||
|
|
||||||
return registry -> registry
|
|
||||||
.addHandler(webSocketHandler, webSocketProperties.getPath())
|
|
||||||
.addInterceptors(handshakeInterceptor)
|
|
||||||
.setAllowedOrigins(webSocketProperties.getAllowedOrigins());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public HandshakeInterceptor handshakeInterceptor() {
|
|
||||||
return new PlusWebSocketInterceptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public WebSocketHandler webSocketHandler() {
|
|
||||||
return new PlusWebSocketHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public WebSocketTopicListener topicListener() {
|
|
||||||
return new WebSocketTopicListener();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.xmzs.common.chat.config.properties;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WebSocket 配置项
|
|
||||||
*
|
|
||||||
* @author zendwang
|
|
||||||
*/
|
|
||||||
@ConfigurationProperties("websocket")
|
|
||||||
@Data
|
|
||||||
public class WebSocketProperties {
|
|
||||||
|
|
||||||
private Boolean enabled;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 路径
|
|
||||||
*/
|
|
||||||
private String path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置访问源地址
|
|
||||||
*/
|
|
||||||
private String allowedOrigins;
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package com.xmzs.common.chat.constant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 描述:
|
|
||||||
*
|
|
||||||
* @author https:www.unfbx.com
|
|
||||||
* @since 2023-03-06
|
|
||||||
*/
|
|
||||||
public class OpenAIConst {
|
|
||||||
|
|
||||||
public final static String OPENAI_HOST = "https://api.openai.com/";
|
|
||||||
|
|
||||||
public final static int SUCCEED_CODE = 200;
|
|
||||||
|
|
||||||
/** GPT3扣除费用 */
|
|
||||||
public final static double GPT3_COST = 0.05;
|
|
||||||
|
|
||||||
/** GPT4扣除费用 */
|
|
||||||
public final static double GPT4_COST = 0.2;
|
|
||||||
|
|
||||||
/** DALL普通绘图扣除费用 */
|
|
||||||
public final static double DALL3_COST = 0.3;
|
|
||||||
|
|
||||||
/** DALL高清绘图扣除费用 */
|
|
||||||
public final static double DALL3_HD_COST = 0.5;
|
|
||||||
|
|
||||||
/** MJ操作类型1(变化、变焦、文生图、图生图、局部重绘、混图)扣除费用 */
|
|
||||||
public final static double MJ_COST_TYPE1 = 0.3;
|
|
||||||
|
|
||||||
/** MJ操作类型2(换脸、放大、图生文、prompt分析)扣除费用 */
|
|
||||||
public final static double MJ_COST_TYPE2 = 0.1;
|
|
||||||
|
|
||||||
/** MJ操作类型3(查询任务进度、获取seed)扣除费用 */
|
|
||||||
public final static double MJ_COST_TYPE3 = 0.0;
|
|
||||||
|
|
||||||
/** 默认账户余额 */
|
|
||||||
public final static double USER_BALANCE = 5;
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package com.xmzs.common.chat.constant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* websocket的常量配置
|
|
||||||
*
|
|
||||||
* @author zendwang
|
|
||||||
*/
|
|
||||||
public interface WebSocketConstants {
|
|
||||||
/**
|
|
||||||
* websocketSession中的参数的key
|
|
||||||
*/
|
|
||||||
String LOGIN_USER_KEY = "loginUser";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 订阅的频道
|
|
||||||
*/
|
|
||||||
String WEB_SOCKET_TOPIC = "global:websocket";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 前端心跳检查的命令
|
|
||||||
*/
|
|
||||||
String PING = "ping";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 服务端心跳恢复的字符串
|
|
||||||
*/
|
|
||||||
String PONG = "pong";
|
|
||||||
}
|
|
||||||