初始提交
This commit is contained in:
parent
054883c6d3
commit
d698fa8039
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
* text=auto eol=lf
|
||||
*.{bat,cmd} text eol=crlf
|
48
.gitignore
vendored
Normal file
48
.gitignore
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
######################################################################
|
||||
# Build Tools
|
||||
|
||||
.gradle
|
||||
/build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
######################################################################
|
||||
# IDE
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### JRebel ###
|
||||
rebel.xml
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/*
|
||||
nbbuild/
|
||||
nbdist/
|
||||
.nb-gradle/
|
||||
|
||||
######################################################################
|
||||
# Others
|
||||
*.log
|
||||
*.xml.versionsBackup
|
||||
*.swp
|
||||
|
||||
!*/build/*.java
|
||||
!*/build/*.html
|
||||
!*/build/*.xml
|
||||
|
||||
.flattened-pom.xml
|
20
LICENSE
Normal file
20
LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 ruoyi-ai
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
240
README.md
240
README.md
@ -1 +1,239 @@
|
||||
AI标书系统2.0-后端
|
||||
|
||||
|
||||
# RuoYi AI
|
||||
|
||||
|
||||
|
||||
<!-- PROJECT SHIELDS -->
|
||||
|
||||
[![Contributors][contributors-shield]][contributors-url]
|
||||
[![Forks][forks-shield]][forks-url]
|
||||
[![Stargazers][stars-shield]][stars-url]
|
||||
[![Issues][issues-shield]][issues-url]
|
||||
[![MIT License][license-shield]][license-url]
|
||||
|
||||
|
||||
<!-- PROJECT LOGO -->
|
||||
<br />
|
||||
|
||||
|
||||
<img style="text-align: center;" src="image/00.png" alt="Logo" width="150" height="150">
|
||||
|
||||
<h3 style="text-align: center;">快速搭建属于自己的 AI 助手平台</h3>
|
||||
|
||||
<p style="text-align: center;">
|
||||
全新升级,开箱即用,简单高效
|
||||
<br />
|
||||
<a href="https://doc.pandarobot.chat"><strong>探索本项目的文档 »</strong></a>
|
||||
<br />
|
||||
<br />
|
||||
<a href="https://web.pandarobot.chat">项目预览</a>
|
||||
·
|
||||
<a href="https://github.com/ageerle/ruoyi-ai/issues">报告Bug</a>
|
||||
·
|
||||
<a href="https://github.com/ageerle/ruoyi-ai/issues">提出新特性</a>
|
||||
</p>
|
||||
|
||||
## 目录
|
||||
|
||||
- [源码地址](#源码地址)
|
||||
- [特色功能](#特色功能)
|
||||
- [项目演示](#项目演示)
|
||||
- [后台管理](#后台管理)
|
||||
- [用户端](#用户端)
|
||||
- [小程序端](#小程序端)
|
||||
- [开发前的配置要求](#开发前的配置要求)
|
||||
- [文件目录说明](#文件目录说明)
|
||||
- [使用到的框架](#使用到的框架)
|
||||
- [贡献者](#贡献者)
|
||||
- [如何参与开源项目](#如何参与开源项目)
|
||||
- [版本控制](#版本控制)
|
||||
- [作者](#作者)
|
||||
- [鸣谢](#鸣谢)
|
||||
|
||||
### 源码地址
|
||||
- 项目文档: https://doc.pandarobot.chat
|
||||
- 前端-后台管理: https://github.com/ageerle/ruoyi-admin
|
||||
- 前端-用户端: https://github.com/ageerle/ruoyi-web
|
||||
- 小程序端: https://github.com/ageerle/ruoyi-uniapp
|
||||
- 演示地址: https://web.pandarobot.chat
|
||||
- 后台管理: https://admin.pandarobot.chat
|
||||
- 用户名: admin 密码:admin123
|
||||
-
|
||||
### gitcode源码地址
|
||||
- https://gitcode.com/ageerle/ruoyi-ai
|
||||
- https://gitcode.com/ageerle/ruoyi-web
|
||||
- https://gitcode.com/ageerle/ruoyi-admin
|
||||
- https://gitcode.com/ageerle/ruoyi-uniapp
|
||||
|
||||
### 特色功能
|
||||
1. 全套开源系统:提供完整的前端应用、后台管理以及小程序应用,基于MIT协议,开箱即用。
|
||||
2. 本地RAG方案:集成Milvus/Weaviate向量库、本地向量化模型与Ollama,实现本地化RAG
|
||||
3. 丰富插件功能:支持联网、SQL查询插件及Text2API插件,扩展系统能力与应用场景。
|
||||
4. 内置SSE、websocket等网络协议,支持对接多种大语言模型,同时还集成了MidJourney和DALLE AI绘画功能
|
||||
5. 强大的多媒体功能:支持AI翻译、PPT制作、语音克隆和翻唱等
|
||||
6. 扩展功能:支持将大模型接入个人或企业微信
|
||||
7. 支付功能:支持易支付、微信支付等多种支付方式
|
||||
|
||||
### 项目演示
|
||||
|
||||
#### 后台管理
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: center;">
|
||||
<img src="image/02.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
<img src="image/03.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
<img src="image/04.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
<img src="image/05.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
</div>
|
||||
|
||||
|
||||
#### 用户端
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: center;">
|
||||
<img src="image/08.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
<img src="image/09.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
<img src="image/10.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
<img src="image/11.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
</div>
|
||||
|
||||
#### 小程序端
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: flex-start;">
|
||||
<img src="image/06.png" alt="drawing" style="width: 320px; height: 600px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
<img src="image/07.png" alt="drawing" style="width: 320px; height: 600px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
</div>
|
||||
|
||||
### 开发前的配置要求
|
||||
|
||||
1. jdk 17
|
||||
2. mysql 5.7、8.0
|
||||
3. redis 版本必须 >= 5.X
|
||||
4. maven 3.8+
|
||||
5. nodejs 20+ & pnpm
|
||||
|
||||
### 文件目录说明
|
||||
RuoYi-AI
|
||||
|
||||
```
|
||||
├─ ruoyi-admin // 管理模块
|
||||
│ └─ RuoYiApplication // 启动类
|
||||
│ └─ RuoYiServletInitializer // 容器部署初始化类
|
||||
│ └─ resources // 资源文件
|
||||
│ └─ i18n/messages.properties // 国际化配置文件
|
||||
│ └─ application.yml // 框架总配置文件
|
||||
│ └─ application-dev.yml // 开发环境配置文件
|
||||
│ └─ application-prod.yml // 生产环境配置文件
|
||||
│ └─ banner.txt // 框架启动图标
|
||||
│ └─ logback-plus.xml // 日志配置文件
|
||||
│ └─ ip2region.xdb // IP区域地址库
|
||||
├─ ruoyi-common // 通用模块
|
||||
│ └─ ruoyi-common-bom // common依赖包管理
|
||||
└─ ruoyi-common-chat // 聊天模块
|
||||
│ └─ ruoyi-common-core // 核心模块
|
||||
│ └─ ruoyi-common-doc // 系统接口模块
|
||||
│ └─ ruoyi-common-encrypt // 数据加解密模块
|
||||
│ └─ ruoyi-common-excel // excel模块
|
||||
│ └─ ruoyi-common-idempotent // 幂等功能模块
|
||||
│ └─ ruoyi-common-json // 序列化模块
|
||||
│ └─ ruoyi-common-log // 日志模块
|
||||
│ └─ ruoyi-common-mail // 邮件模块
|
||||
│ └─ ruoyi-common-mybatis // 数据库模块
|
||||
│ └─ ruoyi-common-oss // oss服务模块
|
||||
│ └─ ruoyi-common-pay // 支付模块
|
||||
│ └─ ruoyi-common-ratelimiter // 限流功能模块
|
||||
│ └─ ruoyi-common-redis // 缓存服务模块
|
||||
│ └─ ruoyi-common-satoken // satoken模块
|
||||
│ └─ ruoyi-common-security // 安全模块
|
||||
│ └─ ruoyi-common-sensitive // 脱敏模块
|
||||
│ └─ ruoyi-common-sms // 短信模块
|
||||
│ └─ ruoyi-common-tenant // 租户模块
|
||||
│ └─ ruoyi-common-translation // 通用翻译模块
|
||||
│ └─ ruoyi-common-web // web模块
|
||||
├─ ruoyi-modules // 模块组
|
||||
│ └─ ruoyi-demo // 演示模块
|
||||
│ └─ ruoyi-system // 业务模块
|
||||
├─ .run // 执行脚本文件
|
||||
├─ .editorconfig // 编辑器编码格式配置
|
||||
├─ LICENSE // 开源协议
|
||||
├─ pom.xml // 公共依赖
|
||||
├─ README.md // 框架说明文件
|
||||
|
||||
|
||||
```
|
||||
|
||||
### 版本控制
|
||||
|
||||
该项目使用Git进行版本管理。您可以在repository参看当前可用版本。
|
||||
|
||||
|
||||
|
||||
### 版权说明
|
||||
|
||||
该项目使用了MIT授权许可,详情请参阅 [LICENSE.txt](https://github.com/ageerle/ruoyi-ai/blob/main/LICENSE)
|
||||
|
||||
|
||||
### 作者寄语
|
||||
|
||||
最近,我们的项目意外地受到了广泛关注,甚至被许多人误以为是一个已经成熟且能够快速落地的项目。然而,事实并非如此。这个项目是我个人在业余时间进行的研究,主要目的是学习和探索。它是一个以人工智能(AI)为核心的平台,旨在帮助企业通过配置的方式快速构建AI应用。
|
||||
|
||||
#### 项目现状
|
||||
|
||||
目前,项目还处于早期阶段,距离成熟还有很长的路要走。由于个人精力有限,项目的发展速度受到了一定的限制。为了加快项目的进度,我真诚地希望更多人能够参与到项目中来。无论是经验丰富的开发者,还是刚刚入门的小白,我都热烈欢迎你们提交Pull Request(PR)。即使代码修改得很少,或者存在一些错误,都没有关系。我会认真审核每一位贡献者的代码,并和大家一起完善项目。
|
||||
|
||||
#### 开发计划
|
||||
|
||||
- 智能体管理
|
||||
|
||||
通过设置提示词、插件、知识库等,用户可以快速构建一个AI应用。这将极大地简化AI应用的开发流程,降低开发门槛,使更多企业能够轻松地利用AI技术。
|
||||
<div>
|
||||
<img src="image/13.png" alt="drawing" width="600px" height="300px"/>
|
||||
</div>
|
||||
|
||||
- 流程编排
|
||||
|
||||
通过流程编排功能,用户可以将不同的模型按照业务逻辑进行有序连接。这将解决单一模型能力不足的问题,充分发挥多个模型的协同作用,从而更好地满足企业的复杂业务需求。
|
||||
|
||||
- 感谢
|
||||
|
||||
最后,我要感谢RuoYi-Vue-Plus、chatgpt-java、chatgpt-web-midjourney-proxy等优秀框架。正是因为这些项目的开源和共享,我才能够在这个基础上进行开发,使我们的项目能够取得今天的成果。再次感谢这些项目及其背后的开发者们!
|
||||
|
||||
希望更多志同道合的朋友能够加入我们,共同推动这个项目的发展。让我们一起努力,将这个项目打造成一个真正成熟、实用的AI平台!
|
||||
|
||||
#### 如何参与开源项目
|
||||
|
||||
贡献使开源社区成为一个学习、激励和创造的绝佳场所。你所作的任何贡献都是**非常感谢**的。
|
||||
|
||||
1. Fork 这个项目
|
||||
2. 创建你的功能分支 (`git checkout -b feature/dev`)
|
||||
3. 提交你的更改 (`git commit -m 'Add some dev'`)
|
||||
4. 推送到分支 (`git push origin feature/dev`)
|
||||
5. 打开拉取请求
|
||||
6. pr请提交到GitHub上,会定时同步到gitee
|
||||
|
||||
#### 项目文档
|
||||
1. 项目文档基于vitepress构建
|
||||
2. 按照[如何参与开源项目](#如何参与开源项目)拉取 https://github.com/ageerle/ruoyi-doc
|
||||
3. 安装依赖:npm install
|
||||
4. 启动项目:npm run docs:dev
|
||||
5. 主页路径:docs/guide/introduction/index.md
|
||||
|
||||
### 鸣谢
|
||||
- [chatgpt-java](https://github.com/Grt1228/chatgpt-java)
|
||||
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||
- [chatgpt-web-midjourney-proxy](https://github.com/Dooy/chatgpt-web-midjourney-proxy)
|
||||
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin)
|
||||
- [Naive UI](https://www.naiveui.com)
|
||||
|
||||
<!-- links -->
|
||||
[your-project-path]:https://github.com/ageerle/ruoyi-ai
|
||||
[contributors-shield]: https://img.shields.io/github/contributors/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
[contributors-url]: https://github.com/ageerle/ruoyi-ai/graphs/contributors
|
||||
[forks-shield]: https://img.shields.io/github/forks/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
[forks-url]: https://github.com/ageerle/ruoyi-ai/network/members
|
||||
[stars-shield]: https://img.shields.io/github/stars/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
[stars-url]: https://github.com/ageerle/ruoyi-ai/stargazers
|
||||
[issues-shield]: https://img.shields.io/github/issues/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
[issues-url]: https://img.shields.io/github/issues/ageerle/ruoyi-ai.svg
|
||||
[license-shield]: https://img.shields.io/github/license/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
[license-url]: https://github.com/ageerle/ruoyi-ai/blob/master/LICENSE.txt
|
||||
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555
|
||||
|
||||
|
||||
|
||||
|
35
aibidding-admin/Dockerfile
Normal file
35
aibidding-admin/Dockerfile
Normal file
@ -0,0 +1,35 @@
|
||||
#基础镜像
|
||||
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 /aibidding/server/logs \
|
||||
/aibidding/server/temp \
|
||||
/aibidding/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=aibidding-server", \
|
||||
# "-javaagent:/aibidding/skywalking/agent/skywalking-agent.jar", \
|
||||
"-jar", "app.jar"]
|
||||
|
||||
|
129
aibidding-admin/pom.xml
Normal file
129
aibidding-admin/pom.xml
Normal file
@ -0,0 +1,129 @@
|
||||
<?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>aibidding-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>aibidding-common-doc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-fusion</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-knowledge</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-generator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- demo模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-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>
|
@ -0,0 +1,21 @@
|
||||
package org.aibidding;
|
||||
|
||||
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 RuoYiAIApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication application = new SpringApplication(RuoYiAIApplication.class);
|
||||
application.setApplicationStartup(new BufferingApplicationStartup(2048));
|
||||
application.run(args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ AIBidding2.0系统启动成功 ლ(´ڡ`ლ)゙");
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.aibidding;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
/**
|
||||
* web容器中进行部署
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public class RuoYiAIServletInitializer extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
return application.sources(RuoYiAIApplication.class);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
package org.aibidding.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.aibidding.common.core.constant.Constants;
|
||||
import org.aibidding.common.core.domain.R;
|
||||
import org.aibidding.common.core.domain.model.EmailLoginBody;
|
||||
import org.aibidding.common.core.domain.model.LoginBody;
|
||||
import org.aibidding.common.core.domain.model.RegisterBody;
|
||||
import org.aibidding.common.core.domain.model.SmsLoginBody;
|
||||
import org.aibidding.common.core.domain.model.VisitorLoginBody;
|
||||
import org.aibidding.common.core.utils.MapstructUtils;
|
||||
import org.aibidding.common.core.utils.StreamUtils;
|
||||
import org.aibidding.common.core.utils.StringUtils;
|
||||
import org.aibidding.common.satoken.utils.LoginHelper;
|
||||
import org.aibidding.common.tenant.helper.TenantHelper;
|
||||
import org.aibidding.system.domain.bo.SysTenantBo;
|
||||
import org.aibidding.system.domain.vo.LoginTenantVo;
|
||||
import org.aibidding.system.domain.vo.SysTenantVo;
|
||||
import org.aibidding.system.domain.vo.TenantListVo;
|
||||
import org.aibidding.system.service.ISysTenantService;
|
||||
|
||||
import org.aibidding.system.service.SysLoginService;
|
||||
import org.aibidding.system.service.SysRegisterService;
|
||||
import org.aibidding.system.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;
|
||||
|
||||
|
||||
@PostMapping("/xcxLogin")
|
||||
public R<LoginVo> login(@Validated @RequestBody String xcxCode) throws WxErrorException {
|
||||
|
||||
String openidFromCode = loginService.getOpenidFromCode((String) JSONUtil.parseObj(xcxCode).get("xcxCode"));
|
||||
LoginVo loginVo = loginService.mpLogin(openidFromCode);
|
||||
return R.ok(loginVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录方法
|
||||
*
|
||||
* @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 loginBody 登录信息
|
||||
* @return token信息
|
||||
*/
|
||||
@PostMapping("/visitorLogin")
|
||||
public R<LoginVo> visitorLogin(@RequestBody VisitorLoginBody loginBody) {
|
||||
LoginVo loginVo = new LoginVo();
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
public R<Void> logout() {
|
||||
loginService.logout();
|
||||
return R.ok("退出成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*/
|
||||
@PostMapping("/register")
|
||||
public R<Void> register(@Validated @RequestBody RegisterBody user, HttpServletRequest request) {
|
||||
String domainName = request.getServerName();
|
||||
user.setDomainName(domainName);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
package org.aibidding.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 org.aibidding.common.core.constant.Constants;
|
||||
import org.aibidding.common.core.constant.GlobalConstants;
|
||||
import org.aibidding.common.core.domain.R;
|
||||
import org.aibidding.common.core.exception.ServiceException;
|
||||
import org.aibidding.common.core.service.ConfigService;
|
||||
import org.aibidding.common.core.utils.SpringUtils;
|
||||
import org.aibidding.common.core.utils.StringUtils;
|
||||
import org.aibidding.common.core.utils.reflect.ReflectUtils;
|
||||
import org.aibidding.common.mail.utils.MailUtils;
|
||||
import org.aibidding.common.redis.utils.RedisUtils;
|
||||
import org.aibidding.common.sms.config.properties.SmsProperties;
|
||||
import org.aibidding.common.sms.core.SmsTemplate;
|
||||
import org.aibidding.common.sms.entity.SmsResult;
|
||||
import org.aibidding.common.web.config.properties.CaptchaProperties;
|
||||
import org.aibidding.common.web.enums.CaptchaType;
|
||||
import org.aibidding.system.domain.request.EmailRequest;
|
||||
import org.aibidding.system.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.*;
|
||||
|
||||
/**
|
||||
* 验证码操作处理
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@SaIgnore
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
public class CaptchaController {
|
||||
|
||||
private final CaptchaProperties captchaProperties;
|
||||
private final SmsProperties smsProperties;
|
||||
private final ConfigService configService;
|
||||
|
||||
/**
|
||||
* 短信验证码
|
||||
*
|
||||
* @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")
|
||||
public R<Void> emailCode(@RequestBody @Valid EmailRequest emailRequest) {
|
||||
String key = GlobalConstants.CAPTCHA_CODE_KEY + emailRequest.getUsername();
|
||||
String code = RandomUtil.randomNumbers(4);
|
||||
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
|
||||
// 检验邮箱后缀
|
||||
String suffix = configService.getConfigValue("mail", "suffix");
|
||||
String prompt = configService.getConfigValue("mail", "prompt");
|
||||
if(StringUtils.isNotEmpty(suffix)){
|
||||
// 动态的域名列表
|
||||
String[] invalidDomains = suffix.split(",");
|
||||
for (String domain : invalidDomains) {
|
||||
if (emailRequest.getUsername().endsWith(domain)) {
|
||||
throw new ServiceException(prompt);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 自定义邮箱模板
|
||||
String model = configService.getConfigValue("mail", "mailModel");
|
||||
String mailTitle = configService.getConfigValue("mail", "mailTitle");
|
||||
String replacedModel = model.replace("{code}", code);
|
||||
try {
|
||||
MailUtils.sendHtml(emailRequest.getUsername(), mailTitle, replacedModel);
|
||||
} catch (Exception e) {
|
||||
log.error("邮箱验证码发送异常 => {}", e.getMessage());
|
||||
return R.fail(e.getMessage());
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成验证码
|
||||
*/
|
||||
@GetMapping("/auth/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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.aibidding.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 首页
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@SaIgnore
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
public class IndexController {
|
||||
|
||||
/**
|
||||
* 访问首页,提示语
|
||||
*/
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "RuoYi-AI 启动成功";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,208 @@
|
||||
package org.aibidding.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.aibidding.common.chat.config.ChatConfig;
|
||||
import org.aibidding.common.chat.domain.request.ChatRequest;
|
||||
import org.aibidding.common.chat.entity.chat.ChatCompletion;
|
||||
import org.aibidding.common.chat.entity.chat.Message;
|
||||
import org.aibidding.common.chat.openai.OpenAiStreamClient;
|
||||
import org.aibidding.common.core.domain.R;
|
||||
import org.aibidding.common.core.validate.AddGroup;
|
||||
import org.aibidding.common.excel.utils.ExcelUtil;
|
||||
import org.aibidding.common.log.annotation.Log;
|
||||
import org.aibidding.common.log.enums.BusinessType;
|
||||
import org.aibidding.common.mybatis.core.page.PageQuery;
|
||||
import org.aibidding.common.mybatis.core.page.TableDataInfo;
|
||||
import org.aibidding.common.satoken.utils.LoginHelper;
|
||||
import org.aibidding.common.web.core.BaseController;
|
||||
import org.aibidding.knowledge.domain.bo.KnowledgeAttachBo;
|
||||
import org.aibidding.knowledge.domain.bo.KnowledgeFragmentBo;
|
||||
import org.aibidding.knowledge.domain.bo.KnowledgeInfoBo;
|
||||
import org.aibidding.knowledge.domain.req.KnowledgeInfoUploadRequest;
|
||||
import org.aibidding.knowledge.domain.vo.KnowledgeAttachVo;
|
||||
import org.aibidding.knowledge.domain.vo.KnowledgeFragmentVo;
|
||||
import org.aibidding.knowledge.domain.vo.KnowledgeInfoVo;
|
||||
import org.aibidding.knowledge.service.EmbeddingService;
|
||||
import org.aibidding.knowledge.service.IKnowledgeAttachService;
|
||||
import org.aibidding.knowledge.service.IKnowledgeFragmentService;
|
||||
import org.aibidding.knowledge.service.IKnowledgeInfoService;
|
||||
import org.aibidding.system.listener.SSEEventSourceListener;
|
||||
import org.aibidding.system.service.ISseService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.aibidding.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);
|
||||
}
|
||||
|
||||
}
|
99
aibidding-admin/src/main/resources/application-dev.yml
Normal file
99
aibidding-admin/src/main/resources/application-dev.yml
Normal file
@ -0,0 +1,99 @@
|
||||
--- # 监控中心配置
|
||||
spring.boot.admin.client:
|
||||
# 增加客户端开关
|
||||
enabled: false
|
||||
url: http://localhost:9090/admin
|
||||
instance:
|
||||
service-host-type: IP
|
||||
username: aibidding
|
||||
password: 123456
|
||||
|
||||
--- # 数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
|
||||
dynamic:
|
||||
# 性能分析插件(有性能损耗 不建议生产环境使用)
|
||||
p6spy: true
|
||||
# 设置默认的数据源或者数据源组,默认值即为 master
|
||||
primary: master
|
||||
# 严格模式 匹配不到数据源则报错
|
||||
strict: true
|
||||
datasource:
|
||||
# 主库数据源
|
||||
master:
|
||||
type: ${spring.datasource.type}
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://47.104.134.46:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
username: ry-vue
|
||||
password: hTMeGJdpfLrLCwWD
|
||||
|
||||
|
||||
hikari:
|
||||
# 最大连接池数量
|
||||
maxPoolSize: 20
|
||||
# 最小空闲线程数量
|
||||
minIdle: 10
|
||||
# 配置获取连接等待超时的时间
|
||||
connectionTimeout: 30000
|
||||
# 校验超时时间
|
||||
validationTimeout: 5000
|
||||
# 空闲连接存活最大时间,默认10分钟
|
||||
idleTimeout: 600000
|
||||
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
|
||||
maxLifetime: 1800000
|
||||
# 连接测试query(配置检测连接是否有效)
|
||||
connectionTestQuery: SELECT 1
|
||||
# 多久检查一次连接的活性
|
||||
keepaliveTime: 30000
|
||||
|
||||
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
|
||||
spring.data:
|
||||
redis:
|
||||
# 地址
|
||||
host: 127.0.0.1
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 0
|
||||
# 密码(如没有密码请注释掉)
|
||||
# password: 123456
|
||||
# 连接超时时间
|
||||
timeout: 10S
|
||||
# 是否开启ssl
|
||||
ssl: false
|
||||
|
||||
redisson:
|
||||
# redis key前缀
|
||||
keyPrefix:
|
||||
# 线程池数量
|
||||
threads: 4
|
||||
# Netty线程池数量
|
||||
nettyThreads: 8
|
||||
# 单节点配置
|
||||
singleServerConfig:
|
||||
# 客户端名称
|
||||
clientName: ${ruoyi.name}
|
||||
# 最小空闲连接数
|
||||
connectionMinimumIdleSize: 8
|
||||
# 连接池大小
|
||||
connectionPoolSize: 32
|
||||
# 连接空闲超时,单位:毫秒
|
||||
idleConnectionTimeout: 10000
|
||||
# 命令等待超时,单位:毫秒
|
||||
timeout: 3000
|
||||
# 发布和订阅连接池大小
|
||||
subscriptionConnectionPoolSize: 50
|
||||
|
||||
--- # sms 短信
|
||||
sms:
|
||||
enabled: false
|
||||
# 阿里云 dysmsapi.aliyuncs.com
|
||||
# 腾讯云 sms.tencentcloudapi.com
|
||||
endpoint: "dysmsapi.aliyuncs.com"
|
||||
accessKeyId: xxxxxxx
|
||||
accessKeySecret: xxxxxx
|
||||
signName: 测试
|
||||
# 腾讯专用
|
||||
sdkAppId:
|
174
aibidding-admin/src/main/resources/application-prod.yml
Normal file
174
aibidding-admin/src/main/resources/application-prod.yml
Normal file
@ -0,0 +1,174 @@
|
||||
--- # 临时文件存储位置 避免临时文件被系统清理报错
|
||||
spring.servlet.multipart.location: /ruoyi/server/temp
|
||||
|
||||
--- # 监控中心配置
|
||||
spring.boot.admin.client:
|
||||
# 增加客户端开关
|
||||
enabled: false
|
||||
url: http://localhost:9090/admin
|
||||
instance:
|
||||
service-host-type: IP
|
||||
username: aibidding
|
||||
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:
|
||||
datasource:
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
|
||||
dynamic:
|
||||
# 性能分析插件(有性能损耗 不建议生产环境使用)
|
||||
p6spy: false
|
||||
# 设置默认的数据源或者数据源组,默认值即为 master
|
||||
primary: master
|
||||
# 严格模式 匹配不到数据源则报错
|
||||
strict: true
|
||||
datasource:
|
||||
# 主库数据源
|
||||
master:
|
||||
type: ${spring.datasource.type}
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
|
||||
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
|
||||
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
username: root
|
||||
password: root
|
||||
# 从库数据源
|
||||
slave:
|
||||
lazy: true
|
||||
type: ${spring.datasource.type}
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
username:
|
||||
password:
|
||||
# oracle:
|
||||
# type: ${spring.datasource.type}
|
||||
# driverClassName: oracle.jdbc.OracleDriver
|
||||
# url: jdbc:oracle:thin:@//localhost:1521/XE
|
||||
# username: ROOT
|
||||
# password: root
|
||||
# hikari:
|
||||
# connectionTestQuery: SELECT 1 FROM DUAL
|
||||
# postgres:
|
||||
# type: ${spring.datasource.type}
|
||||
# driverClassName: org.postgresql.Driver
|
||||
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
|
||||
# username: root
|
||||
# password: root
|
||||
# sqlserver:
|
||||
# type: ${spring.datasource.type}
|
||||
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
|
||||
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
|
||||
# username: SA
|
||||
# password: root
|
||||
hikari:
|
||||
# 最大连接池数量
|
||||
maxPoolSize: 20
|
||||
# 最小空闲线程数量
|
||||
minIdle: 10
|
||||
# 配置获取连接等待超时的时间
|
||||
connectionTimeout: 30000
|
||||
# 校验超时时间
|
||||
validationTimeout: 5000
|
||||
# 空闲连接存活最大时间,默认10分钟
|
||||
idleTimeout: 600000
|
||||
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
|
||||
maxLifetime: 1800000
|
||||
# 连接测试query(配置检测连接是否有效)
|
||||
connectionTestQuery: SELECT 1
|
||||
# 多久检查一次连接的活性
|
||||
keepaliveTime: 30000
|
||||
|
||||
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
|
||||
spring.data:
|
||||
redis:
|
||||
# 地址
|
||||
host: localhost
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 0
|
||||
# 密码(如没有密码请注释掉)
|
||||
# password:
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
# 是否开启ssl
|
||||
ssl: false
|
||||
|
||||
redisson:
|
||||
# redis key前缀
|
||||
keyPrefix:
|
||||
# 线程池数量
|
||||
threads: 16
|
||||
# Netty线程池数量
|
||||
nettyThreads: 32
|
||||
# 单节点配置
|
||||
singleServerConfig:
|
||||
# 客户端名称
|
||||
clientName: ${ruoyi.name}
|
||||
# 最小空闲连接数
|
||||
connectionMinimumIdleSize: 32
|
||||
# 连接池大小
|
||||
connectionPoolSize: 64
|
||||
# 连接空闲超时,单位:毫秒
|
||||
idleConnectionTimeout: 10000
|
||||
# 命令等待超时,单位:毫秒
|
||||
timeout: 3000
|
||||
# 发布和订阅连接池大小
|
||||
subscriptionConnectionPoolSize: 50
|
||||
|
||||
--- # mail 邮件发送
|
||||
mail:
|
||||
enabled: false
|
||||
host: smtp.163.com
|
||||
port: 465
|
||||
# 是否需要用户名密码验证
|
||||
auth: true
|
||||
# 发送方,遵循RFC-822标准
|
||||
from: xxx@163.com
|
||||
# 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
|
||||
user: xxx@163.com
|
||||
# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
|
||||
pass: xxxxxxxxxx
|
||||
# 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
|
||||
starttlsEnable: true
|
||||
# 使用SSL安全连接
|
||||
sslEnable: true
|
||||
# SMTP超时时长,单位毫秒,缺省值不超时
|
||||
timeout: 0
|
||||
# Socket连接超时值,单位毫秒,缺省值不超时
|
||||
connectionTimeout: 0
|
||||
|
||||
--- # sms 短信
|
||||
sms:
|
||||
enabled: false
|
||||
# 阿里云 dysmsapi.aliyuncs.com
|
||||
# 腾讯云 sms.tencentcloudapi.com
|
||||
endpoint: "dysmsapi.aliyuncs.com"
|
||||
accessKeyId: xxxxxxx
|
||||
accessKeySecret: xxxxxx
|
||||
signName: 测试
|
||||
# 腾讯专用
|
||||
sdkAppId:
|
322
aibidding-admin/src/main/resources/application.yml
Normal file
322
aibidding-admin/src/main/resources/application.yml
Normal file
@ -0,0 +1,322 @@
|
||||
|
||||
# 项目相关配置
|
||||
ruoyi:
|
||||
# 名称
|
||||
name: "ruoyi"
|
||||
# 版本
|
||||
version: ${revision}
|
||||
# 版权年份
|
||||
copyrightYear: 2025
|
||||
# 实例演示开关
|
||||
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:
|
||||
org.ruoyi: @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: 50MB
|
||||
# 设置总上传的文件大小
|
||||
max-request-size: 200MB
|
||||
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:
|
||||
# 支付回调
|
||||
- /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: org.aibidding.**.mapper
|
||||
# 对应的 XML 文件位置
|
||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||
# 实体扫描,多个package用逗号或者分号分隔
|
||||
typeAliasesPackage: org.ruoyi.**.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: org.ruoyi.demo
|
||||
- group: 2.通用模块
|
||||
packages-to-scan: org.ruoyi.web
|
||||
- group: 3.系统模块
|
||||
packages-to-scan: org.ruoyi.system
|
||||
- group: 4.代码生成模块
|
||||
packages-to-scan: org.ruoyi.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: true
|
||||
# 路径
|
||||
path: '/resource/websocket'
|
||||
# 设置访问源地址
|
||||
allowedOrigins: '*'
|
||||
|
||||
# 微信小程序配置信息
|
||||
wx:
|
||||
miniapp:
|
||||
configs:
|
||||
- appid: # 你的appid
|
||||
secret: # 你的secret
|
||||
token: #微信小程序消息服务器配置的token
|
||||
aesKey: #微信小程序消息服务器配置的EncodingAESKey
|
||||
msgDataFormat: JSON
|
||||
|
||||
# 企业微信应用
|
||||
wechat:
|
||||
cp:
|
||||
corpId:
|
||||
appConfigs:
|
||||
- agentId:
|
||||
secret: ''
|
||||
token: ''
|
||||
aesKey: ''
|
||||
|
||||
|
||||
|
2
aibidding-admin/src/main/resources/banner.txt
Normal file
2
aibidding-admin/src/main/resources/banner.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Application Version: ${revision}
|
||||
Spring Boot Version: ${spring-boot.version}
|
54
aibidding-admin/src/main/resources/i18n/messages.properties
Normal file
54
aibidding-admin/src/main/resources/i18n/messages.properties
Normal file
@ -0,0 +1,54 @@
|
||||
#错误消息
|
||||
not.null=* 必须填写
|
||||
user.jcaptcha.error=验证码错误
|
||||
user.jcaptcha.expire=验证码已失效
|
||||
user.not.exists=对不起, 您的账号:{0} 不存在.
|
||||
user.password.not.match=用户不存在/密码错误
|
||||
user.password.retry.limit.count=密码输入错误{0}次
|
||||
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
|
||||
user.password.delete=对不起,您的账号:{0} 已被删除
|
||||
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
|
||||
role.blocked=角色已封禁,请联系管理员
|
||||
user.logout.success=退出成功
|
||||
length.not.valid=长度必须在{min}到{max}个字符之间
|
||||
user.username.not.blank=用户名不能为空
|
||||
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
|
||||
user.username.length.valid=账户长度必须在{min}到{max}个字符之间
|
||||
user.password.not.blank=用户密码不能为空
|
||||
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
|
||||
user.password.not.valid=* 5-50个字符
|
||||
user.email.not.valid=邮箱格式错误
|
||||
user.email.not.blank=邮箱不能为空
|
||||
user.phonenumber.not.blank=用户手机号不能为空
|
||||
user.mobile.phone.number.not.valid=手机号格式错误
|
||||
user.login.success=登录成功
|
||||
user.register.success=注册成功
|
||||
user.register.save.error=保存用户 {0} 失败,注册账号已存在
|
||||
user.register.error=注册失败,请联系系统管理人员
|
||||
user.notfound=请重新登录
|
||||
user.forcelogout=管理员强制退出,请重新登录
|
||||
user.unknown.error=未知错误,请重新登录
|
||||
##文件上传消息
|
||||
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
|
||||
upload.filename.exceed.length=上传的文件名最长{0}个字符
|
||||
##权限
|
||||
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
|
||||
repeat.submit.message=不允许重复提交,请稍候再试
|
||||
rate.limiter.message=访问过于频繁,请稍候再试
|
||||
sms.code.not.blank=短信验证码不能为空
|
||||
sms.code.retry.limit.count=短信验证码输入错误{0}次
|
||||
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟
|
||||
email.code.not.blank=邮箱验证码不能为空
|
||||
email.code.retry.limit.count=邮箱验证码输入错误{0}次
|
||||
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟
|
||||
xcx.code.not.blank=小程序code不能为空
|
||||
##租户
|
||||
tenant.number.not.blank=租户编号不能为空
|
||||
tenant.not.exists=对不起, 您的租户不存在,请联系管理员
|
||||
tenant.blocked=对不起,您的租户已禁用,请联系管理员
|
||||
tenant.expired=对不起,您的租户已过期,请联系管理员
|
@ -0,0 +1,54 @@
|
||||
#错误消息
|
||||
not.null=* Required fill in
|
||||
user.jcaptcha.error=Captcha error
|
||||
user.jcaptcha.expire=Captcha invalid
|
||||
user.not.exists=Sorry, your account: {0} does not exist
|
||||
user.password.not.match=User does not exist/Password error
|
||||
user.password.retry.limit.count=Password input error {0} times
|
||||
user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes
|
||||
user.password.delete=Sorry, your account:{0} has been deleted
|
||||
user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator
|
||||
role.blocked=Role disabled,please contact administrators
|
||||
user.logout.success=Exit successful
|
||||
length.not.valid=The length must be between {min} and {max} characters
|
||||
user.username.not.blank=Username cannot be blank
|
||||
user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number
|
||||
user.username.length.valid=Account length must be between {min} and {max} characters
|
||||
user.password.not.blank=Password cannot be empty
|
||||
user.password.length.valid=Password length must be between {min} and {max} characters
|
||||
user.password.not.valid=* 5-50 characters
|
||||
user.email.not.valid=Mailbox format error
|
||||
user.email.not.blank=Mailbox cannot be blank
|
||||
user.phonenumber.not.blank=Phone number cannot be blank
|
||||
user.mobile.phone.number.not.valid=Phone number format error
|
||||
user.login.success=Login successful
|
||||
user.register.success=Register successful
|
||||
user.register.save.error=Failed to save user {0}, The registered account already exists
|
||||
user.register.error=Register failed, please contact system administrator
|
||||
user.notfound=Please login again
|
||||
user.forcelogout=The administrator is forced to exit,please login again
|
||||
user.unknown.error=Unknown error, please login again
|
||||
##文件上传消息
|
||||
upload.exceed.maxSize=The uploaded file size exceeds the limit file size!<br/>the maximum allowed file size is:{0}MB!
|
||||
upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters
|
||||
##权限
|
||||
no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}]
|
||||
no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}]
|
||||
no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}]
|
||||
no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}]
|
||||
no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}]
|
||||
no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}]
|
||||
repeat.submit.message=Repeat submit is not allowed, please try again later
|
||||
rate.limiter.message=Visit too frequently, please try again later
|
||||
sms.code.not.blank=Sms code cannot be blank
|
||||
sms.code.retry.limit.count=Sms code input error {0} times
|
||||
sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes
|
||||
email.code.not.blank=Email code cannot be blank
|
||||
email.code.retry.limit.count=Email code input error {0} times
|
||||
email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes
|
||||
xcx.code.not.blank=Mini program code cannot be blank
|
||||
##租户
|
||||
tenant.number.not.blank=Tenant number cannot be blank
|
||||
tenant.not.exists=Sorry, your tenant does not exist. Please contact the administrator
|
||||
tenant.blocked=Sorry, your tenant is disabled. Please contact the administrator
|
||||
tenant.expired=Sorry, your tenant has expired. Please contact the administrator.
|
@ -0,0 +1,54 @@
|
||||
#错误消息
|
||||
not.null=* 必须填写
|
||||
user.jcaptcha.error=验证码错误
|
||||
user.jcaptcha.expire=验证码已失效
|
||||
user.not.exists=对不起, 您的账号:{0} 不存在.
|
||||
user.password.not.match=用户不存在/密码错误
|
||||
user.password.retry.limit.count=密码输入错误{0}次
|
||||
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
|
||||
user.password.delete=对不起,您的账号:{0} 已被删除
|
||||
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
|
||||
role.blocked=角色已封禁,请联系管理员
|
||||
user.logout.success=退出成功
|
||||
length.not.valid=长度必须在{min}到{max}个字符之间
|
||||
user.username.not.blank=用户名不能为空
|
||||
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
|
||||
user.username.length.valid=账户长度必须在{min}到{max}个字符之间
|
||||
user.password.not.blank=用户密码不能为空
|
||||
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
|
||||
user.password.not.valid=* 5-50个字符
|
||||
user.email.not.valid=邮箱格式错误
|
||||
user.email.not.blank=邮箱不能为空
|
||||
user.phonenumber.not.blank=用户手机号不能为空
|
||||
user.mobile.phone.number.not.valid=手机号格式错误
|
||||
user.login.success=登录成功
|
||||
user.register.success=注册成功
|
||||
user.register.save.error=保存用户 {0} 失败,注册账号已存在
|
||||
user.register.error=注册失败,请联系系统管理人员
|
||||
user.notfound=请重新登录
|
||||
user.forcelogout=管理员强制退出,请重新登录
|
||||
user.unknown.error=未知错误,请重新登录
|
||||
##文件上传消息
|
||||
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
|
||||
upload.filename.exceed.length=上传的文件名最长{0}个字符
|
||||
##权限
|
||||
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
|
||||
repeat.submit.message=不允许重复提交,请稍候再试
|
||||
rate.limiter.message=访问过于频繁,请稍候再试
|
||||
sms.code.not.blank=短信验证码不能为空
|
||||
sms.code.retry.limit.count=短信验证码输入错误{0}次
|
||||
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟
|
||||
email.code.not.blank=邮箱验证码不能为空
|
||||
email.code.retry.limit.count=邮箱验证码输入错误{0}次
|
||||
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟
|
||||
xcx.code.not.blank=小程序code不能为空
|
||||
##租户
|
||||
tenant.number.not.blank=租户编号不能为空
|
||||
tenant.not.exists=对不起, 您的租户不存在,请联系管理员
|
||||
tenant.blocked=对不起,您的租户已禁用,请联系管理员
|
||||
tenant.expired=对不起,您的租户已过期,请联系管理员
|
BIN
aibidding-admin/src/main/resources/ip2region.xdb
Normal file
BIN
aibidding-admin/src/main/resources/ip2region.xdb
Normal file
Binary file not shown.
129
aibidding-admin/src/main/resources/logback-plus.xml
Normal file
129
aibidding-admin/src/main/resources/logback-plus.xml
Normal file
@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<property name="log.path" value="./logs"/>
|
||||
<property name="console.log.pattern"
|
||||
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
|
||||
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${console.log.pattern}</pattern>
|
||||
<charset>utf-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-console.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-console.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大 1天 -->
|
||||
<maxHistory>1</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
<charset>utf-8</charset>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-info.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- info异步输出 -->
|
||||
<appender name="async_info" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
|
||||
<queueSize>512</queueSize>
|
||||
<!-- 添加附加的appender,最多只能添加一个 -->
|
||||
<appender-ref ref="file_info"/>
|
||||
</appender>
|
||||
|
||||
<!-- error异步输出 -->
|
||||
<appender name="async_error" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
|
||||
<queueSize>512</queueSize>
|
||||
<!-- 添加附加的appender,最多只能添加一个 -->
|
||||
<appender-ref ref="file_error"/>
|
||||
</appender>
|
||||
|
||||
<!-- 整合 skywalking 控制台输出 tid -->
|
||||
<!-- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">-->
|
||||
<!-- <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
|
||||
<!-- <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">-->
|
||||
<!-- <pattern>[%tid] ${console.log.pattern}</pattern>-->
|
||||
<!-- </layout>-->
|
||||
<!-- <charset>utf-8</charset>-->
|
||||
<!-- </encoder>-->
|
||||
<!-- </appender>-->
|
||||
|
||||
<!-- 整合 skywalking 推送采集日志 -->
|
||||
<!-- <appender name="sky_log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">-->
|
||||
<!-- <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
|
||||
<!-- <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">-->
|
||||
<!-- <pattern>[%tid] ${console.log.pattern}</pattern>-->
|
||||
<!-- </layout>-->
|
||||
<!-- <charset>utf-8</charset>-->
|
||||
<!-- </encoder>-->
|
||||
<!-- </appender>-->
|
||||
|
||||
<!--系统操作日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="console" />
|
||||
<appender-ref ref="async_info" />
|
||||
<appender-ref ref="async_error" />
|
||||
<appender-ref ref="file_console" />
|
||||
<!-- <appender-ref ref="sky_log"/>-->
|
||||
</root>
|
||||
|
||||
</configuration>
|
1
aibidding-admin/src/main/resources/spy.properties
Normal file
1
aibidding-admin/src/main/resources/spy.properties
Normal file
@ -0,0 +1 @@
|
||||
exclude=SELECT 1
|
187
aibidding-common/aibidding-common-bom/pom.xml
Normal file
187
aibidding-common/aibidding-common-bom/pom.xml
Normal file
@ -0,0 +1,187 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-bom</artifactId>
|
||||
<version>${revision}</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<description>
|
||||
ruoyi-common-bom common依赖项
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<revision>1.0.0</revision>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- 核心模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 接口模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-doc</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- excel -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-excel</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 幂等 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-idempotent</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 日志记录 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-log</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 邮件服务 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-mail</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库服务 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-mybatis</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- OSS -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-oss</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 限流 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-ratelimiter</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 缓存服务 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-redis</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- satoken -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-satoken</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 安全模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-security</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 短信模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-sms</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- web服务 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-web</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 翻译模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-translation</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 脱敏模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-sensitive</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 序列化模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-json</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库加解密模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-encrypt</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 租户模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-tenant</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- chat模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-chat</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 微信模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-wechat</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- AI绘画 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-fusion</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- 支付模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-pay</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
</project>
|
118
aibidding-common/aibidding-common-chat/pom.xml
Normal file
118
aibidding-common/aibidding-common-chat/pom.xml
Normal file
@ -0,0 +1,118 @@
|
||||
<?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>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>aibidding-common-chat</artifactId>
|
||||
|
||||
<description>
|
||||
ruoyi-common-chat 模块
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<retrofit2.version>2.9.0</retrofit2.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.33</version>
|
||||
</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>aibidding-common-json</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>aibidding-common-satoken</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>retrofit</artifactId>
|
||||
<version>${retrofit2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>converter-jackson</artifactId>
|
||||
<version>${retrofit2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>adapter-rxjava2</artifactId>
|
||||
<version>${retrofit2.version}</version>
|
||||
</dependency>
|
||||
|
||||
<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>
|
||||
</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>
|
||||
<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>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>2.7.5</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,56 @@
|
||||
package org.aibidding.common.chat.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import org.aibidding.common.chat.openai.OpenAiStreamClient;
|
||||
import org.aibidding.common.chat.openai.function.KeyRandomStrategy;
|
||||
import org.aibidding.common.chat.openai.interceptor.OpenAILogger;
|
||||
import org.aibidding.common.core.service.ConfigService;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Chat配置类
|
||||
*
|
||||
* @date: 2023/5/16
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class ChatConfig {
|
||||
|
||||
@Getter
|
||||
private OpenAiStreamClient openAiStreamClient;
|
||||
|
||||
private final ConfigService configService;
|
||||
|
||||
// 重启才会生效
|
||||
@Bean
|
||||
public OpenAiStreamClient openAiStreamClient() {
|
||||
String apiHost = configService.getConfigValue("chat", "apiHost");
|
||||
String apiKey = configService.getConfigValue("chat", "apiKey");
|
||||
openAiStreamClient = createOpenAiStreamClient(apiHost,apiKey);
|
||||
return openAiStreamClient;
|
||||
}
|
||||
|
||||
public OpenAiStreamClient createOpenAiStreamClient(String apiHost, String apiKey) {
|
||||
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(Collections.singletonList(apiKey))
|
||||
.keyStrategy(new KeyRandomStrategy())
|
||||
.okHttpClient(okHttpClient)
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package org.aibidding.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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package org.aibidding.common.chat.config;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.aibidding.common.chat.config.properties.WebSocketProperties;
|
||||
import org.aibidding.common.chat.handler.PlusWebSocketHandler;
|
||||
import org.aibidding.common.chat.interceptor.PlusWebSocketInterceptor;
|
||||
import org.aibidding.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) {
|
||||
// 如果WebSocket的路径为空,则设置默认路径为 "/websocket"
|
||||
if (StrUtil.isBlank(webSocketProperties.getPath())) {
|
||||
webSocketProperties.setPath("/websocket");
|
||||
}
|
||||
// 如果允许跨域访问的地址为空,则设置为 "*",表示允许所有来源的跨域请求
|
||||
if (StrUtil.isBlank(webSocketProperties.getAllowedOrigins())) {
|
||||
webSocketProperties.setAllowedOrigins("*");
|
||||
}
|
||||
// 返回一个WebSocketConfigurer对象,用于配置WebSocket
|
||||
return registry -> registry
|
||||
// 添加WebSocket处理程序和拦截器到指定路径,设置允许的跨域来源
|
||||
.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();
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.aibidding.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;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package org.aibidding.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;
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package org.aibidding.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";
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package org.aibidding.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.aibidding.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();
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package org.aibidding.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.aibidding.common.chat.entity.chat.ChatCompletionResponse;
|
||||
import org.aibidding.common.chat.entity.chat.Message;
|
||||
import org.aibidding.common.chat.entity.chat.tool.ToolCallFunction;
|
||||
import org.aibidding.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();
|
||||
}
|
||||
}
|
@ -0,0 +1,417 @@
|
||||
package org.aibidding.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.aibidding.common.chat.entity.chat.*;
|
||||
import org.aibidding.common.chat.entity.chat.tool.ToolCallFunction;
|
||||
import org.aibidding.common.chat.entity.chat.tool.ToolCalls;
|
||||
import org.aibidding.common.chat.entity.chat.tool.Tools;
|
||||
import org.aibidding.common.chat.entity.chat.tool.ToolsFunction;
|
||||
import org.aibidding.common.chat.openai.OpenAiClient;
|
||||
import org.aibidding.common.chat.openai.OpenAiStreamClient;
|
||||
import org.aibidding.common.chat.openai.function.KeyRandomStrategy;
|
||||
import org.aibidding.common.chat.openai.interceptor.DynamicKeyOpenAiAuthInterceptor;
|
||||
import org.aibidding.common.chat.openai.interceptor.OpenAILogger;
|
||||
import org.aibidding.common.chat.openai.interceptor.OpenAiResponseInterceptor;
|
||||
import org.aibidding.common.chat.openai.plugin.PluginAbstract;
|
||||
import org.aibidding.common.chat.plugin.CmdPlugin;
|
||||
import org.aibidding.common.chat.plugin.CmdReq;
|
||||
import org.aibidding.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 "西瓜";
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package org.aibidding.common.chat.demo;
|
||||
|
||||
|
||||
import org.aibidding.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();
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package org.aibidding.common.chat.demo;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import org.aibidding.common.chat.openai.plugin.PluginParam;
|
||||
|
||||
@Data
|
||||
public class WeatherReq extends PluginParam {
|
||||
/**
|
||||
* 城市
|
||||
*/
|
||||
private String location;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package org.aibidding.common.chat.demo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WeatherResp {
|
||||
/**
|
||||
* 温度
|
||||
*/
|
||||
private String temp;
|
||||
/**
|
||||
* 风力等级
|
||||
*/
|
||||
private Integer level;
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
package org.aibidding.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());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package org.aibidding.common.chat.domain.request;
|
||||
|
||||
import org.aibidding.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;
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package org.aibidding.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;
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package org.aibidding.common.chat.entity.Tts;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.*;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TextToSpeech {
|
||||
|
||||
@Builder.Default
|
||||
private String model = Model.TTS_1.getName();
|
||||
/**
|
||||
* 音频声音源
|
||||
*
|
||||
* @see TtsVoice
|
||||
*/
|
||||
private String voice;
|
||||
/**
|
||||
* 输入内容
|
||||
*/
|
||||
private String input;
|
||||
/**
|
||||
* 输出音频文件格式
|
||||
*
|
||||
* @see TtsFormat
|
||||
*/
|
||||
@JsonProperty("response_format")
|
||||
private String responseFormat;
|
||||
/**
|
||||
* 速度调节,默认是1,取值范围0.25——4.0
|
||||
*/
|
||||
private Double speed;
|
||||
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Model {
|
||||
TTS_1("tts-1"),
|
||||
TTS_1_HD("tts-1-hd"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package org.aibidding.common.chat.entity.Tts;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum TtsFormat {
|
||||
MP3("mp3"),
|
||||
OPUS("opus"),
|
||||
AAC("aac"),
|
||||
FLAC("flac"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.aibidding.common.chat.entity.Tts;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 生成不同声音的音频
|
||||
* <p>具体语音效果参考:https://platform.openai.com/docs/guides/text-to-speech</p>
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum TtsVoice {
|
||||
|
||||
ALLOY("alloy"),
|
||||
ECHO("echo"),
|
||||
FABLE("fable"),
|
||||
ONYX("onyx"),
|
||||
NOVA("nova"),
|
||||
SHIMMER("shimmer"),
|
||||
;
|
||||
|
||||
private final String name;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package org.aibidding.common.chat.entity.billing;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:金额消耗信息
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-04-08
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class BillingUsage {
|
||||
|
||||
@JsonProperty("object")
|
||||
private String object;
|
||||
/**
|
||||
* 账号金额消耗明细
|
||||
*/
|
||||
@JsonProperty("daily_costs")
|
||||
private List<DailyCost> dailyCosts;
|
||||
/**
|
||||
* 总使用金额:美分
|
||||
*/
|
||||
@JsonProperty("total_usage")
|
||||
private BigDecimal totalUsage;
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package org.aibidding.common.chat.entity.billing;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 描述:余额查询接口返回值
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-18
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class CreditGrantsResponse implements Serializable {
|
||||
private String object;
|
||||
/**
|
||||
* 总金额:美元
|
||||
*/
|
||||
@JsonProperty("total_granted")
|
||||
private BigDecimal totalGranted;
|
||||
/**
|
||||
* 总使用金额:美元
|
||||
*/
|
||||
@JsonProperty("total_used")
|
||||
private BigDecimal totalUsed;
|
||||
/**
|
||||
* 总剩余金额:美元
|
||||
*/
|
||||
@JsonProperty("total_available")
|
||||
private BigDecimal totalAvailable;
|
||||
/**
|
||||
* 余额明细
|
||||
*/
|
||||
private Grants grants;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package org.aibidding.common.chat.entity.billing;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:金额消耗列表
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-04-08
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class DailyCost {
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
@JsonProperty("timestamp")
|
||||
private long timestamp;
|
||||
/**
|
||||
* 模型消耗金额详情
|
||||
*/
|
||||
@JsonProperty("line_items")
|
||||
private List<LineItem> lineItems;
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package org.aibidding.common.chat.entity.billing;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-18
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Datum {
|
||||
private String object;
|
||||
private String id;
|
||||
/**
|
||||
* 赠送金额:美元
|
||||
*/
|
||||
@JsonProperty("grant_amount")
|
||||
private BigDecimal grantAmount;
|
||||
/**
|
||||
* 使用金额:美元
|
||||
*/
|
||||
@JsonProperty("used_amount")
|
||||
private BigDecimal usedAmount;
|
||||
/**
|
||||
* 生效时间戳
|
||||
*/
|
||||
@JsonProperty("effective_at")
|
||||
private Long effectiveAt;
|
||||
/**
|
||||
* 过期时间戳
|
||||
*/
|
||||
@JsonProperty("expires_at")
|
||||
private Long expiresAt;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package org.aibidding.common.chat.entity.billing;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-18
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Grants {
|
||||
private String object;
|
||||
@JsonProperty("data")
|
||||
private List<Datum> data;
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package org.aibidding.common.chat.entity.billing;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* openKey信息
|
||||
*
|
||||
* @author admin
|
||||
* @date 2023/6/15
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@ToString
|
||||
public class KeyInfo {
|
||||
/**
|
||||
* 订阅类型
|
||||
*/
|
||||
private String planTitle;
|
||||
/**
|
||||
* key值
|
||||
*/
|
||||
private String keyValue;
|
||||
/**
|
||||
* 剩余额度
|
||||
*/
|
||||
private Double remaining;
|
||||
|
||||
/**
|
||||
* 账户总余额
|
||||
*/
|
||||
private Double totalAmount;
|
||||
|
||||
/**
|
||||
* 已使用的额度
|
||||
*/
|
||||
private Double totalUsage;
|
||||
|
||||
/**
|
||||
* 截至日期
|
||||
*/
|
||||
private LocalDate limitDate;
|
||||
|
||||
/**
|
||||
* 是否绑卡
|
||||
*/
|
||||
private Boolean isHasPaymentMethod;
|
||||
|
||||
/**
|
||||
* 最高可用模型
|
||||
*/
|
||||
private String model;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.aibidding.common.chat.entity.billing;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 描述:金额消耗列表
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-04-08
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class LineItem {
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 消耗金额
|
||||
*/
|
||||
private BigDecimal cost;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package org.aibidding.common.chat.entity.billing;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-04-08
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Plan {
|
||||
private String title;
|
||||
private String id;
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package org.aibidding.common.chat.entity.billing;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 描述:账户信息
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-04-08
|
||||
*/
|
||||
@Data
|
||||
public class Subscription {
|
||||
|
||||
@JsonProperty("object")
|
||||
private String object;
|
||||
|
||||
/**
|
||||
* 付款方式
|
||||
*/
|
||||
@JsonProperty("has_payment_method")
|
||||
private boolean hasPaymentMethod;
|
||||
|
||||
@JsonProperty("canceled")
|
||||
private boolean canceled;
|
||||
@JsonProperty("canceled_at")
|
||||
private Object canceledAt;
|
||||
|
||||
@JsonProperty("delinquent")
|
||||
private Object delinquent;
|
||||
@JsonProperty("access_until")
|
||||
private long accessUntil;
|
||||
@JsonProperty("soft_limit")
|
||||
private long softLimit;
|
||||
@JsonProperty("hard_limit")
|
||||
private long hardLimit;
|
||||
@JsonProperty("system_hard_limit")
|
||||
private long systemHardLimit;
|
||||
@JsonProperty("soft_limit_usd")
|
||||
private double softLimitUsd;
|
||||
@JsonProperty("hard_limit_usd")
|
||||
private double hardLimitUsd;
|
||||
@JsonProperty("system_hard_limit_usd")
|
||||
private double systemHardLimitUsd;
|
||||
/**
|
||||
* 计划
|
||||
*/
|
||||
@JsonProperty("plan")
|
||||
private Plan plan;
|
||||
|
||||
/**
|
||||
* 账户名称
|
||||
*/
|
||||
@JsonProperty("account_name")
|
||||
private String accountName;
|
||||
|
||||
@JsonProperty("po_number")
|
||||
private Object poNumber;
|
||||
|
||||
/**
|
||||
* 账单邮箱
|
||||
*/
|
||||
@JsonProperty("billing_email")
|
||||
private Object billingEmail;
|
||||
@JsonProperty("tax_ids")
|
||||
private Object taxIds;
|
||||
@JsonProperty("billing_address")
|
||||
private Object billingAddress;
|
||||
@JsonProperty("business_address")
|
||||
private Object businessAddress;
|
||||
@JsonProperty("primary")
|
||||
private Boolean primary;
|
||||
}
|
@ -0,0 +1,255 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import org.aibidding.common.chat.entity.chat.tool.Tools;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.aibidding.common.chat.entity.chat.BaseChatCompletion.Model.GPT_3_5_TURBO;
|
||||
|
||||
/**
|
||||
* 描述: chat模型基础类
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 1.1.2
|
||||
* 2023-11-10
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BaseChatCompletion implements Serializable {
|
||||
|
||||
@NonNull
|
||||
@Builder.Default
|
||||
private String model = GPT_3_5_TURBO.getName();
|
||||
|
||||
/**
|
||||
* 指定模型必须输出的格式的对象。
|
||||
*
|
||||
* @since 1.1.2
|
||||
*/
|
||||
@JsonProperty("response_format")
|
||||
private ResponseFormat responseFormat;
|
||||
|
||||
/**
|
||||
* 已过时
|
||||
*
|
||||
* @see #tools
|
||||
*/
|
||||
@Deprecated
|
||||
private List<Functions> functions;
|
||||
|
||||
/**
|
||||
* 取值:null,auto或者自定义
|
||||
* functions没有值的时候默认为:null
|
||||
* functions存在值得时候默认为:auto
|
||||
* 也可以自定义
|
||||
* <p>已过时</p>
|
||||
*
|
||||
* @see #toolChoice
|
||||
*/
|
||||
@Deprecated
|
||||
@JsonProperty("function_call")
|
||||
private Object functionCall;
|
||||
|
||||
/**
|
||||
* 模型可能调用的工具列表。
|
||||
* 当前版本仅支持:functions
|
||||
*
|
||||
* @since 1.1.2
|
||||
*/
|
||||
private List<Tools> tools;
|
||||
|
||||
/**
|
||||
* 取值:String或者ToolChoiceObj
|
||||
*
|
||||
* @since 1.1.2
|
||||
*/
|
||||
@JsonProperty("tool_choice")
|
||||
private Object toolChoice;
|
||||
|
||||
/**
|
||||
* 使用什么取样温度,0到2之间。较高的值(如0.8)将使输出更加随机,而较低的值(如0.2)将使输出更加集中和确定。
|
||||
* <p>
|
||||
* We generally recommend altering this or but not both.top_p
|
||||
*/
|
||||
@Builder.Default
|
||||
private double temperature = 0.2;
|
||||
|
||||
/**
|
||||
* 使用温度采样的替代方法称为核心采样,其中模型考虑具有top_p概率质量的令牌的结果。因此,0.1 意味着只考虑包含前 10% 概率质量的代币。
|
||||
* <p>
|
||||
* 我们通常建议更改此设置,但不要同时更改两者。temperature
|
||||
*/
|
||||
@JsonProperty("top_p")
|
||||
@Builder.Default
|
||||
private Double topP = 1d;
|
||||
|
||||
|
||||
/**
|
||||
* 为每个提示生成的完成次数。
|
||||
*/
|
||||
@Builder.Default
|
||||
private Integer n = 1;
|
||||
|
||||
|
||||
/**
|
||||
* 是否流式输出.
|
||||
* default:false
|
||||
*/
|
||||
@Builder.Default
|
||||
private boolean stream = false;
|
||||
/**
|
||||
* 停止输出标识
|
||||
*/
|
||||
private List<String> stop;
|
||||
/**
|
||||
* 最大支持4096
|
||||
*/
|
||||
@JsonProperty("max_tokens")
|
||||
@Builder.Default
|
||||
private Integer maxTokens = 2048;
|
||||
|
||||
|
||||
@JsonProperty("presence_penalty")
|
||||
@Builder.Default
|
||||
private double presencePenalty = 0;
|
||||
|
||||
/**
|
||||
* -2.0 ~~ 2.0
|
||||
*/
|
||||
@JsonProperty("frequency_penalty")
|
||||
@Builder.Default
|
||||
private double frequencyPenalty = 0;
|
||||
|
||||
@JsonProperty("logit_bias")
|
||||
private Map logitBias;
|
||||
/**
|
||||
* 用户唯一值,确保接口不被重复调用
|
||||
*/
|
||||
private String user;
|
||||
|
||||
/**
|
||||
* @since 1.1.2
|
||||
*/
|
||||
private Integer seed;
|
||||
|
||||
|
||||
/**
|
||||
* 最新模型参考官方文档:
|
||||
* <a href="https://platform.openai.com/docs/models/model-endpoint-compatibility">官方稳定模型列表</a>
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Model {
|
||||
/**
|
||||
* gpt-3.5-turbo
|
||||
*/
|
||||
GPT_3_5_TURBO("gpt-3.5-turbo"),
|
||||
/**
|
||||
* 临时模型,不建议使用,2023年9 月 13 日将被弃用
|
||||
*/
|
||||
@Deprecated
|
||||
GPT_3_5_TURBO_0301("gpt-3.5-turbo-0301"),
|
||||
/**
|
||||
* gpt-3.5-turbo-0613 支持函数
|
||||
*/
|
||||
GPT_3_5_TURBO_1106("gpt-3.5-turbo-1106"),
|
||||
|
||||
GPT_3_5_TURBO_0613("gpt-3.5-turbo-0613"),
|
||||
/**
|
||||
* gpt-3.5-turbo-16k 超长上下文
|
||||
*/
|
||||
GPT_3_5_TURBO_16K("gpt-3.5-turbo-16k"),
|
||||
/**
|
||||
* gpt-3.5-turbo-16k-0613 超长上下文 支持函数
|
||||
*/
|
||||
GPT_3_5_TURBO_16K_0613("gpt-3.5-turbo-16k-0613"),
|
||||
/**
|
||||
* gpt-3.5-turbo-0125 超长上下文 支持函数
|
||||
*/
|
||||
GPT_3_5_TURBO_0125("gpt-3.5-turbo-0125"),
|
||||
/**
|
||||
* GPT4.0
|
||||
*/
|
||||
GPT_4("gpt-4"),
|
||||
/**
|
||||
* 临时模型,不建议使用,2023年9 月 13 日将被弃用
|
||||
*/
|
||||
@Deprecated
|
||||
GPT_4_0314("gpt-4-0314"),
|
||||
/**
|
||||
* GPT4.0 超长上下文
|
||||
*/
|
||||
GPT_4_32K("gpt-4-32k"),
|
||||
/**
|
||||
* 临时模型,不建议使用,2023年9 月 13 日将被弃用
|
||||
*/
|
||||
@Deprecated
|
||||
GPT_4_32K_0314("gpt-4-32k-0314"),
|
||||
|
||||
/**
|
||||
* gpt-4-0613,支持函数
|
||||
*/
|
||||
GPT_4_0613("gpt-4-0613"),
|
||||
/**
|
||||
* gpt-4-0613,支持函数
|
||||
*/
|
||||
GPT_4_32K_0613("gpt-4-32k-0613"),
|
||||
/**
|
||||
* 支持数组模式,支持function call,支持可重复输出
|
||||
*/
|
||||
GPT_4_1106_PREVIEW("gpt-4-1106-preview"),
|
||||
/**
|
||||
* 支持图片
|
||||
*/
|
||||
GPT_4_VISION_PREVIEW("gpt-4-vision-preview"),
|
||||
/**
|
||||
* gpt-4-0613,支持函数
|
||||
*/
|
||||
GPT_4_0125_PREVIEW("gpt-4-0125-preview"),
|
||||
|
||||
/**
|
||||
* GPT_4_ALL
|
||||
*/
|
||||
GPT_4_ALL("gpt-4-all"),
|
||||
|
||||
GPT_4_GIZMO("gpt-4-gizmo"),
|
||||
|
||||
NET("net"),
|
||||
|
||||
CLAUDE_3_SONNET("claude-3-sonnet-20240229"),
|
||||
|
||||
GEMINI_PRO("gemini-pro"),
|
||||
|
||||
STABLE_DIFFUSION("stable-diffusion"),
|
||||
|
||||
SUNO_V3("suno-v3"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ChatType {
|
||||
/**
|
||||
* 对话类型 - 输入
|
||||
*/
|
||||
CHAT_IN("in"),
|
||||
/**
|
||||
* 对话类型 - 输出
|
||||
*/
|
||||
CHAT_OUT("out"),
|
||||
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.aibidding.common.chat.entity.chat.tool.ToolCalls;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 1.1.2
|
||||
* 2023-03-02
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@AllArgsConstructor
|
||||
public class BaseMessage implements Serializable {
|
||||
|
||||
/**
|
||||
* 目前支持四个中角色参考官网,进行情景输入:
|
||||
* https://platform.openai.com/docs/guides/chat/introduction
|
||||
*/
|
||||
private String role;
|
||||
|
||||
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The tool calls generated by the model, such as function calls.
|
||||
* @since 1.1.2
|
||||
*/
|
||||
@JsonProperty("tool_calls")
|
||||
private List<ToolCalls> toolCalls;
|
||||
|
||||
/**
|
||||
* @since 1.1.2
|
||||
*/
|
||||
@JsonProperty("tool_call_id")
|
||||
private String toolCallId;
|
||||
|
||||
@Deprecated
|
||||
@JsonProperty("function_call")
|
||||
private FunctionCall functionCall;
|
||||
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param role 角色
|
||||
* @param name name
|
||||
* @param functionCall functionCall
|
||||
*/
|
||||
public BaseMessage(String role, String name, FunctionCall functionCall) {
|
||||
this.role = role;
|
||||
this.name = name;
|
||||
this.functionCall = functionCall;
|
||||
}
|
||||
|
||||
public BaseMessage() {
|
||||
}
|
||||
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Role {
|
||||
|
||||
SYSTEM("system"),
|
||||
USER("user"),
|
||||
ASSISTANT("assistant"),
|
||||
FUNCTION("function"),
|
||||
TOOL("tool"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-02
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ChatChoice implements Serializable {
|
||||
private long index;
|
||||
/**
|
||||
* 请求参数stream为true返回是delta
|
||||
*/
|
||||
@JsonProperty("delta")
|
||||
private Message delta;
|
||||
/**
|
||||
* 请求参数stream为false返回是message
|
||||
*/
|
||||
@JsonProperty("message")
|
||||
private Message message;
|
||||
@JsonProperty("finish_reason")
|
||||
private String finishReason;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述: chat模型参数
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-03-02
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@Slf4j
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ChatCompletion extends BaseChatCompletion implements Serializable {
|
||||
|
||||
/**
|
||||
* 问题描述
|
||||
*/
|
||||
@NonNull
|
||||
private List<Message> messages;
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
import org.aibidding.common.chat.entity.common.Usage;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述: chat答案类
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-03-02
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ChatCompletionResponse implements Serializable {
|
||||
private String id;
|
||||
private String object;
|
||||
private long created;
|
||||
private String model;
|
||||
private List<ChatChoice> choices;
|
||||
private Usage usage;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述: chat模型附带图片的参数
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 1.1.2
|
||||
* 2023-11-10
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@Slf4j
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ChatCompletionWithPicture extends BaseChatCompletion implements Serializable {
|
||||
/**
|
||||
* 问题描述
|
||||
*/
|
||||
private List<MessagePicture> messages;
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https://www.unfbx.com
|
||||
* @since 1.1.2
|
||||
* 2023-11-10
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@Slf4j
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Content {
|
||||
/**
|
||||
* 输入类型:text、image_url
|
||||
*
|
||||
* @see Type
|
||||
*/
|
||||
private String type;
|
||||
private String text;
|
||||
@JsonProperty("image_url")
|
||||
private ImageUrl imageUrl;
|
||||
|
||||
/**
|
||||
* 生成图片风格
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Type {
|
||||
TEXT("text"),
|
||||
IMAGE_URL("image_url"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 描述:函数调用返回值
|
||||
*
|
||||
* @author https://www.unfbx.com
|
||||
* @since 2023-06-14
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class FunctionCall {
|
||||
/**
|
||||
* 方法名
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 方法参数
|
||||
*/
|
||||
private String arguments;
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:方法参数实体类,实例数据如下
|
||||
* <pre>
|
||||
* {
|
||||
* "name": "get_current_weather",
|
||||
* "description": "Get the current weather in a given location",
|
||||
* "parameters": {
|
||||
* "type": "object",
|
||||
* "properties": {
|
||||
* "location": {
|
||||
* "type": "string",
|
||||
* "description": "The city and state, e.g. San Francisco, CA"
|
||||
* },
|
||||
* "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
|
||||
* },
|
||||
* "required": ["location"]
|
||||
* },
|
||||
* }
|
||||
* </pre>
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-06-14
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class Functions implements Serializable {
|
||||
/**
|
||||
* 方法名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 方法描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 方法参数
|
||||
* 扩展参数可以继承Parameters自己实现,json格式的数据
|
||||
*/
|
||||
private Parameters parameters;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https://www.unfbx.com
|
||||
* 2023-11-10
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@Slf4j
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ImageUrl {
|
||||
/**
|
||||
* 图片地址,支持base64. eg: data:image/jpeg;base64,{base64_image} <p\>
|
||||
* https://platform.openai.com/docs/guides/vision
|
||||
*/
|
||||
private String url;
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
import org.aibidding.common.chat.entity.chat.tool.ToolCalls;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-02
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Message extends BaseMessage implements Serializable {
|
||||
|
||||
private Object content;
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param role 角色
|
||||
* @param name name
|
||||
* @param content content
|
||||
* @param functionCall functionCall
|
||||
*/
|
||||
public Message(String role, String name, String content, List<ToolCalls> toolCalls, String toolCallId, FunctionCall functionCall) {
|
||||
this.content = content;
|
||||
super.setRole(role);
|
||||
super.setName(name);
|
||||
super.setToolCalls(toolCalls);
|
||||
super.setToolCallId(toolCallId);
|
||||
super.setFunctionCall(functionCall);
|
||||
}
|
||||
|
||||
public Message() {
|
||||
}
|
||||
|
||||
private Message(Builder builder) {
|
||||
setContent(builder.content);
|
||||
super.setRole(builder.role);
|
||||
super.setName(builder.name);
|
||||
super.setFunctionCall(builder.functionCall);
|
||||
super.setToolCalls(builder.toolCalls);
|
||||
super.setToolCallId(builder.toolCallId);
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private String role;
|
||||
private String content;
|
||||
private String name;
|
||||
private String toolCallId;
|
||||
private List<ToolCalls> toolCalls;
|
||||
private FunctionCall functionCall;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder role(Role role) {
|
||||
this.role = role.getName();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder role(String role) {
|
||||
this.role = role;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder content(String content) {
|
||||
this.content = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder functionCall(FunctionCall functionCall) {
|
||||
this.functionCall = functionCall;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder toolCalls(List<ToolCalls> toolCalls) {
|
||||
this.toolCalls = toolCalls;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder toolCallId(String toolCallId) {
|
||||
this.toolCallId = toolCallId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Message build() {
|
||||
return new Message(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.aibidding.common.chat.entity.chat.tool.ToolCalls;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-02
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@AllArgsConstructor
|
||||
public class MessagePicture extends BaseMessage implements Serializable {
|
||||
/**
|
||||
* Content数组支持多图片输入
|
||||
* https://platform.openai.com/docs/guides/vision
|
||||
*/
|
||||
private List<Content> content;
|
||||
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param role 角色
|
||||
* @param name name
|
||||
* @param content content
|
||||
* @param functionCall functionCall
|
||||
*/
|
||||
public MessagePicture(String role, String name, List<Content> content, List<ToolCalls> toolCalls, String toolCallId, FunctionCall functionCall) {
|
||||
this.content = content;
|
||||
super.setRole(role);
|
||||
super.setName(name);
|
||||
super.setToolCalls(toolCalls);
|
||||
super.setToolCallId(toolCallId);
|
||||
super.setFunctionCall(functionCall);
|
||||
}
|
||||
|
||||
public MessagePicture() {
|
||||
}
|
||||
|
||||
private MessagePicture(Builder builder) {
|
||||
setContent(builder.content);
|
||||
super.setRole(builder.role);
|
||||
super.setName(builder.name);
|
||||
super.setFunctionCall(builder.functionCall);
|
||||
super.setToolCalls(builder.toolCalls);
|
||||
super.setToolCallId(builder.toolCallId);
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private String role;
|
||||
private List<Content> content;
|
||||
private String name;
|
||||
private String toolCallId;
|
||||
private List<ToolCalls> toolCalls;
|
||||
private FunctionCall functionCall;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder role(Role role) {
|
||||
this.role = role.getName();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder role(String role) {
|
||||
this.role = role;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder content(List<Content> content) {
|
||||
this.content = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder functionCall(FunctionCall functionCall) {
|
||||
this.functionCall = functionCall;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder toolCalls(List<ToolCalls> toolCalls) {
|
||||
this.toolCalls = toolCalls;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder toolCallId(String toolCallId) {
|
||||
this.toolCallId = toolCallId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MessagePicture build() {
|
||||
return new MessagePicture(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
/**
|
||||
* 描述:方法参数类,扩展参数可以继承Parameters自己实现
|
||||
* 参考:
|
||||
* <pre>
|
||||
* {
|
||||
* "type": "object",
|
||||
* "properties": {
|
||||
* "location": {
|
||||
* "type": "string",
|
||||
* "description": "The city and state, e.g. San Francisco, CA"
|
||||
* },
|
||||
* "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
|
||||
* },
|
||||
* "required": ["location"]
|
||||
* }
|
||||
* </pre>
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-06-14
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class Parameters implements Serializable {
|
||||
/**
|
||||
* 参数类型
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 参数属性、描述
|
||||
*/
|
||||
private Object properties;
|
||||
/**
|
||||
* 方法必输字段
|
||||
*/
|
||||
private List<String> required;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package org.aibidding.common.chat.entity.chat;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 指定模型必须输出的格式的对象。
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ResponseFormat {
|
||||
/**
|
||||
* 默认:text
|
||||
*
|
||||
* @see Type
|
||||
*/
|
||||
private String type;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Type {
|
||||
JSON_OBJECT("json_object"),
|
||||
TEXT("text"),
|
||||
;
|
||||
private final String name;
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package org.aibidding.common.chat.entity.chat.tool;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ToolCall 的 Function参数
|
||||
* The function that the model called.
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 1.1.2
|
||||
* 2023-11-09
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ToolCallFunction implements Serializable {
|
||||
/**
|
||||
* 方法名
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 方法参数
|
||||
*/
|
||||
private String arguments;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package org.aibidding.common.chat.entity.chat.tool;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* The tool calls generated by the model, such as function calls.
|
||||
*
|
||||
* @author <a href="https://www.unfbx.com">unfbx</a>
|
||||
* @since 1.1.2
|
||||
* 2023-11-09
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ToolCalls implements Serializable {
|
||||
/**
|
||||
* The ID of the tool call.
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* The type of the tool. Currently, only function is supported.
|
||||
*/
|
||||
private String type;
|
||||
|
||||
private ToolCallFunction function;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Type {
|
||||
FUNCTION("function"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package org.aibidding.common.chat.entity.chat.tool;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* choice和object同时存在是以object为准
|
||||
*
|
||||
* @author <a href="https://www.unfbx.com">unfbx</a>
|
||||
* @since 1.1.2
|
||||
* 2023-11-09
|
||||
*/
|
||||
@Data
|
||||
public class ToolChoice implements Serializable {
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Choice {
|
||||
NONE("none"),
|
||||
AUTO("auto"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package org.aibidding.common.chat.entity.chat.tool;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* @author <a href="https://www.unfbx.com">unfbx</a>
|
||||
* @since 1.1.2
|
||||
* 2023-11-09
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ToolChoiceObj {
|
||||
/**
|
||||
* 需要调用的方法名称
|
||||
*/
|
||||
private ToolChoiceObjFunction function;
|
||||
/**
|
||||
* 工具的类型。目前仅支持函数。
|
||||
*
|
||||
* @see Type
|
||||
*/
|
||||
private String type;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Type {
|
||||
FUNCTION("function"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package org.aibidding.common.chat.entity.chat.tool;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author <a href="https://www.unfbx.com">unfbx</a>
|
||||
* @since 1.1.2
|
||||
* 2023-11-09
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ToolChoiceObjFunction {
|
||||
|
||||
private String name;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.aibidding.common.chat.entity.chat.tool;
|
||||
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author <a href="https://www.unfbx.com">unfbx</a>
|
||||
* @since 1.1.2
|
||||
* 2023-11-09
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Tools implements Serializable {
|
||||
|
||||
/**
|
||||
* 目前只支持:function
|
||||
*
|
||||
* @see Type
|
||||
*/
|
||||
private String type;
|
||||
|
||||
private ToolsFunction function;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Type {
|
||||
FUNCTION("function"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package org.aibidding.common.chat.entity.chat.tool;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.aibidding.common.chat.entity.chat.Parameters;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author <a href="https://www.unfbx.com">unfbx</a>
|
||||
* @since 1.1.2
|
||||
* 2023-11-09
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ToolsFunction implements Serializable {
|
||||
|
||||
/**
|
||||
* 要调用的函数的名称。必须是 a-z、A-Z、0-9,或包含下划线和破折号,最大长度为 64
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 对函数功能的描述,模型使用它来选择何时以及如何调用该函数。
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 函数接受的参数,描述为 JSON Schema 对象
|
||||
* 扩展参数可以继承Parameters自己实现,json格式的数据
|
||||
*/
|
||||
private Parameters parameters;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.aibidding.common.chat.entity.common;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Choice implements Serializable {
|
||||
private String text;
|
||||
private long index;
|
||||
private Object logprobs;
|
||||
@JsonProperty("finish_reason")
|
||||
private String finishReason;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package org.aibidding.common.chat.entity.common;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class DeleteResponse implements Serializable {
|
||||
private String id;
|
||||
private String object;
|
||||
private boolean deleted;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package org.aibidding.common.chat.entity.common;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class OpenAiResponse<T> implements Serializable {
|
||||
private String object;
|
||||
private List<T> data;
|
||||
private Error error;
|
||||
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Error {
|
||||
private String message;
|
||||
private String type;
|
||||
private String param;
|
||||
private String code;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package org.aibidding.common.chat.entity.common;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Usage implements Serializable {
|
||||
@JsonProperty("prompt_tokens")
|
||||
private long promptTokens;
|
||||
@JsonProperty("completion_tokens")
|
||||
private long completionTokens;
|
||||
@JsonProperty("total_tokens")
|
||||
private long totalTokens;
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
package org.aibidding.common.chat.entity.completions;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 描述: 问题类
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-11
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@Slf4j
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Completion implements Serializable {
|
||||
|
||||
@NonNull
|
||||
@Builder.Default
|
||||
private String model = Model.DAVINCI_003.getName();
|
||||
/**
|
||||
* 问题描述
|
||||
*/
|
||||
@NonNull
|
||||
private String prompt;
|
||||
/**
|
||||
* 完成输出后的后缀,用于格式化输出结果
|
||||
*/
|
||||
private String suffix;
|
||||
|
||||
/**
|
||||
* 最大支持4096
|
||||
*/
|
||||
@JsonProperty("max_tokens")
|
||||
@Builder.Default
|
||||
private Integer maxTokens = 2048;
|
||||
/**
|
||||
* 使用什么取样温度,0到2之间。较高的值(如0.8)将使输出更加随机,而较低的值(如0.2)将使输出更加集中和确定。
|
||||
* <p>
|
||||
* We generally recommend altering this or but not both.top_p
|
||||
*/
|
||||
@Builder.Default
|
||||
private double temperature = 0;
|
||||
|
||||
/**
|
||||
* 使用温度采样的替代方法称为核心采样,其中模型考虑具有top_p概率质量的令牌的结果。因此,0.1 意味着只考虑包含前 10% 概率质量的代币。
|
||||
* <p>
|
||||
* 我们通常建议更改此设置,但不要同时更改两者。temperature
|
||||
*/
|
||||
@JsonProperty("top_p")
|
||||
@Builder.Default
|
||||
private Double topP = 1d;
|
||||
|
||||
/**
|
||||
* 为每个提示生成的完成次数。
|
||||
*/
|
||||
@Builder.Default
|
||||
private Integer n = 1;
|
||||
|
||||
@Builder.Default
|
||||
private boolean stream = false;
|
||||
/**
|
||||
* 最大值:5
|
||||
*/
|
||||
private Integer logprobs;
|
||||
|
||||
@Builder.Default
|
||||
private boolean echo = false;
|
||||
|
||||
private List<String> stop;
|
||||
|
||||
@JsonProperty("presence_penalty")
|
||||
@Builder.Default
|
||||
private double presencePenalty = 0;
|
||||
|
||||
/**
|
||||
* -2.0 ~~ 2.0
|
||||
*/
|
||||
@JsonProperty("frequency_penalty")
|
||||
@Builder.Default
|
||||
private double frequencyPenalty = 0;
|
||||
|
||||
@JsonProperty("best_of")
|
||||
@Builder.Default
|
||||
private Integer bestOf = 1;
|
||||
|
||||
@JsonProperty("logit_bias")
|
||||
private Map logitBias;
|
||||
/**
|
||||
* 用户唯一值,确保接口不被重复调用
|
||||
*/
|
||||
private String user;
|
||||
|
||||
/**
|
||||
* 获取当前参数的tokens数
|
||||
* @return token数量
|
||||
*/
|
||||
// public long tokens() {
|
||||
// if (StrUtil.isBlank(this.prompt) || StrUtil.isBlank(this.model)) {
|
||||
// log.warn("参数异常model:{},prompt:{}", this.model, this.prompt);
|
||||
// return 0;
|
||||
// }
|
||||
// return TikTokensUtil.tokens(this.model, this.prompt);
|
||||
// }
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Model {
|
||||
DAVINCI_003("text-davinci-003"),
|
||||
DAVINCI_002("text-davinci-002"),
|
||||
DAVINCI("davinci"),
|
||||
;
|
||||
private String name;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
package org.aibidding.common.chat.entity.completions;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
import org.aibidding.common.chat.entity.common.Choice;
|
||||
import org.aibidding.common.chat.entity.common.OpenAiResponse;
|
||||
import org.aibidding.common.chat.entity.common.Usage;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述: 答案类
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-11
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class CompletionResponse extends OpenAiResponse implements Serializable {
|
||||
private String id;
|
||||
private String object;
|
||||
private long created;
|
||||
private String model;
|
||||
private Choice[] choices;
|
||||
private Usage usage;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package org.aibidding.common.chat.entity.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息的dto
|
||||
*
|
||||
* @author zendwang
|
||||
*/
|
||||
@Data
|
||||
public class WebSocketMessageDto implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 需要推送到的session key 列表
|
||||
*/
|
||||
private List<Long> sessionKeys;
|
||||
|
||||
/**
|
||||
* 需要发送的消息
|
||||
*/
|
||||
private String message;
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package org.aibidding.common.chat.entity.edits;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@Slf4j
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Edit implements Serializable {
|
||||
/**
|
||||
* 编辑模型,目前支持两种
|
||||
*/
|
||||
@NonNull
|
||||
private String model;
|
||||
|
||||
@NonNull
|
||||
private String input;
|
||||
/**
|
||||
* 提示说明。告知模型如何修改。
|
||||
*/
|
||||
@NonNull
|
||||
private String instruction;
|
||||
|
||||
|
||||
/**
|
||||
* 使用什么取样温度,0到2之间。较高的值(如0.8)将使输出更加随机,而较低的值(如0.2)将使输出更加集中和确定。
|
||||
*
|
||||
* We generally recommend altering this or but not both.top_p
|
||||
*/
|
||||
@Builder.Default
|
||||
private double temperature = 0;
|
||||
|
||||
/**
|
||||
* 使用温度采样的替代方法称为核心采样,其中模型考虑具有top_p概率质量的令牌的结果。因此,0.1 意味着只考虑包含前 10% 概率质量的代币。
|
||||
*
|
||||
* 我们通常建议更改此设置,但不要同时更改两者。temperature
|
||||
*/
|
||||
@JsonProperty("top_p")
|
||||
@Builder.Default
|
||||
private Double topP = 1d;
|
||||
|
||||
/**
|
||||
* 为每个提示生成的完成次数。
|
||||
*/
|
||||
@Builder.Default
|
||||
private Integer n = 1;
|
||||
|
||||
public void setModel(Model model) {
|
||||
this.model = model.getName();
|
||||
}
|
||||
|
||||
public void setTemperature(double temperature) {
|
||||
if (temperature > 2 || temperature < 0) {
|
||||
log.error("temperature参数异常,temperature属于[0,2]");
|
||||
this.temperature = 2;
|
||||
return;
|
||||
}
|
||||
if (temperature < 0) {
|
||||
log.error("temperature参数异常,temperature属于[0,2]");
|
||||
this.temperature = 0;
|
||||
return;
|
||||
}
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
|
||||
public void setTopP(Double topP) {
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
public void setN(Integer n) {
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
public void setInput(String input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public void setInstruction(String instruction) {
|
||||
this.instruction = instruction;
|
||||
}
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Model {
|
||||
TEXT_DAVINCI_EDIT_001("text-davinci-edit-001"),
|
||||
CODE_DAVINCI_EDIT_001("code-davinci-edit-001"),
|
||||
;
|
||||
private String name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
package org.aibidding.common.chat.entity.edits;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
import org.aibidding.common.chat.entity.common.Choice;
|
||||
import org.aibidding.common.chat.entity.common.Usage;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class EditResponse implements Serializable {
|
||||
private String id;
|
||||
private String object;
|
||||
private long created;
|
||||
private String model;
|
||||
private Choice[] choices;
|
||||
private Usage usage;
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package org.aibidding.common.chat.entity.embeddings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Getter
|
||||
@Slf4j
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Embedding implements Serializable {
|
||||
@NonNull
|
||||
@Builder.Default
|
||||
private String model = Model.TEXT_EMBEDDING_ADA_002.getName();
|
||||
/**
|
||||
* 必选项:长度不能超过:8192
|
||||
*/
|
||||
@NonNull
|
||||
private List<String> input;
|
||||
|
||||
private String user;
|
||||
|
||||
public void setModel(Model model) {
|
||||
if (Objects.isNull(model)) {
|
||||
model = Model.TEXT_EMBEDDING_ADA_002;
|
||||
}
|
||||
this.model = model.getName();
|
||||
}
|
||||
|
||||
|
||||
public void setUser(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Model {
|
||||
TEXT_EMBEDDING_ADA_002("text-embedding-ada-002"),
|
||||
;
|
||||
private String name;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package org.aibidding.common.chat.entity.embeddings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
import org.aibidding.common.chat.entity.common.Usage;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class EmbeddingResponse implements Serializable {
|
||||
|
||||
private String object;
|
||||
private List<Item> data;
|
||||
private String model;
|
||||
private Usage usage;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package org.aibidding.common.chat.entity.embeddings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Item implements Serializable {
|
||||
private String object;
|
||||
private List<BigDecimal> embedding;
|
||||
private Integer index;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.aibidding.common.chat.entity.engines;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Engine implements Serializable {
|
||||
|
||||
private String id;
|
||||
private String object;
|
||||
private String owner;
|
||||
private boolean ready;
|
||||
private Object permissions;
|
||||
private long created;
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.aibidding.common.chat.entity.files;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class File implements Serializable {
|
||||
|
||||
// private String id;
|
||||
// private String object;
|
||||
// private long bytes;
|
||||
// private long created_at;
|
||||
// private String filename;
|
||||
// private String purpose;
|
||||
// private String status;
|
||||
// @JsonProperty("status_details")
|
||||
// private String statusDetails;
|
||||
|
||||
private long bytes;
|
||||
private long created_at;
|
||||
private String filename;
|
||||
private String id;
|
||||
private String object;
|
||||
private String url;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package org.aibidding.common.chat.entity.files;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class UploadFileResponse extends File implements Serializable {
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package org.aibidding.common.chat.entity.fineTune;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Event implements Serializable {
|
||||
private String object;
|
||||
@JsonProperty("created_at")
|
||||
private long createdAt;
|
||||
private String level;
|
||||
private String message;
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package org.aibidding.common.chat.entity.fineTune;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aibidding.common.chat.openai.exception.CommonError;
|
||||
import org.aibidding.common.core.exception.base.BaseException;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Getter
|
||||
@Slf4j
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class FineTune implements Serializable {
|
||||
|
||||
/**
|
||||
* 上传的文件ID
|
||||
*/
|
||||
@NonNull
|
||||
@JsonProperty("training_file")
|
||||
private String trainingFile;
|
||||
|
||||
@JsonProperty("validation_file")
|
||||
private String validationFile;
|
||||
/**
|
||||
* 参考
|
||||
* @see Model
|
||||
*/
|
||||
private String model;
|
||||
|
||||
@JsonProperty("n_epochs")
|
||||
@Builder.Default
|
||||
private Integer n_epochs = 4;
|
||||
|
||||
@JsonProperty("batch_size")
|
||||
private Integer batchSize;
|
||||
|
||||
@JsonProperty("learning_rate_multiplier")
|
||||
private Double learningRateMultiplier;
|
||||
|
||||
@JsonProperty("prompt_loss_weight")
|
||||
@Builder.Default
|
||||
private Double promptLossWeight = 0.01;
|
||||
|
||||
@JsonProperty("compute_classification_metrics")
|
||||
@Builder.Default
|
||||
private boolean computeClassificationMetrics = false;
|
||||
|
||||
@JsonProperty("classification_n_classes")
|
||||
private Integer classificationNClasses;
|
||||
|
||||
@JsonProperty("classification_betas")
|
||||
private List classificationBetas;
|
||||
|
||||
private String suffix;
|
||||
|
||||
public void setTrainingFile(String trainingFile) {
|
||||
this.trainingFile = trainingFile;
|
||||
}
|
||||
|
||||
public void setValidationFile(String validationFile) {
|
||||
this.validationFile = validationFile;
|
||||
}
|
||||
|
||||
public void setModel(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public void setN_epochs(Integer n_epochs) {
|
||||
this.n_epochs = n_epochs;
|
||||
}
|
||||
|
||||
public void setBatchSize(Integer batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
}
|
||||
|
||||
public void setLearningRateMultiplier(Double learningRateMultiplier) {
|
||||
this.learningRateMultiplier = learningRateMultiplier;
|
||||
}
|
||||
|
||||
public void setPromptLossWeight(Double promptLossWeight) {
|
||||
this.promptLossWeight = promptLossWeight;
|
||||
}
|
||||
|
||||
public void setComputeClassificationMetrics(boolean computeClassificationMetrics) {
|
||||
this.computeClassificationMetrics = computeClassificationMetrics;
|
||||
}
|
||||
|
||||
public void setClassificationNClasses(Integer classificationNClasses) {
|
||||
this.classificationNClasses = classificationNClasses;
|
||||
}
|
||||
|
||||
public void setClassificationBetas(List classificationBetas) {
|
||||
this.classificationBetas = classificationBetas;
|
||||
}
|
||||
|
||||
public void setSuffix(String suffix) {
|
||||
if(Objects.nonNull(suffix) && !"".equals(suffix) && suffix.length() > 40){
|
||||
log.error("后缀长度不能大于40");
|
||||
throw new BaseException(CommonError.PARAM_ERROR.msg());
|
||||
}
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Model {
|
||||
// or a fine-tuned model created after 2022-04-21.
|
||||
ADA("ada"),
|
||||
BABBAGE("babbage"),
|
||||
CURIE("curie"),
|
||||
DAVINCI("davinci"),
|
||||
;
|
||||
private String name;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.aibidding.common.chat.entity.fineTune;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class FineTuneDeleteResponse implements Serializable {
|
||||
|
||||
private String id;
|
||||
|
||||
private String object;
|
||||
|
||||
private boolean deleted;
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package org.aibidding.common.chat.entity.fineTune;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class FineTuneResponse implements Serializable {
|
||||
|
||||
private String id;
|
||||
|
||||
private String object;
|
||||
|
||||
private String model;
|
||||
|
||||
@JsonProperty("created_at")
|
||||
private long createdAt;
|
||||
|
||||
private List<Event> events;
|
||||
|
||||
@JsonProperty("fine_tuned_model")
|
||||
private String fineTunedModel;
|
||||
|
||||
@JsonProperty("hyperparams")
|
||||
private HyperParam hyperParams;
|
||||
|
||||
@JsonProperty("organization_id")
|
||||
private String organizationId;
|
||||
|
||||
@JsonProperty("result_files")
|
||||
private List resultFiles;
|
||||
|
||||
private String status;
|
||||
|
||||
@JsonProperty("validation_files")
|
||||
private List validationFiles;
|
||||
|
||||
@JsonProperty("training_files")
|
||||
private List<TrainingFile> trainingFiles;
|
||||
|
||||
@JsonProperty("updated_at")
|
||||
private long updatedAt;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package org.aibidding.common.chat.entity.fineTune;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class HyperParam implements Serializable {
|
||||
|
||||
@JsonProperty("batch_size")
|
||||
private Integer batchSize;
|
||||
@JsonProperty("learning_rate_multiplier")
|
||||
private Double learningRateMultiplier;
|
||||
@JsonProperty("n_epochs")
|
||||
private Integer nEpochs;
|
||||
@JsonProperty("prompt_loss_weight")
|
||||
private Double promptLossWeight;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.aibidding.common.chat.entity.fineTune;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class TrainingFile implements Serializable {
|
||||
|
||||
private String id;
|
||||
private String object;
|
||||
private long bytes;
|
||||
@JsonProperty("created_at")
|
||||
private long createdAt;
|
||||
private String filename;
|
||||
private String purpose;
|
||||
private String status;
|
||||
@JsonProperty("status_details")
|
||||
private String statusDetails;
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package org.aibidding.common.chat.entity.images;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Getter
|
||||
@Slf4j
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Image implements Serializable {
|
||||
|
||||
/**
|
||||
* 提示词:dall-e-2支持1000字符、dall-e-3支持4000字符
|
||||
*/
|
||||
private String prompt;
|
||||
/**
|
||||
* 支持dall-e-2、dall-e-3
|
||||
*
|
||||
* @see Model
|
||||
*/
|
||||
@Builder.Default
|
||||
private String model = Model.DALL_E_3.getName();
|
||||
|
||||
/**
|
||||
* 此参数仅仅dall-e-3,默认值:standard
|
||||
*
|
||||
* @see Quality
|
||||
*/
|
||||
private String quality;
|
||||
|
||||
/**
|
||||
* 为每个提示生成的个数,dall-e-3只能为1。
|
||||
*/
|
||||
private Integer n;
|
||||
/**
|
||||
* 图片尺寸,默认值:1024x1024
|
||||
* dall-e-2支持:256x256, 512x512, or 1024x1024
|
||||
* dall-e-3支持:1024x1024, 1792x1024, or 1024x1792
|
||||
*
|
||||
* @see SizeEnum
|
||||
*/
|
||||
private String size;
|
||||
/**
|
||||
* 此参数仅仅dall-e-3,取值范围:vivid、natural
|
||||
* 默认值:vivid
|
||||
*
|
||||
* @see Style
|
||||
*/
|
||||
private String style;
|
||||
|
||||
/**
|
||||
* 生成图片格式:url、b64_json
|
||||
*
|
||||
* @see ResponseFormat
|
||||
*/
|
||||
@JsonProperty("response_format")
|
||||
private String responseFormat;
|
||||
|
||||
private String user;
|
||||
|
||||
/**
|
||||
* 图片生成模型
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Model {
|
||||
DALL_E_2("dall-e-2"),
|
||||
DALL_E_3("dall-e-3"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成图片质量
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Quality {
|
||||
STANDARD("standard"),
|
||||
HD("hd"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成图片风格
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Style {
|
||||
VIVID("vivid"),
|
||||
NATURAL("natural"),
|
||||
;
|
||||
private final String name;
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package org.aibidding.common.chat.entity.images;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aibidding.common.chat.openai.exception.CommonError;
|
||||
import org.aibidding.common.core.exception.base.BaseException;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Getter
|
||||
@Slf4j
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ImageEdit implements Serializable {
|
||||
/**
|
||||
* 必选项:描述文字,最多1000字符
|
||||
*/
|
||||
@NonNull
|
||||
private String prompt;
|
||||
/**
|
||||
* 为每个提示生成的完成次数。
|
||||
*/
|
||||
@Builder.Default
|
||||
private Integer n = 1;
|
||||
/**
|
||||
* 256x256
|
||||
* 512x512
|
||||
* 1024x1024
|
||||
*/
|
||||
@Builder.Default
|
||||
private String size = SizeEnum.size_512.getName();
|
||||
|
||||
@JsonProperty("response_format")
|
||||
@Builder.Default
|
||||
private String responseFormat = ResponseFormat.URL.getName();
|
||||
|
||||
private String user;
|
||||
|
||||
public ImageEdit setN(Integer n) {
|
||||
if(n < 1){
|
||||
log.warn("n最小值1");
|
||||
n = 1;
|
||||
}
|
||||
if(n > 10){
|
||||
log.warn("n最大值10");
|
||||
n = 10;
|
||||
}
|
||||
this.n = n;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageEdit setPrompt(String prompt) {
|
||||
if(Objects.isNull(prompt) || "".equals(prompt)){
|
||||
log.error("参数异常");
|
||||
throw new BaseException(CommonError.PARAM_ERROR.msg());
|
||||
}
|
||||
if(prompt.length() > 1000){
|
||||
log.error("长度超过1000");
|
||||
throw new BaseException(CommonError.PARAM_ERROR.msg());
|
||||
}
|
||||
this.prompt = prompt;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageEdit setSize(SizeEnum size) {
|
||||
if(Objects.isNull(size)){
|
||||
size = SizeEnum.size_512;
|
||||
}
|
||||
this.size = size.getName();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageEdit setResponseFormat(ResponseFormat responseFormat) {
|
||||
if(Objects.isNull(responseFormat)){
|
||||
responseFormat = ResponseFormat.URL;
|
||||
}
|
||||
this.responseFormat = responseFormat.getName();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageEdit setUser(String user) {
|
||||
this.user = user;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package org.aibidding.common.chat.entity.images;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ImageResponse implements Serializable {
|
||||
private long created;
|
||||
private List<Item> data;
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package org.aibidding.common.chat.entity.images;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Getter
|
||||
@Slf4j
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ImageVariations implements Serializable {
|
||||
/**
|
||||
* 为每个提示生成的完成次数。
|
||||
*/
|
||||
@Builder.Default
|
||||
private Integer n = 1;
|
||||
/**
|
||||
* 256x256
|
||||
* 512x512
|
||||
* 1024x1024
|
||||
*/
|
||||
@Builder.Default
|
||||
private String size = SizeEnum.size_512.getName();
|
||||
|
||||
@JsonProperty("response_format")
|
||||
@Builder.Default
|
||||
private String responseFormat = ResponseFormat.URL.getName();
|
||||
|
||||
private String user;
|
||||
|
||||
|
||||
public void setN(Integer n) {
|
||||
if (n < 1) {
|
||||
log.warn("n最小值1");
|
||||
this.n = 1;
|
||||
return;
|
||||
}
|
||||
if (n > 10) {
|
||||
log.warn("n最大值10");
|
||||
this.n = 10;
|
||||
return;
|
||||
}
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
|
||||
public void setSize(SizeEnum size) {
|
||||
if (Objects.isNull(size)) {
|
||||
size = SizeEnum.size_512;
|
||||
}
|
||||
this.size = size.getName();
|
||||
}
|
||||
|
||||
public void setResponseFormat(ResponseFormat responseFormat) {
|
||||
if (Objects.isNull(responseFormat)) {
|
||||
responseFormat = ResponseFormat.URL;
|
||||
}
|
||||
this.responseFormat = responseFormat.getName();
|
||||
}
|
||||
|
||||
public void setUser(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package org.aibidding.common.chat.entity.images;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Item implements Serializable {
|
||||
private String url;
|
||||
@JsonProperty("b64_json")
|
||||
private String b64Json;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package org.aibidding.common.chat.entity.images;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum ResponseFormat implements Serializable {
|
||||
URL("url"),
|
||||
B64_JSON("b64_json"),
|
||||
;
|
||||
|
||||
private String name;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.aibidding.common.chat.entity.images;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SizeEnum implements Serializable {
|
||||
size_1024_1792("1024x1792"),
|
||||
size_1792_1024("1792x1024"),
|
||||
size_1024("1024x1024"),
|
||||
size_512("512x512"),
|
||||
size_256("256x256"),
|
||||
|
||||
;
|
||||
private String name;
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user