Compare commits
453 Commits
v2.0.1
...
fdddec2f14
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdddec2f14 | ||
|
|
57e23be82f | ||
|
|
89f4976b7c | ||
|
|
a0d93b1ca8 | ||
|
|
ca8ba6fe48 | ||
|
|
7994704c11 | ||
|
|
8d4fadc9a2 | ||
|
|
bd8dccf7b2 | ||
|
|
584cead6bf | ||
|
|
a52529eefd | ||
|
|
6e433237e0 | ||
|
|
abd4f01b69 | ||
|
|
5c430ee1d2 | ||
|
|
e23e295d68 | ||
|
|
3d6bbad616 | ||
|
|
5088c0e6d7 | ||
|
|
2995b6ddde | ||
|
|
5475776caa | ||
|
|
08d4977263 | ||
|
|
31602cb85e | ||
|
|
5adc5f0006 | ||
|
|
307d095cf1 | ||
|
|
2cef4e17dc | ||
|
|
b47da3f438 | ||
|
|
827ac48826 | ||
|
|
f906645708 | ||
|
|
c17e16dd0f | ||
|
|
837236f1cc | ||
|
|
60793b957a | ||
|
|
fa4dc87e76 | ||
|
|
4ac63c3268 | ||
|
|
54e7999fe3 | ||
|
|
32fd910584 | ||
|
|
25e659dffa | ||
|
|
585e5ff0f8 | ||
|
|
bd346f1e85 | ||
|
|
2caf9a47ed | ||
|
|
f10f44158c | ||
|
|
76acd4a40b | ||
|
|
6467af1d73 | ||
|
|
35146f3495 | ||
|
|
9e23587fb1 | ||
|
|
a61bd57e22 | ||
|
|
6bb7bc6eb5 | ||
|
|
3f9e83a767 | ||
|
|
0d711b1842 | ||
|
|
a33159f9a3 | ||
|
|
6462752fd6 | ||
|
|
afc1272ff5 | ||
|
|
fa5dc80a93 | ||
|
|
acc2d5d1a8 | ||
|
|
c22b9fdb9c | ||
|
|
2a45776aeb | ||
|
|
ff0a3d1016 | ||
|
|
b2a589ed9c | ||
|
|
13da60e151 | ||
|
|
1f0c0ba0a9 | ||
|
|
ef3541fe77 | ||
|
|
2b5fd810a4 | ||
|
|
4a8d21a742 | ||
|
|
c62530176f | ||
|
|
c7554d7e35 | ||
|
|
1e4af3d01b | ||
|
|
1e3b49c9b8 | ||
|
|
9f7f00e50c | ||
|
|
1c721981db | ||
|
|
6e6ba84fd2 | ||
|
|
ef69778bb7 | ||
|
|
7a374d877b | ||
|
|
43426054ec | ||
|
|
ccdbb20935 | ||
|
|
4b37cfe97d | ||
|
|
c43d4784de | ||
|
|
359cee28d5 | ||
|
|
aa11c1f233 | ||
|
|
a0d029c142 | ||
|
|
6ce52befe2 | ||
|
|
330bdc3761 | ||
|
|
4f7ad59e46 | ||
|
|
b696fde881 | ||
|
|
00f9a1a55b | ||
|
|
a1c7b86e72 | ||
|
|
62676a54fb | ||
|
|
e51425a951 | ||
|
|
268be2d9ec | ||
|
|
f448a18e44 | ||
|
|
22e59fe5a1 | ||
|
|
0780e3b8c9 | ||
|
|
0cdba56a07 | ||
|
|
ebc13c06af | ||
|
|
416f011c73 | ||
|
|
bfeb389171 | ||
|
|
caf7f14781 | ||
|
|
a6eb98daab | ||
|
|
4834b615a6 | ||
|
|
42aabeed96 | ||
|
|
67303cf5be | ||
|
|
5bd95b496a | ||
|
|
8fcaa7c90c | ||
|
|
27398c1000 | ||
|
|
bd9ffb10a9 | ||
|
|
bb9c85ac3c | ||
|
|
70ca78d935 | ||
|
|
1af8c4ee50 | ||
|
|
b9276c5dcc | ||
|
|
d1e98a2001 | ||
|
|
baf065a294 | ||
|
|
842a39d6d2 | ||
|
|
9fba91c35f | ||
|
|
498135b7fd | ||
|
|
c3ab13ae67 | ||
|
|
1638b9dd75 | ||
|
|
4434d8346c | ||
|
|
119483df86 | ||
|
|
98f7e3ada2 | ||
|
|
50d9e0e843 | ||
|
|
2871cf7630 | ||
|
|
07cb351807 | ||
|
|
951ee6bd8a | ||
|
|
5b6605c345 | ||
|
|
5db116ec88 | ||
|
|
645c754dd0 | ||
|
|
8751bb5104 | ||
|
|
8d0c557bdb | ||
|
|
5ac785c570 | ||
|
|
60145f9291 | ||
|
|
d7b89cd1b3 | ||
|
|
5264b47c2f | ||
|
|
e9cd9e84d4 | ||
|
|
b52f7a7112 | ||
|
|
2abdf762c1 | ||
|
|
099c94e3cb | ||
|
|
affdc5e3a6 | ||
|
|
047044eb06 | ||
|
|
7108727395 | ||
|
|
d3732a155d | ||
|
|
a0db91ebe6 | ||
|
|
e83d70e9c3 | ||
|
|
5eb166839a | ||
|
|
e27a6cb738 | ||
|
|
d964e86b23 | ||
|
|
86d7eab5b5 | ||
|
|
fa5ad8caf6 | ||
|
|
e5011e0dd9 | ||
|
|
5fe8bd7706 | ||
|
|
0f28e1f3f6 | ||
|
|
503f86644e | ||
|
|
579beb6833 | ||
|
|
22c0c733f6 | ||
|
|
9f4a2256b4 | ||
|
|
5a4d76ac09 | ||
|
|
5a2e08f87d | ||
|
|
838a393abc | ||
|
|
210a9d9b14 | ||
|
|
66518925c1 | ||
|
|
19d3f018b8 | ||
|
|
450ec6db44 | ||
|
|
0bb897de1f | ||
|
|
ab9ff52200 | ||
|
|
d94bcf250e | ||
|
|
10708b7625 | ||
|
|
5e032a68d5 | ||
|
|
bd41ff0f28 | ||
|
|
3ffba456f4 | ||
|
|
993346534e | ||
|
|
38169ba90d | ||
|
|
b003e1b3bb | ||
|
|
f36dda74a1 | ||
|
|
c609095c69 | ||
|
|
93e34b3f03 | ||
|
|
cc4ca69640 | ||
|
|
85930f4b12 | ||
|
|
3c19a2b7a4 | ||
|
|
21c390c4d6 | ||
|
|
cdef9e1c89 | ||
|
|
3c60f43daa | ||
|
|
a24fa7a2b4 | ||
|
|
21f8462ebb | ||
|
|
897222c41c | ||
|
|
227670df9d | ||
|
|
6b2cf1a3c3 | ||
|
|
37f832c31c | ||
|
|
25cf1f9744 | ||
|
|
a48178685c | ||
|
|
7e60cb357f | ||
|
|
915a393427 | ||
|
|
de323d8c45 | ||
|
|
ffe4867d40 | ||
|
|
8b3c0b4134 | ||
|
|
999282210e | ||
|
|
a99344813f | ||
|
|
63ec00cd71 | ||
|
|
7eebd87cc8 | ||
|
|
9a816bb0c7 | ||
|
|
bc6ed508b0 | ||
|
|
d64abaaed3 | ||
|
|
285aa2ae62 | ||
|
|
99114d3301 | ||
|
|
e857f0345b | ||
|
|
138fa5f0e9 | ||
|
|
241c6dc57a | ||
|
|
6005339ec8 | ||
|
|
db892d35fb | ||
|
|
605b223985 | ||
|
|
e117ec8e27 | ||
|
|
5e8db861ea | ||
|
|
fa2791e2e3 | ||
|
|
f1f7cb1084 | ||
|
|
acb1f27c37 | ||
|
|
e46245d97d | ||
|
|
0eff37fa51 | ||
|
|
c1a178c0be | ||
|
|
94d4446321 | ||
|
|
d7930ad713 | ||
|
|
48270add01 | ||
|
|
3786644a25 | ||
|
|
53532681d3 | ||
|
|
daa7b7315b | ||
|
|
df3b687be4 | ||
|
|
ecb5ef32fc | ||
|
|
e5116472ed | ||
|
|
e58aeb5361 | ||
|
|
b4306289f0 | ||
|
|
d9c47bd983 | ||
|
|
8ddbb43dde | ||
|
|
dfe8c7dc85 | ||
|
|
fd94a1772f | ||
|
|
c105d47d99 | ||
|
|
4e2ec2dc82 | ||
|
|
614280d8ea | ||
|
|
2fae8d0ad0 | ||
|
|
d7c2d1bcf3 | ||
|
|
122f63dfbd | ||
|
|
719e968192 | ||
|
|
bf790ceb51 | ||
|
|
de5488bd8c | ||
|
|
c77a245a4d | ||
|
|
6dcd8823cd | ||
|
|
8be480e06c | ||
|
|
11286de676 | ||
|
|
5aaf0a672c | ||
|
|
0089706336 | ||
|
|
cc129801b9 | ||
|
|
6a73e09ac7 | ||
|
|
e1dc22348c | ||
|
|
f37e4da669 | ||
|
|
3e097d9a68 | ||
|
|
97ae5a46cd | ||
|
|
baa664ac4f | ||
|
|
353fbf26b8 | ||
|
|
f79b4ec012 | ||
|
|
0a73cb4e17 | ||
|
|
cbe882af66 | ||
|
|
1d51a103d0 | ||
|
|
d635e30b4a | ||
|
|
ca50d1ddfb | ||
|
|
bd94a3eae8 | ||
|
|
fcdcf534f1 | ||
|
|
deefb6cc0b | ||
|
|
fa96c3d12f | ||
|
|
77069fdecd | ||
|
|
db4a264a52 | ||
|
|
70ae7ea8f1 | ||
|
|
6a93856d90 | ||
|
|
71cae94815 | ||
|
|
a2905d08f9 | ||
|
|
463ad6c583 | ||
|
|
abcde9e36e | ||
|
|
8e723f5b78 | ||
|
|
2021fb5071 | ||
|
|
ecbab7df7b | ||
|
|
d6fcaa0a11 | ||
|
|
58faded4ff | ||
|
|
7cc7af70f0 | ||
|
|
4312a729a2 | ||
|
|
5d972d66f4 | ||
|
|
1bff2791a6 | ||
|
|
a76769e540 | ||
|
|
bedffffd86 | ||
|
|
2884c37599 | ||
|
|
c25749c9ca | ||
|
|
147b3fd8f5 | ||
|
|
373424bd01 | ||
|
|
287a0b3d70 | ||
|
|
cd7e07bea6 | ||
|
|
7edfae09bc | ||
|
|
a1759ddf5a | ||
|
|
5517a5d19b | ||
|
|
8fb72ba4fe | ||
|
|
24511fac8f | ||
|
|
ce9f2a82da | ||
|
|
0f82711199 | ||
|
|
b81fb7cb3f | ||
|
|
676a63c0d6 | ||
|
|
427736271c | ||
|
|
c39dd7a917 | ||
|
|
ed85fef0de | ||
|
|
22d9d9ba85 | ||
|
|
86825eeb2e | ||
|
|
c491a98dc7 | ||
|
|
2a4978c668 | ||
|
|
5b4eeee756 | ||
|
|
53e3180658 | ||
|
|
e43e14454d | ||
|
|
93ddcd53b1 | ||
|
|
0ee47a5c00 | ||
|
|
3ceef41ab0 | ||
|
|
a4e995d46c | ||
|
|
57693059a1 | ||
|
|
d18e307e10 | ||
|
|
eed708c6d3 | ||
|
|
1093888889 | ||
|
|
e58a420f9f | ||
|
|
4a0c3d132a | ||
|
|
0d81aa640e | ||
|
|
951524bff7 | ||
|
|
c7d0e9337a | ||
|
|
6955f3c7dc | ||
|
|
a52b017e1a | ||
|
|
158a0190b5 | ||
|
|
096fc11313 | ||
|
|
e9ac795d23 | ||
|
|
32f1a6bab1 | ||
|
|
052069a2df | ||
|
|
e1c997883f | ||
|
|
031b7da198 | ||
|
|
931af963b1 | ||
|
|
f5fa7d5da8 | ||
|
|
c6ffbcb3cf | ||
|
|
05ae200ff5 | ||
|
|
e745f772ef | ||
|
|
584212c569 | ||
|
|
dc9bf3e25d | ||
|
|
da84a26c47 | ||
|
|
7d3282c347 | ||
|
|
4454be44c3 | ||
|
|
52e0feda01 | ||
|
|
c89f5d07fb | ||
|
|
778a7bc21b | ||
|
|
50f5f38996 | ||
|
|
32da85daab | ||
|
|
3666157d14 | ||
|
|
1a178d0ef8 | ||
|
|
b64b758263 | ||
|
|
a68c6481ba | ||
|
|
3cbacb5ed9 | ||
|
|
38667797d3 | ||
|
|
9a6acb84a4 | ||
|
|
e3c8a84849 | ||
|
|
cc349f5954 | ||
|
|
e4b78e0510 | ||
|
|
15c6cd272e | ||
|
|
1614eff008 | ||
|
|
c86e88ebd1 | ||
|
|
39ebd85f58 | ||
|
|
bde82fe516 | ||
|
|
2ca650db76 | ||
|
|
e3da640737 | ||
|
|
e1dea1d9e2 | ||
|
|
84b8d6f675 | ||
|
|
8563428bf9 | ||
|
|
7b3b727c0e | ||
|
|
08098ff3f3 | ||
|
|
fb492d41f3 | ||
|
|
9c2586ab43 | ||
|
|
1bddf5df3b | ||
|
|
57b2f833f8 | ||
|
|
7907cbeb7f | ||
|
|
9cfcdd2b9b | ||
|
|
980df20752 | ||
|
|
aa92d232bb | ||
|
|
81c0bb5738 | ||
|
|
1a645c6e10 | ||
|
|
731f6ceb6e | ||
|
|
8e21245348 | ||
|
|
936e157e4a | ||
|
|
256f72c487 | ||
|
|
009aa5f1a5 | ||
|
|
d22d2cb708 | ||
|
|
59104028b6 | ||
|
|
c2f6a8321a | ||
|
|
5476a4b0b7 | ||
|
|
cd490aa0e5 | ||
|
|
b1ff44df4b | ||
|
|
dc6d00f0fc | ||
|
|
990da8da6f | ||
|
|
8fc7ad0359 | ||
|
|
8a89d9eb9c | ||
|
|
abfa9ae97b | ||
|
|
bde2e8ff8e | ||
|
|
4d8eb1850f | ||
|
|
5aaa3a5662 | ||
|
|
8fec96f5b2 | ||
|
|
15c306eca2 | ||
|
|
620ea1fc76 | ||
|
|
c5c375dc6d | ||
|
|
1b793e822a | ||
|
|
6281840f36 | ||
|
|
f5daa7eb78 | ||
|
|
52cb563383 | ||
|
|
69efc3261e | ||
|
|
fb19fb29cc | ||
|
|
9f257cf712 | ||
|
|
4af26fe4b4 | ||
|
|
ab2a118ee9 | ||
|
|
9cd97a4dc5 | ||
|
|
788b372e32 | ||
|
|
744f9b6c7f | ||
|
|
761d954ef1 | ||
|
|
d1006f50ad | ||
|
|
f24ff5bbdd | ||
|
|
a4314dbbde | ||
|
|
188dc1e55e | ||
|
|
731352fd04 | ||
|
|
4b53939002 | ||
|
|
b50c15755d | ||
|
|
0dc6262b39 | ||
|
|
9b32e3b3b2 | ||
|
|
37a8b7dad3 | ||
|
|
efeb0bd6fb | ||
|
|
af33040117 | ||
|
|
ac4c037634 | ||
|
|
9734ec53f7 | ||
|
|
2b8a92c7d6 | ||
|
|
adb4538317 | ||
|
|
2509099146 | ||
|
|
3be9005f95 | ||
|
|
be6d027cad | ||
|
|
3d679f8749 | ||
|
|
5a5a48e153 | ||
|
|
e5da648941 | ||
|
|
d2755f00bc | ||
|
|
09abc0b5af | ||
|
|
00f362acf1 | ||
|
|
65d479458e | ||
|
|
57e17e0dda | ||
|
|
691d1735fc | ||
|
|
360984bc4b | ||
|
|
0153f004f4 | ||
|
|
cc23508527 | ||
|
|
c884f4f2d3 | ||
|
|
fab6de1f5c | ||
|
|
c02f66636d | ||
|
|
c1162148b1 | ||
|
|
f76fdbf3ad | ||
|
|
feca08b3ec | ||
|
|
72675b17c4 | ||
|
|
9ea5186f49 | ||
|
|
d0a2eadc38 | ||
|
|
ae141a6591 | ||
|
|
d3f4d7b8ca | ||
|
|
b8e7a406d3 | ||
|
|
412e8bdc10 |
7
.gitignore
vendored
@@ -1,6 +1,9 @@
|
||||
######################################################################
|
||||
# Build Tools
|
||||
|
||||
|
||||
|
||||
|
||||
.gradle
|
||||
/build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
@@ -8,6 +11,10 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
ruoyi-modules/ruoyi-generator/src/main/resources/vm/vben5
|
||||
|
||||
README.md
|
||||
|
||||
######################################################################
|
||||
# IDE
|
||||
|
||||
|
||||
360
README.md
@@ -1,10 +1,6 @@
|
||||
|
||||
|
||||
# RuoYi AI
|
||||
|
||||
|
||||
|
||||
<!-- PROJECT SHIELDS -->
|
||||
<div align="center">
|
||||
|
||||
[![Contributors][contributors-shield]][contributors-url]
|
||||
[![Forks][forks-shield]][forks-url]
|
||||
@@ -13,216 +9,170 @@
|
||||
[![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 align="center">
|
||||
<a href="https://trendshift.io/repositories/13209">
|
||||
<img src="https://trendshift.io/api/badge/repositories/13209" alt="GitHub Trending">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## 目录
|
||||
|
||||
- [源码地址](#源码地址)
|
||||
- [特色功能](#特色功能)
|
||||
- [项目演示](#项目演示)
|
||||
- [后台管理](#后台管理)
|
||||
- [用户端](#用户端)
|
||||
- [小程序端](#小程序端)
|
||||
- [开发前的配置要求](#开发前的配置要求)
|
||||
- [文件目录说明](#文件目录说明)
|
||||
- [使用到的框架](#使用到的框架)
|
||||
- [贡献者](#贡献者)
|
||||
- [如何参与开源项目](#如何参与开源项目)
|
||||
- [版本控制](#版本控制)
|
||||
- [作者](#作者)
|
||||
- [鸣谢](#鸣谢)
|
||||
<img src="image/00.png" alt="RuoYi AI Logo" width="120" height="120">
|
||||
|
||||
### 源码地址
|
||||
- 项目文档: 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. 支付功能:支持易支付、微信支付等多种支付方式
|
||||
|
||||
### 项目演示
|
||||
### 企业级AI助手平台
|
||||
|
||||
*开箱即用的智能AI平台,深度集成 FastGPT、扣子(Coze)、DIFY 等主流AI平台,提供先进的RAG技术和多模型支持*
|
||||
|
||||
**[🇺🇸 English](README_EN.md)** | **[📖 使用文档](https://doc.pandarobot.chat)** | **[🚀 在线体验](https://web.pandarobot.chat)** | **[🐛 问题反馈](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 功能建议](https://github.com/ageerle/ruoyi-ai/issues)**
|
||||
|
||||
#### 后台管理
|
||||
<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>
|
||||
|
||||
## ✨ 核心亮点
|
||||
|
||||
### 🤖 智能AI引擎
|
||||
- **多模型接入**:支持 OpenAI GPT-4、Azure、ChatGLM、通义千问、智谱AI 等主流模型
|
||||
- **AI平台集成**:深度集成 **FastGPT**、**扣子(Coze)**、**DIFY** 等主流AI应用平台
|
||||
- **Spring AI MCP 集成**:基于模型上下文协议,打造可扩展的AI工具生态系统
|
||||
- **实时流式对话**:采用 SSE/WebSocket 技术,提供丝滑的对话体验
|
||||
- **AI 编程助手**:内置智能代码分析和项目脚手架生成能力
|
||||
|
||||
### 🌟 AI平台生态集成
|
||||
- **FastGPT 深度集成**:原生支持 FastGPT API,包括知识库检索、工作流编排和上下文管理
|
||||
- **扣子(Coze) 官方SDK**:集成字节跳动扣子平台官方SDK,支持Bot对话和流式响应
|
||||
- **DIFY 完整兼容**:使用 DIFY Java Client,支持应用编排、工作流和知识库管理
|
||||
- **统一聊天接口**:提供统一的聊天服务接口,支持多平台无缝切换和负载均衡
|
||||
|
||||
### 🧠 本地化RAG方案
|
||||
- **私有知识库**:基于 Langchain4j 框架 + BGE-large-zh-v1.5 中文向量模型
|
||||
- **多种向量库**:支持 Milvus、Weaviate、Qdrant 等主流向量数据库
|
||||
- **数据安全可控**:支持完全本地部署,保护企业数据隐私
|
||||
- **灵活模型部署**:兼容 Ollama、vLLM 等本地推理框架
|
||||
|
||||
### 🎨 AI创作工具
|
||||
- **AI 绘画创作**:深度集成 DALL·E-3、MidJourney、Stable Diffusion
|
||||
- **智能PPT生成**:一键将文本内容转换为精美演示文稿
|
||||
- **多模态理解**:支持文本、图片、文档等多种格式的智能处理
|
||||
|
||||
|
||||
|
||||
## 🚀 快速体验
|
||||
|
||||
### 在线演示
|
||||
- **用户端体验**:[web.pandarobot.chat](https://web.pandarobot.chat) (账号:demo 密码:demo123)
|
||||
- **管理后台**:[admin.pandarobot.chat](https://admin.pandarobot.chat) (账号:admin 密码:admin123)
|
||||
|
||||
### 项目源码
|
||||
| 项目模块 | GitHub 仓库 | Gitee 仓库 | GitCode 仓库 |
|
||||
|---------|------------|-----------|-------------|
|
||||
| 🔧 后端服务 | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) |
|
||||
| 🎨 用户前端 | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) |
|
||||
| 🛠️ 管理后台 | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
|
||||
|
||||
### 合作项目
|
||||
| 项目介绍 | GitHub 仓库 | Gitee 仓库 |
|
||||
|:--------:|:----------:|:----------:|
|
||||
| 前端简化版 | [ruoyi-element-ai](https://github.com/element-plus-x/ruoyi-element-ai) | [ruoyi-element-ai](https://gitee.com/he-jiayue/ruoyi-element-ai) |
|
||||
|
||||
|
||||
|
||||
|
||||
## 🛠️ 技术架构
|
||||
|
||||
### 🏗️ 核心框架
|
||||
- **后端架构**:Spring Boot 3.4 + Spring AI + Langchain4j
|
||||
- **数据存储**:MySQL 8.0 + Redis + 向量数据库(Milvus/Weaviate/Qdrant)
|
||||
- **前端技术**:Vue 3 + Vben Admin + Naive UI
|
||||
- **安全认证**:Sa-Token + JWT 双重保障
|
||||
|
||||
### 🔧 系统组件
|
||||
- **文档处理**:PDF、Word、Excel 解析,图像智能分析
|
||||
- **实时通信**:WebSocket 实时通信,SSE 流式响应
|
||||
- **系统监控**:完善的日志体系、性能监控、服务健康检查
|
||||
|
||||
## 📚 使用文档
|
||||
|
||||
想要深入了解安装部署、功能配置和二次开发?
|
||||
|
||||
**👉 [完整使用文档](https://doc.pandarobot.chat)**
|
||||
|
||||
## 🤝 参与贡献
|
||||
|
||||
我们热烈欢迎社区贡献!无论您是资深开发者还是初学者,都可以为项目贡献力量 💪
|
||||
|
||||
### 贡献方式
|
||||
1. **Fork** 项目到您的账户
|
||||
2. **创建分支** (`git checkout -b feature/新功能名称`)
|
||||
3. **提交代码** (`git commit -m '添加某某功能'`)
|
||||
4. **推送分支** (`git push origin feature/新功能名称`)
|
||||
5. **发起 Pull Request**
|
||||
|
||||
> 💡 **小贴士**:建议将 PR 提交到 GitHub,我们会自动同步到其他代码托管平台
|
||||
|
||||
<a href="https://openomy.com/ageerle/ruoyi-ai" target="_blank" style="display: block; width: 100%;" align="center">
|
||||
<img src="https://openomy.com/svg?repo=ageerle/ruoyi-ai&chart=bubble&latestMonth=3" target="_blank" alt="Contribution Leaderboard" style="display: block; width: 100%;" />
|
||||
</a>
|
||||
|
||||
## 📄 开源协议
|
||||
|
||||
本项目采用 **MIT 开源协议**,详情请查看 [LICENSE](LICENSE) 文件。
|
||||
|
||||
## 🙏 特别鸣谢
|
||||
|
||||
感谢以下优秀的开源项目为本项目提供支持:
|
||||
|
||||
- [Spring AI Alibaba Copilot](https://github.com/springaialibaba/spring-ai-alibaba-copilot) - 基于spring-ai-alibaba 的智能编码助手
|
||||
- [Spring AI](https://spring.io/projects/spring-ai) - Spring 官方 AI 集成框架
|
||||
- [Langchain4j](https://github.com/langchain4j/langchain4j) - 强大的 Java LLM 开发框架
|
||||
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - 成熟的企业级快速开发框架
|
||||
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - 现代化的 Vue 后台管理模板
|
||||
- [chatgpt-java](https://github.com/Grt1228/chatgpt-java) - 优秀的 ChatGPT Java SDK
|
||||
|
||||
## 🌐 生态伙伴
|
||||
|
||||
- [PPIO 派欧云](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - 提供高性价比的 GPU 算力和模型 API 服务
|
||||
- [优云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_ruoyi) - 万卡RTX40系GPU+海内外主流模型API服务,秒级响应,按量计费,新客免费用。
|
||||
- [胜算云](https://www.shengsuanyun.com/?from=CH_3WG71ZOS) - AI模型算力聚合超市云服务。
|
||||
|
||||
## 💬 社区交流
|
||||
|
||||
<div align="center">
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="image/wx.png" alt="微信二维码" width="200" height="200"><br>
|
||||
<strong>扫码添加作者微信</strong><br>
|
||||
<em>邀请进群学习</em>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="image/qq.png" alt="QQ群二维码" width="200" height="200"><br>
|
||||
<strong>QQ技术交流群</strong><br>
|
||||
<em>技术讨论</em>
|
||||
</td>
|
||||
|
||||
<td align="center">
|
||||
<img width="200" height="200" alt="95e8b1b3baeadbd24650bfb974ca5a58" src="https://github.com/user-attachments/assets/2a346218-6388-484d-aa75-6e98942193f7" /><br>
|
||||
<strong>微信技术交流群</strong><br>
|
||||
<em>技术讨论</em>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
#### 用户端
|
||||
<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 align="center">
|
||||
|
||||
**[⭐ 点个Star支持一下](https://github.com/ageerle/ruoyi-ai)** • **[🍴 Fork 开始贡献](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 English](README_EN.md)** • **[📖 查看完整文档](https://doc.pandarobot.chat)**
|
||||
|
||||
*用 ❤️ 打造,由 RuoYi AI 开源社区维护*
|
||||
|
||||
</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
|
||||
<!-- Badge Links -->
|
||||
[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
|
||||
@@ -230,10 +180,6 @@ RuoYi-AI
|
||||
[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
|
||||
[issues-url]: https://github.com/ageerle/ruoyi-ai/issues
|
||||
[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
|
||||
|
||||
|
||||
|
||||
[license-url]: https://github.com/ageerle/ruoyi-ai/blob/main/LICENSE
|
||||
|
||||
167
README_EN.md
Normal file
@@ -0,0 +1,167 @@
|
||||
|
||||
# RuoYi AI
|
||||
|
||||
<div align="center">
|
||||
|
||||
[![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]
|
||||
|
||||
<img src="image/00.png" alt="RuoYi AI Logo" width="120" height="120">
|
||||
|
||||
### Enterprise-Grade AI Assistant Platform
|
||||
|
||||
*Production-ready AI platform with deep integration of FastGPT, Coze, DIFY and advanced RAG technology*
|
||||
|
||||
**[📖 中文文档](README.md)** | **[📚 Documentation](https://doc.pandarobot.chat)** | **[🚀 Live Demo](https://web.pandarobot.chat)** | **[🐛 Report Bug](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 Request Feature](https://github.com/ageerle/ruoyi-ai/issues)**
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## ✨ Key Features
|
||||
|
||||
### 🤖 Advanced AI Engine
|
||||
- **Multi-Model Support**: OpenAI GPT-4, Azure, ChatGLM, Qwen, ZhipuAI
|
||||
- **AI Platform Integration**: Deep integration with **FastGPT**, **Coze**, **DIFY** and other leading AI platforms
|
||||
- **Spring AI MCP Integration**: Extensible tool ecosystem with Model Context Protocol
|
||||
- **Streaming Chat**: Real-time SSE/WebSocket communication
|
||||
- **AI Copilot**: Intelligent code analysis and project scaffolding
|
||||
|
||||
### 🌟 AI Platform Ecosystem
|
||||
- **FastGPT Deep Integration**: Native FastGPT API support with knowledge base retrieval, workflow orchestration and context management
|
||||
- **Coze Official SDK**: Integration with ByteDance Coze platform official SDK, supporting Bot conversations and streaming responses
|
||||
- **DIFY Full Compatibility**: Using DIFY Java Client for app orchestration, workflows and knowledge base management
|
||||
- **Unified Chat Interface**: Standardized chat service interface supporting seamless platform switching and load balancing
|
||||
|
||||
### 🧠 Enterprise RAG Solution
|
||||
- **Local Knowledge Base**: Langchain4j + BGE-large-zh-v1.5 embeddings
|
||||
- **Vector Database Support**: Milvus, Weaviate, Qdrant
|
||||
- **Privacy-First**: On-premise deployment with local LLM support
|
||||
- **Ollama & vLLM Compatible**: Flexible model deployment options
|
||||
|
||||
### 🎨 Creative AI Tools
|
||||
- **AI Art Generation**: DALL·E-3, MidJourney, Stable Diffusion integration
|
||||
- **PPT Creation**: Automated slide generation from text input
|
||||
- **Multi-Modal Processing**: Text, image, and document understanding
|
||||
|
||||
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Live Demo
|
||||
- **User Portal**: [web.pandarobot.chat](https://web.pandarobot.chat) (demo/demo123)
|
||||
- **Admin Panel**: [admin.pandarobot.chat](https://admin.pandarobot.chat) (admin/admin123)
|
||||
|
||||
### Source Code
|
||||
| Component | GitHub | Gitee | GitCode |
|
||||
|-----------|--------|-------|---------|
|
||||
| Backend API | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) |
|
||||
| User Frontend | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) |
|
||||
| Admin Frontend | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
|
||||
|
||||
### Collaborative Projects
|
||||
| Project Description | GitHub Repository | Gitee Repository |
|
||||
|:-------------------:|:-----------------:|:----------------:|
|
||||
| Simplified Frontend | [ruoyi-element-ai](https://github.com/element-plus-x/ruoyi-element-ai) | [ruoyi-element-ai](https://gitee.com/he-jiayue/ruoyi-element-ai) |
|
||||
|
||||
|
||||
## 🛠️ Tech Stack
|
||||
|
||||
### Core Framework
|
||||
- **Backend**: Spring Boot 3.4, Spring AI, Langchain4j
|
||||
- **Database**: MySQL 8.0, Redis, Vector Databases (Milvus/Weaviate/Qdrant)
|
||||
- **Frontend**: Vue 3, Vben Admin, Naive UI
|
||||
- **Authentication**: Sa-Token, JWT
|
||||
|
||||
### System Components
|
||||
- **File Processing**: PDF, Word, Excel parsing, intelligent image analysis
|
||||
- **Real-time Communication**: WebSocket real-time communication, SSE streaming
|
||||
- **System Monitoring**: Comprehensive logging, performance monitoring, health checks
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
For detailed setup, configuration, and development guides, visit our comprehensive documentation:
|
||||
|
||||
**[📖 Official Documentation](https://doc.pandarobot.chat)**
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We welcome contributions from developers of all skill levels! Whether you're fixing bugs, adding features, or improving documentation, your help is appreciated.
|
||||
|
||||
### How to Contribute
|
||||
1. Fork the repository
|
||||
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
||||
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
||||
4. Push to the branch (`git push origin feature/amazing-feature`)
|
||||
5. Open a Pull Request
|
||||
|
||||
*Please submit PRs to GitHub - they will be synchronized to other platforms automatically.*
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
Special thanks to these amazing open source projects:
|
||||
|
||||
- [Spring AI Alibaba Copilot](https://github.com/springaialibaba/spring-ai-alibaba-copilot) - Intelligent coding assistant based on spring-ai-alibaba with MCP protocol integration for project analysis and code generation
|
||||
- [Spring AI](https://spring.io/projects/spring-ai) - Spring's AI integration framework
|
||||
- [Langchain4j](https://github.com/langchain4j/langchain4j) - Java LLM framework
|
||||
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - Enterprise development framework
|
||||
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - Vue admin template
|
||||
- [chatgpt-java](https://github.com/Grt1228/chatgpt-java) - ChatGPT Java SDK
|
||||
|
||||
## 🌐 Ecosystem Partners
|
||||
|
||||
- [PPIO Cloud](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - Cost-effective GPU containers and model APIs
|
||||
|
||||
## 💬 Community
|
||||
|
||||
<div align="center">
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="image/wx.png" alt="WeChat" width="200" height="200"><br>
|
||||
<strong>Add Author WeChat</strong><br>
|
||||
<em>Scan to join learning group</em>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="image/qq.png" alt="QQ Group" width="200" height="200"><br>
|
||||
<strong>QQ Group</strong><br>
|
||||
<em>Technical discussion</em>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**[⭐ Star this repo](https://github.com/ageerle/ruoyi-ai)** • **[🍴 Fork it](https://github.com/ageerle/ruoyi-ai/fork)** • **[📖 中文文档](README.md)** • **[📚 Documentation](https://doc.pandarobot.chat)**
|
||||
|
||||
*Built with ❤️ by the RuoYi AI community*
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Badge Links -->
|
||||
[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://github.com/ageerle/ruoyi-ai/issues
|
||||
[license-shield]: https://img.shields.io/github/license/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
[license-url]: https://github.com/ageerle/ruoyi-ai/blob/main/LICENSE
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
image/01.png
|
Before Width: | Height: | Size: 232 KiB |
BIN
image/02.png
|
Before Width: | Height: | Size: 329 KiB |
BIN
image/03.png
|
Before Width: | Height: | Size: 123 KiB |
BIN
image/04.png
|
Before Width: | Height: | Size: 127 KiB |
BIN
image/05.png
|
Before Width: | Height: | Size: 129 KiB |
BIN
image/06.png
|
Before Width: | Height: | Size: 284 KiB |
BIN
image/07.png
|
Before Width: | Height: | Size: 674 KiB |
BIN
image/08.png
|
Before Width: | Height: | Size: 35 KiB |
BIN
image/09.png
|
Before Width: | Height: | Size: 100 KiB |
BIN
image/10.png
|
Before Width: | Height: | Size: 65 KiB |
BIN
image/11.png
|
Before Width: | Height: | Size: 26 KiB |
BIN
image/12.png
|
Before Width: | Height: | Size: 95 KiB |
BIN
image/13.png
|
Before Width: | Height: | Size: 136 KiB |
BIN
image/qq.png
Normal file
|
After Width: | Height: | Size: 267 KiB |
BIN
image/wx.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
103
pom.xml
@@ -14,37 +14,36 @@
|
||||
|
||||
<properties>
|
||||
<revision>1.0.0</revision>
|
||||
<spring-boot.version>3.0.6</spring-boot.version>
|
||||
<spring-boot.version>3.4.4</spring-boot.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
<spring-boot.mybatis>3.0.1</spring-boot.mybatis>
|
||||
<springdoc.version>2.1.0</springdoc.version>
|
||||
<mysql.version>8.0.33</mysql.version>
|
||||
<mybatis.version>3.5.16</mybatis.version>
|
||||
<springdoc.version>2.8.5</springdoc.version>
|
||||
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
|
||||
<poi.version>5.2.3</poi.version>
|
||||
<easyexcel.version>3.2.1</easyexcel.version>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
<satoken.version>1.34.0</satoken.version>
|
||||
<mybatis-plus.version>3.5.3.1</mybatis-plus.version>
|
||||
<mybatis-plus.version>3.5.11</mybatis-plus.version>
|
||||
<p6spy.version>3.9.1</p6spy.version>
|
||||
<hutool.version>5.8.18</hutool.version>
|
||||
<hutool.version>5.8.35</hutool.version>
|
||||
<okhttp.version>4.10.0</okhttp.version>
|
||||
<dynamic-ds.version>4.3.1</dynamic-ds.version>
|
||||
<spring-boot-admin.version>3.0.3</spring-boot-admin.version>
|
||||
<redisson.version>3.20.1</redisson.version>
|
||||
<lock4j.version>2.2.4</lock4j.version>
|
||||
<dynamic-ds.version>3.6.1</dynamic-ds.version>
|
||||
<alibaba-ttl.version>2.14.2</alibaba-ttl.version>
|
||||
<xxl-job.version>2.4.0</xxl-job.version>
|
||||
<mapstruct-plus.version>1.2.1</mapstruct-plus.version>
|
||||
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
|
||||
<lombok.version>1.18.26</lombok.version>
|
||||
<bouncycastle.version>1.72</bouncycastle.version>
|
||||
<!-- Apache Commons Compress 版本 -->
|
||||
<commons-compress.version>1.26.2</commons-compress.version>
|
||||
<!-- 离线IP地址定位库 -->
|
||||
<ip2region.version>2.7.0</ip2region.version>
|
||||
|
||||
<!-- 临时修复 snakeyaml 漏洞 -->
|
||||
<snakeyaml.version>1.33</snakeyaml.version>
|
||||
|
||||
<!-- OSS 配置 -->
|
||||
<aws-java-sdk-s3.version>1.12.400</aws-java-sdk-s3.version>
|
||||
<!-- SMS 配置 -->
|
||||
@@ -57,9 +56,6 @@
|
||||
<maven-compiler-plugin.verison>3.11.0</maven-compiler-plugin.verison>
|
||||
<maven-surefire-plugin.version>3.0.0</maven-surefire-plugin.version>
|
||||
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
|
||||
<weixin-java-miniapp.version>4.5.0</weixin-java-miniapp.version>
|
||||
<weixin-java-pay.version>4.6.0</weixin-java-pay.version>
|
||||
<weixin-java-cp.version>4.6.0</weixin-java-cp.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
@@ -96,6 +92,12 @@
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${mysql.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot的依赖配置-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -194,22 +196,22 @@
|
||||
<version>${satoken.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- dynamic-datasource 多数据源-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
||||
<version>${dynamic-ds.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>${spring-boot.mybatis}</version>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
<version>${mybatis.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-jsqlparser</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
@@ -219,6 +221,13 @@
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- dynamic-datasource 多数据源-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||
<version>${dynamic-ds.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- sql性能分析插件 -->
|
||||
<dependency>
|
||||
<groupId>p6spy</groupId>
|
||||
@@ -244,18 +253,6 @@
|
||||
<version>${tencent.sms.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>de.codecentric</groupId>-->
|
||||
<!-- <artifactId>spring-boot-admin-starter-server</artifactId>-->
|
||||
<!-- <version>${spring-boot-admin.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>de.codecentric</groupId>-->
|
||||
<!-- <artifactId>spring-boot-admin-starter-client</artifactId>-->
|
||||
<!-- <version>${spring-boot-admin.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!--redisson-->
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||
@@ -281,13 +278,6 @@
|
||||
<version>${alibaba-ttl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 临时修复 snakeyaml 漏洞 -->
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>${snakeyaml.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 加密包引入 -->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
@@ -295,6 +285,13 @@
|
||||
<version>${bouncycastle.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Commons Compress -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>${commons-compress.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.linpeilie</groupId>
|
||||
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
|
||||
@@ -317,14 +314,25 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-fusion</artifactId>
|
||||
<artifactId>ruoyi-chat</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-knowledge-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-knowledge</artifactId>
|
||||
<artifactId>ruoyi-chat-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
@@ -336,7 +344,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-demo</artifactId>
|
||||
<artifactId>ruoyi-aihuman</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
@@ -344,10 +352,13 @@
|
||||
</dependencyManagement>
|
||||
|
||||
<modules>
|
||||
<module>ruoyi-admin</module>
|
||||
<module>ruoyi-common</module>
|
||||
<module>ruoyi-modules</module>
|
||||
<module>ruoyi-modules-api</module>
|
||||
<module>ruoyi-admin</module>
|
||||
<module>ruoyi-extend</module>
|
||||
</modules>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#基础镜像
|
||||
FROM findepi/graalvm:java17-native
|
||||
|
||||
# 设置环境变量
|
||||
ENV LANG C.UTF-8
|
||||
ENV LANGUAGE C.UTF-8
|
||||
ENV LC_ALL C.UTF-8
|
||||
ENV SERVER_PORT=6039
|
||||
|
||||
MAINTAINER ageerle
|
||||
|
||||
RUN mkdir -p /ruoyi/server/logs \
|
||||
/ruoyi/server/temp \
|
||||
/ruoyi/skywalking/agent
|
||||
|
||||
|
||||
#工作空间
|
||||
WORKDIR /ruoyi/server
|
||||
|
||||
|
||||
|
||||
EXPOSE ${SERVER_PORT}
|
||||
|
||||
ADD ./target/ruoyi-admin.jar ./app.jar
|
||||
|
||||
|
||||
ENTRYPOINT ["java", \
|
||||
"-Djava.security.egd=file:/dev/./urandom", \
|
||||
"-Dserver.port=${SERVER_PORT}", \
|
||||
# 应用名称 如果想区分集群节点监控 改成不同的名称即可
|
||||
# "-Dskywalking.agent.service_name=ruoyi-server", \
|
||||
# "-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar", \
|
||||
"-jar", "app.jar"]
|
||||
|
||||
|
||||
@@ -42,11 +42,6 @@
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-doc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
@@ -54,12 +49,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-fusion</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-knowledge</artifactId>
|
||||
<artifactId>ruoyi-chat</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -67,29 +57,9 @@
|
||||
<artifactId>ruoyi-generator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- demo模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-demo</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 添加thumbnailator依赖 -->
|
||||
<dependency>
|
||||
<groupId>net.coobird</groupId>
|
||||
<artifactId>thumbnailator</artifactId>
|
||||
<version>0.4.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.ollama4j</groupId>
|
||||
<artifactId>ollama4j</artifactId>
|
||||
<version>1.0.79</version>
|
||||
<scope>compile</scope>
|
||||
<artifactId>ruoyi-aihuman</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -3,13 +3,17 @@ package org.ruoyi;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* 启动程序
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(scanBasePackages = {"org.ruoyi", "org.ruoyi.aihuman"})
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
public class RuoYiAIApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
@@ -18,4 +22,4 @@ public class RuoYiAIApplication {
|
||||
application.run(args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ RuoYiAI启动成功 ლ(´ڡ`ლ)゙");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,11 @@ package org.ruoyi.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.json.ObjectMapper;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.ruoyi.common.core.constant.Constants;
|
||||
import org.ruoyi.common.core.domain.R;
|
||||
import org.ruoyi.common.core.domain.model.EmailLoginBody;
|
||||
import org.ruoyi.common.core.domain.model.LoginBody;
|
||||
import org.ruoyi.common.core.domain.model.RegisterBody;
|
||||
import org.ruoyi.common.core.domain.model.SmsLoginBody;
|
||||
import org.ruoyi.common.core.domain.model.VisitorLoginBody;
|
||||
import org.ruoyi.common.core.domain.model.*;
|
||||
import org.ruoyi.common.core.utils.MapstructUtils;
|
||||
import org.ruoyi.common.core.utils.StreamUtils;
|
||||
import org.ruoyi.common.core.utils.StringUtils;
|
||||
@@ -19,16 +14,12 @@ import org.ruoyi.common.satoken.utils.LoginHelper;
|
||||
import org.ruoyi.common.tenant.helper.TenantHelper;
|
||||
import org.ruoyi.system.domain.bo.SysTenantBo;
|
||||
import org.ruoyi.system.domain.vo.LoginTenantVo;
|
||||
import org.ruoyi.system.domain.vo.LoginVo;
|
||||
import org.ruoyi.system.domain.vo.SysTenantVo;
|
||||
import org.ruoyi.system.domain.vo.TenantListVo;
|
||||
import org.ruoyi.system.service.ISysTenantService;
|
||||
|
||||
import org.ruoyi.system.service.SysLoginService;
|
||||
import org.ruoyi.system.service.SysRegisterService;
|
||||
import org.ruoyi.system.domain.vo.LoginVo;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -51,15 +42,6 @@ public class AuthController {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录方法
|
||||
*
|
||||
@@ -76,6 +58,8 @@ public class AuthController {
|
||||
body.getUsername(), body.getPassword(),
|
||||
body.getCode(), body.getUuid());
|
||||
loginVo.setToken(token);
|
||||
// 兼容后台管理登录
|
||||
loginVo.setAccess_token(token);
|
||||
loginVo.setUserInfo(LoginHelper.getLoginUser());
|
||||
return R.ok(loginVo);
|
||||
}
|
||||
@@ -97,7 +81,6 @@ public class AuthController {
|
||||
|
||||
/**
|
||||
* 访客登录
|
||||
*
|
||||
* @param loginBody 登录信息
|
||||
* @return token信息
|
||||
*/
|
||||
@@ -136,7 +119,7 @@ public class AuthController {
|
||||
*/
|
||||
@PostMapping("/register")
|
||||
public R<Void> register(@Validated @RequestBody RegisterBody user, HttpServletRequest request) {
|
||||
String domainName = request.getServerName();
|
||||
String domainName = request.getServerName();
|
||||
user.setDomainName(domainName);
|
||||
registerService.register(user);
|
||||
return R.ok();
|
||||
|
||||
@@ -5,10 +5,13 @@ import cn.hutool.captcha.AbstractCaptcha;
|
||||
import cn.hutool.captcha.generator.CodeGenerator;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.ruoyi.common.core.constant.Constants;
|
||||
import org.ruoyi.common.core.constant.GlobalConstants;
|
||||
import org.ruoyi.common.core.domain.R;
|
||||
import org.ruoyi.common.core.exception.ServiceException;
|
||||
import org.ruoyi.common.core.service.ConfigService;
|
||||
import org.ruoyi.common.core.utils.SpringUtils;
|
||||
import org.ruoyi.common.core.utils.StringUtils;
|
||||
@@ -22,10 +25,6 @@ import org.ruoyi.common.web.config.properties.CaptchaProperties;
|
||||
import org.ruoyi.common.web.enums.CaptchaType;
|
||||
import org.ruoyi.system.domain.request.EmailRequest;
|
||||
import org.ruoyi.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;
|
||||
@@ -36,7 +35,8 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 验证码操作处理
|
||||
@@ -67,7 +67,7 @@ public class CaptchaController {
|
||||
String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber;
|
||||
String code = RandomUtil.randomNumbers(4);
|
||||
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
|
||||
// 验证码模板id 自行处理 (查数据库或写死均可)
|
||||
// 验证码模板id
|
||||
String templateId = "";
|
||||
Map<String, String> map = new HashMap<>(1);
|
||||
map.put("code", code);
|
||||
@@ -90,18 +90,6 @@ public class CaptchaController {
|
||||
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");
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.ruoyi.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -11,7 +10,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
* @author Lion Li
|
||||
*/
|
||||
@SaIgnore
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
public class IndexController {
|
||||
|
||||
@@ -20,7 +18,9 @@ public class IndexController {
|
||||
*/
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "RuoYi-AI 启动成功";
|
||||
return "RuoYi AI启动成功!";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
package org.ruoyi.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.ruoyi.common.chat.config.ChatConfig;
|
||||
import org.ruoyi.common.chat.domain.request.ChatRequest;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
|
||||
import org.ruoyi.common.chat.entity.chat.Message;
|
||||
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
|
||||
import org.ruoyi.common.core.domain.R;
|
||||
import org.ruoyi.common.core.validate.AddGroup;
|
||||
import org.ruoyi.common.excel.utils.ExcelUtil;
|
||||
import org.ruoyi.common.log.annotation.Log;
|
||||
import org.ruoyi.common.log.enums.BusinessType;
|
||||
import org.ruoyi.common.mybatis.core.page.PageQuery;
|
||||
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
|
||||
import org.ruoyi.common.satoken.utils.LoginHelper;
|
||||
import org.ruoyi.common.web.core.BaseController;
|
||||
import org.ruoyi.knowledge.domain.bo.KnowledgeAttachBo;
|
||||
import org.ruoyi.knowledge.domain.bo.KnowledgeFragmentBo;
|
||||
import org.ruoyi.knowledge.domain.bo.KnowledgeInfoBo;
|
||||
import org.ruoyi.knowledge.domain.req.KnowledgeInfoUploadRequest;
|
||||
import org.ruoyi.knowledge.domain.vo.KnowledgeAttachVo;
|
||||
import org.ruoyi.knowledge.domain.vo.KnowledgeFragmentVo;
|
||||
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
|
||||
import org.ruoyi.knowledge.service.EmbeddingService;
|
||||
import org.ruoyi.knowledge.service.IKnowledgeAttachService;
|
||||
import org.ruoyi.knowledge.service.IKnowledgeFragmentService;
|
||||
import org.ruoyi.knowledge.service.IKnowledgeInfoService;
|
||||
import org.ruoyi.system.listener.SSEEventSourceListener;
|
||||
import org.ruoyi.system.service.ISseService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.ruoyi.knowledge.chain.vectorstore.VectorStore;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 知识库
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2024-10-21
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/knowledge")
|
||||
public class KnowledgeController extends BaseController {
|
||||
|
||||
private final IKnowledgeInfoService knowledgeInfoService;
|
||||
|
||||
private final VectorStore vectorStore;
|
||||
|
||||
private final IKnowledgeAttachService attachService;
|
||||
|
||||
private final IKnowledgeFragmentService fragmentService;
|
||||
|
||||
private final EmbeddingService embeddingService;
|
||||
|
||||
private OpenAiStreamClient openAiStreamClient;
|
||||
|
||||
private final ChatConfig chatConfig;
|
||||
|
||||
private final ISseService sseService;
|
||||
|
||||
/**
|
||||
* 知识库对话
|
||||
*/
|
||||
@PostMapping("/send")
|
||||
public SseEmitter send(@RequestBody @Valid ChatRequest chatRequest) {
|
||||
|
||||
openAiStreamClient = chatConfig.getOpenAiStreamClient();
|
||||
SseEmitter sseEmitter = new SseEmitter(0L);
|
||||
SSEEventSourceListener openAIEventSourceListener = new SSEEventSourceListener(sseEmitter);
|
||||
List<Message> messages = chatRequest.getMessages();
|
||||
String content = messages.get(messages.size() - 1).getContent().toString();
|
||||
List<String> nearestList;
|
||||
List<Double> queryVector = embeddingService.getQueryVector(content, chatRequest.getKid());
|
||||
nearestList = vectorStore.nearest(queryVector,chatRequest.getKid());
|
||||
for (String prompt : nearestList) {
|
||||
Message sysMessage = Message.builder().content(prompt).role(Message.Role.USER).build();
|
||||
messages.add(sysMessage);
|
||||
}
|
||||
Message userMessage = Message.builder().content(content + (nearestList.size() > 0 ? "\n\n注意:回答问题时,须严格根据我给你的系统上下文内容原文进行回答,请不要自己发挥,回答时保持原来文本的段落层级" : "") ).role(Message.Role.USER).build();
|
||||
messages.add(userMessage);
|
||||
if (chatRequest.getModel().startsWith("ollama")) {
|
||||
return sseService.ollamaChat(chatRequest);
|
||||
}
|
||||
|
||||
ChatCompletion completion = ChatCompletion
|
||||
.builder()
|
||||
.messages(messages)
|
||||
.model(chatRequest.getModel())
|
||||
.temperature(chatRequest.getTemperature())
|
||||
.topP(chatRequest.getTop_p())
|
||||
.stream(true)
|
||||
.build();
|
||||
openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener);
|
||||
|
||||
return sseEmitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户信息查询本地知识库
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<KnowledgeInfoVo> list(KnowledgeInfoBo bo, PageQuery pageQuery) {
|
||||
if(!StpUtil.isLogin()){
|
||||
return null;
|
||||
}
|
||||
bo.setUid(LoginHelper.getUserId());
|
||||
return knowledgeInfoService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增知识库
|
||||
*/
|
||||
@Log(title = "知识库", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/save")
|
||||
public R<Void> save(@Validated(AddGroup.class) @RequestBody KnowledgeInfoBo bo) {
|
||||
knowledgeInfoService.saveOne(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除知识库
|
||||
*/
|
||||
@PostMapping("/remove/{id}")
|
||||
public R<String> remove(@PathVariable String id){
|
||||
knowledgeInfoService.removeKnowledge(id);
|
||||
return R.ok("删除知识库成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改知识库
|
||||
*/
|
||||
@Log(title = "知识库", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/edit")
|
||||
public R<Void> edit( @RequestBody KnowledgeInfoBo bo) {
|
||||
return toAjax(knowledgeInfoService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出知识库列表
|
||||
*/
|
||||
@Log(title = "知识库", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(KnowledgeInfoBo bo, HttpServletResponse response) {
|
||||
List<KnowledgeInfoVo> list = knowledgeInfoService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "知识库", KnowledgeInfoVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询知识附件信息
|
||||
*/
|
||||
@GetMapping("/detail/{kid}")
|
||||
public TableDataInfo<KnowledgeAttachVo> attach(KnowledgeAttachBo bo, PageQuery pageQuery,@PathVariable String kid){
|
||||
bo.setKid(kid);
|
||||
return attachService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传知识库附件
|
||||
*/
|
||||
@PostMapping(value = "/attach/upload")
|
||||
public R<String> upload(KnowledgeInfoUploadRequest request){
|
||||
knowledgeInfoService.upload(request);
|
||||
return R.ok("上传知识库附件成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取知识库附件详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@GetMapping("attach/info/{id}")
|
||||
public R<KnowledgeAttachVo> getAttachInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(attachService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除知识库附件
|
||||
*
|
||||
*/
|
||||
@PostMapping("attach/remove/{docId}")
|
||||
public R<Void> removeAttach(@NotEmpty(message = "主键不能为空") @PathVariable String docId) {
|
||||
attachService.removeKnowledgeAttach(docId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询知识片段
|
||||
*/
|
||||
@GetMapping("/fragment/list/{docId}")
|
||||
public TableDataInfo<KnowledgeFragmentVo> fragmentList(KnowledgeFragmentBo bo, PageQuery pageQuery, @PathVariable String docId) {
|
||||
bo.setDocId(docId);
|
||||
return fragmentService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,3 @@
|
||||
--- # 监控中心配置
|
||||
spring.boot.admin.client:
|
||||
# 增加客户端开关
|
||||
enabled: false
|
||||
url: http://localhost:9090/admin
|
||||
instance:
|
||||
service-host-type: IP
|
||||
username: ruoyi
|
||||
password: 123456
|
||||
|
||||
--- # 数据源配置
|
||||
spring:
|
||||
@@ -25,10 +16,9 @@ spring:
|
||||
master:
|
||||
type: ${spring.datasource.type}
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://43.139.70.230:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
username: ruoyi-ai
|
||||
password: ruoyi-ai
|
||||
|
||||
url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
username: root
|
||||
password: root
|
||||
|
||||
hikari:
|
||||
# 最大连接池数量
|
||||
@@ -61,9 +51,6 @@ spring.data:
|
||||
# password: 123456
|
||||
# 连接超时时间
|
||||
timeout: 10S
|
||||
# 是否开启ssl
|
||||
ssl: false
|
||||
|
||||
redisson:
|
||||
# redis key前缀
|
||||
keyPrefix:
|
||||
@@ -97,3 +84,23 @@ sms:
|
||||
signName: 测试
|
||||
# 腾讯专用
|
||||
sdkAppId:
|
||||
|
||||
pdf:
|
||||
extract:
|
||||
service:
|
||||
url: http://localhost:8080
|
||||
ai-api:
|
||||
url: https://api.pandarobot.chat/v1/chat/completions
|
||||
key: sk-xxxx
|
||||
transition:
|
||||
# 是否开启mineru
|
||||
enable-minerU: true
|
||||
# mineru conda环境路径
|
||||
conda-env-path: "F:\\ProgramData\\Computer\\Anaconda\\envs\\mineru"
|
||||
# 是否开启图片OCR
|
||||
enable-ocr: true
|
||||
#百炼模型配置
|
||||
dashscope:
|
||||
key: sk-xxxx
|
||||
model: qvq-max
|
||||
|
||||
|
||||
111
ruoyi-admin/src/main/resources/application-local.yml
Normal file
@@ -0,0 +1,111 @@
|
||||
--- # 监控中心配置
|
||||
spring.boot.admin.client:
|
||||
# 增加客户端开关
|
||||
enabled: false
|
||||
url: http://localhost:9090/admin
|
||||
instance:
|
||||
service-host-type: IP
|
||||
username: ruoyi
|
||||
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://localhost:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
username: root
|
||||
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: 127.0.0.1
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 0
|
||||
# 密码(如没有密码请注释掉)
|
||||
password: root
|
||||
# 连接超时时间
|
||||
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:
|
||||
|
||||
pdf:
|
||||
extract:
|
||||
service:
|
||||
url: http://localhost:8080
|
||||
ai-api:
|
||||
url: https://api.pandarobot.chat/v1/chat/completions
|
||||
key: sk-xxxx
|
||||
#百炼模型配置
|
||||
dashscope:
|
||||
key: sk-xxxx
|
||||
model: qvq-max
|
||||
@@ -1,16 +1,13 @@
|
||||
|
||||
# 项目相关配置
|
||||
ruoyi:
|
||||
# 名称
|
||||
name: "ruoyi"
|
||||
name: "ruoyi-ai"
|
||||
# 版本
|
||||
version: ${revision}
|
||||
# 版权年份
|
||||
copyrightYear: 2025
|
||||
# 实例演示开关
|
||||
demoEnabled: true
|
||||
# 获取ip地址开关
|
||||
addressEnabled: false
|
||||
demoEnabled: false
|
||||
|
||||
captcha:
|
||||
enable: false
|
||||
@@ -51,6 +48,8 @@ logging:
|
||||
level:
|
||||
org.ruoyi: @logging.level@
|
||||
org.springframework: warn
|
||||
org.mybatis.spring.mapper: error
|
||||
org.apache.fury: warn
|
||||
config: classpath:logback-plus.xml
|
||||
|
||||
# 用户配置
|
||||
@@ -118,6 +117,8 @@ sa-token:
|
||||
security:
|
||||
# 排除路径
|
||||
excludes:
|
||||
# 获取模型信息
|
||||
- /system/model/modelList
|
||||
# 支付回调
|
||||
- /pay/returnUrl
|
||||
- /pay/notifyUrl
|
||||
@@ -126,7 +127,12 @@ security:
|
||||
# 重置密码
|
||||
- /auth/reset/password
|
||||
# 聊天接口
|
||||
- /chat
|
||||
- /chat/send
|
||||
# 文件上传
|
||||
- /chat/upload
|
||||
# 代码生成调用
|
||||
- /tool/gen/getByTableName
|
||||
- /tool/gen/batchGenCode
|
||||
# 静态资源
|
||||
- /*.html
|
||||
- /**/*.html
|
||||
@@ -138,6 +144,15 @@ security:
|
||||
# swagger 文档配置
|
||||
- /*/api-docs
|
||||
- /*/api-docs/**
|
||||
- /v3/api-docs
|
||||
- /v3/api-docs/**
|
||||
- /v3/api-docs/swagger-config
|
||||
- /swagger-ui.html
|
||||
- /swagger-ui/**
|
||||
- /doc.html
|
||||
- /webjars/**
|
||||
- /swagger-resources
|
||||
- /swagger-resources/**
|
||||
# actuator 监控配置
|
||||
- /actuator
|
||||
- /actuator/**
|
||||
@@ -155,6 +170,9 @@ tenant:
|
||||
- sys_user_post
|
||||
- sys_user_role
|
||||
|
||||
knowledge-role:
|
||||
enable: false
|
||||
|
||||
# MyBatisPlus配置
|
||||
# https://baomidou.com/config/
|
||||
mybatis-plus:
|
||||
@@ -179,7 +197,7 @@ mybatis-plus:
|
||||
# 更详细的日志输出 会有性能损耗 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
|
||||
logImpl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||
global-config:
|
||||
# 是否打印 Logo banner
|
||||
banner: true
|
||||
@@ -213,13 +231,18 @@ mybatis-encryptor:
|
||||
publicKey:
|
||||
privateKey:
|
||||
|
||||
# Swagger配置
|
||||
swagger:
|
||||
springdoc:
|
||||
api-docs:
|
||||
# 是否开启接口文档
|
||||
enabled: true
|
||||
# swagger-ui:
|
||||
# # 持久化认证数据
|
||||
# persistAuthorization: true
|
||||
info:
|
||||
# 标题
|
||||
title: '标题:${ruoyi.name}多租户管理系统_接口文档'
|
||||
title: '标题:ruoyi-ai 接口文档'
|
||||
# 描述
|
||||
description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
|
||||
description: ''
|
||||
# 版本
|
||||
version: '版本号: ${ruoyi.version}'
|
||||
# 作者信息
|
||||
@@ -234,31 +257,20 @@ swagger:
|
||||
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
|
||||
packages-to-scan: org.ruoyi
|
||||
|
||||
knife4j:
|
||||
enable: true
|
||||
setting:
|
||||
language: zh_cn
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
# 排除链接(多个用逗号分隔)
|
||||
excludes: /system/notice
|
||||
excludes: /system/notice,/v3/api-docs/**,/doc.html,/swagger-ui/**,/swagger-ui.html,/swagger-resources/**,/webjars/**,/druid/**,/actuator/**,/favicon.ico
|
||||
# 匹配链接
|
||||
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||
|
||||
@@ -290,6 +302,7 @@ management:
|
||||
logfile:
|
||||
external-file: ./logs/sys-console.log
|
||||
|
||||
# websocket
|
||||
# websocket
|
||||
websocket:
|
||||
enabled: true
|
||||
@@ -298,25 +311,20 @@ websocket:
|
||||
# 设置访问源地址
|
||||
allowedOrigins: '*'
|
||||
|
||||
# 微信小程序配置信息
|
||||
wx:
|
||||
miniapp:
|
||||
configs:
|
||||
- appid: # 你的appid
|
||||
secret: # 你的secret
|
||||
token: #微信小程序消息服务器配置的token
|
||||
aesKey: #微信小程序消息服务器配置的EncodingAESKey
|
||||
msgDataFormat: JSON
|
||||
|
||||
# 企业微信应用
|
||||
wechat:
|
||||
cp:
|
||||
corpId:
|
||||
appConfigs:
|
||||
- agentId:
|
||||
secret: ''
|
||||
token: ''
|
||||
aesKey: ''
|
||||
|
||||
|
||||
spring:
|
||||
ai:
|
||||
openai:
|
||||
api-key: sk-xx
|
||||
base-url: https://api.pandarobot.chat/
|
||||
mcp:
|
||||
client:
|
||||
enabled: false
|
||||
name: ruoyi-ai-mcp
|
||||
sse:
|
||||
connections:
|
||||
server:
|
||||
url: http://127.0.0.1:8081
|
||||
stdio:
|
||||
servers-configuration: classpath:mcp-server.json
|
||||
request-timeout: 300s
|
||||
|
||||
|
||||
22
ruoyi-admin/src/main/resources/mcp-server.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"fileSystem": {
|
||||
"command": "C:\\Program Files\\nodejs\\npx.cmd",
|
||||
"args": [
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-filesystem",
|
||||
"D:\\"
|
||||
]
|
||||
},
|
||||
"search1api": {
|
||||
"command": "C:\\Program Files\\nodejs\\npx.cmd",
|
||||
"args": [
|
||||
"-y",
|
||||
"search1api-mcp"
|
||||
],
|
||||
"env": {
|
||||
"SEARCH1API_KEY": "xx"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
ruoyi-admin/src/main/resources/static/favicon.ico
Normal file
|
After Width: | Height: | Size: 78 KiB |
@@ -2,13 +2,20 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ruoyi-ai</artifactId>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<description>
|
||||
common 通用模块
|
||||
</description>
|
||||
|
||||
<modules>
|
||||
<module>ruoyi-common-bom</module>
|
||||
@@ -33,14 +40,6 @@
|
||||
<module>ruoyi-common-tenant</module>
|
||||
<module>ruoyi-common-chat</module>
|
||||
<module>ruoyi-common-pay</module>
|
||||
<module>ruoyi-common-wechat</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<description>
|
||||
common 通用模块
|
||||
</description>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -166,14 +166,6 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- AI绘画 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-fusion</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- 支付模块 -->
|
||||
<dependency>
|
||||
@@ -182,6 +174,7 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</dependencyManagement>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
|
||||
<properties>
|
||||
<retrofit2.version>2.9.0</retrofit2.version>
|
||||
<azure.version>1.0.0-beta.12</azure.version>
|
||||
<chatglm.version>release-V4-2.3.0</chatglm.version>
|
||||
<okhttp.version>2.7.5</okhttp.version>
|
||||
<jtokkit.version>0.5.0</jtokkit.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -26,38 +30,22 @@
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 序列化模块 -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.33</version>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- redis模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-ai-openai</artifactId>
|
||||
<version>1.0.0-beta.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.ollama4j</groupId>
|
||||
<artifactId>ollama4j</artifactId>
|
||||
<version>1.0.79</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 序列化模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-json</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-satoken</artifactId>
|
||||
<version>${azure.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -79,13 +67,7 @@
|
||||
<dependency>
|
||||
<groupId>com.knuddels</groupId>
|
||||
<artifactId>jtokkit</artifactId>
|
||||
<version>0.5.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.12</version>
|
||||
<version>${jtokkit.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -98,21 +80,18 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.bigmodel.openapi</groupId>
|
||||
<artifactId>oapi-java-sdk</artifactId>
|
||||
<version>release-V4-2.3.0</version>
|
||||
<version>${chatglm.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>2.7.5</version>
|
||||
<scope>compile</scope>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.hutool.core.date.DateUnit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @date 2023-03-10
|
||||
|
||||
@@ -12,6 +12,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@Data
|
||||
public class WebSocketProperties {
|
||||
|
||||
/**
|
||||
* 是否开启
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.ruoyi.common.chat.constant;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-06
|
||||
@@ -10,6 +9,8 @@ public class OpenAIConst {
|
||||
|
||||
public final static String OPENAI_HOST = "https://api.openai.com/";
|
||||
|
||||
public final static String apiUrl = "v1/chat/completions";
|
||||
|
||||
public final static int SUCCEED_CODE = 200;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okhttp3.sse.EventSource;
|
||||
import okhttp3.sse.EventSourceListener;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* 描述: sse
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-06-15
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConsoleEventSourceListenerV2 extends EventSourceListener {
|
||||
@Getter
|
||||
String args = "";
|
||||
final CountDownLatch countDownLatch;
|
||||
|
||||
public ConsoleEventSourceListenerV2(CountDownLatch countDownLatch) {
|
||||
this.countDownLatch = countDownLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(EventSource eventSource, Response response) {
|
||||
log.info("OpenAI建立sse连接...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(EventSource eventSource, String id, String type, String data) {
|
||||
log.info("OpenAI返回数据:{}", data);
|
||||
if (data.equals("[DONE]")) {
|
||||
log.info("OpenAI返回数据结束了");
|
||||
countDownLatch.countDown();
|
||||
return;
|
||||
}
|
||||
ChatCompletionResponse chatCompletionResponse = JSONUtil.toBean(data, ChatCompletionResponse.class);
|
||||
if(Objects.nonNull(chatCompletionResponse.getChoices().get(0).getDelta().getFunctionCall())){
|
||||
args += chatCompletionResponse.getChoices().get(0).getDelta().getFunctionCall().getArguments();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(EventSource eventSource) {
|
||||
log.info("OpenAI关闭sse连接...");
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void onFailure(EventSource eventSource, Throwable t, Response response) {
|
||||
if(Objects.isNull(response)){
|
||||
log.error("OpenAI sse连接异常:{}", t);
|
||||
eventSource.cancel();
|
||||
return;
|
||||
}
|
||||
ResponseBody body = response.body();
|
||||
if (Objects.nonNull(body)) {
|
||||
log.error("OpenAI sse连接异常data:{},异常:{}", body.string(), t);
|
||||
} else {
|
||||
log.error("OpenAI sse连接异常data:{},异常:{}", response, t);
|
||||
}
|
||||
eventSource.cancel();
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okhttp3.sse.EventSource;
|
||||
import okhttp3.sse.EventSourceListener;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse;
|
||||
import org.ruoyi.common.chat.entity.chat.Message;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolCallFunction;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolCalls;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* 描述: demo测试实现类,仅供思路参考
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-11-12
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConsoleEventSourceListenerV3 extends EventSourceListener {
|
||||
@Getter
|
||||
List<ToolCalls> choices = new ArrayList<>();
|
||||
@Getter
|
||||
ToolCalls toolCalls = new ToolCalls();
|
||||
@Getter
|
||||
ToolCallFunction toolCallFunction = ToolCallFunction.builder().name("").arguments("").build();
|
||||
final CountDownLatch countDownLatch;
|
||||
|
||||
public ConsoleEventSourceListenerV3(CountDownLatch countDownLatch) {
|
||||
this.countDownLatch = countDownLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(EventSource eventSource, Response response) {
|
||||
log.info("OpenAI建立sse连接...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(EventSource eventSource, String id, String type, String data) {
|
||||
log.info("OpenAI返回数据:{}", data);
|
||||
if (data.equals("[DONE]")) {
|
||||
log.info("OpenAI返回数据结束了");
|
||||
return;
|
||||
}
|
||||
ChatCompletionResponse chatCompletionResponse = JSONUtil.toBean(data, ChatCompletionResponse.class);
|
||||
Message delta = chatCompletionResponse.getChoices().get(0).getDelta();
|
||||
if (CollectionUtil.isNotEmpty(delta.getToolCalls())) {
|
||||
choices.addAll(delta.getToolCalls());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(EventSource eventSource) {
|
||||
if(CollectionUtil.isNotEmpty(choices)){
|
||||
toolCalls.setId(choices.get(0).getId());
|
||||
toolCalls.setType(choices.get(0).getType());
|
||||
choices.forEach(e -> {
|
||||
toolCallFunction.setName(e.getFunction().getName());
|
||||
toolCallFunction.setArguments(toolCallFunction.getArguments() + e.getFunction().getArguments());
|
||||
toolCalls.setFunction(toolCallFunction);
|
||||
});
|
||||
}
|
||||
log.info("OpenAI关闭sse连接...");
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void onFailure(EventSource eventSource, Throwable t, Response response) {
|
||||
if(Objects.isNull(response)){
|
||||
log.error("OpenAI sse连接异常:{}", t);
|
||||
eventSource.cancel();
|
||||
return;
|
||||
}
|
||||
ResponseBody body = response.body();
|
||||
if (Objects.nonNull(body)) {
|
||||
log.error("OpenAI sse连接异常data:{},异常:{}", body.string(), t);
|
||||
} else {
|
||||
log.error("OpenAI sse连接异常data:{},异常:{}", response, t);
|
||||
}
|
||||
eventSource.cancel();
|
||||
}
|
||||
}
|
||||
@@ -1,417 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.ruoyi.common.chat.entity.chat.*;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolCallFunction;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolCalls;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.Tools;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolsFunction;
|
||||
import org.ruoyi.common.chat.openai.OpenAiClient;
|
||||
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
|
||||
import org.ruoyi.common.chat.openai.function.KeyRandomStrategy;
|
||||
import org.ruoyi.common.chat.openai.interceptor.DynamicKeyOpenAiAuthInterceptor;
|
||||
import org.ruoyi.common.chat.openai.interceptor.OpenAILogger;
|
||||
import org.ruoyi.common.chat.openai.interceptor.OpenAiResponseInterceptor;
|
||||
import org.ruoyi.common.chat.openai.plugin.PluginAbstract;
|
||||
import org.ruoyi.common.chat.plugin.CmdPlugin;
|
||||
import org.ruoyi.common.chat.plugin.CmdReq;
|
||||
import org.ruoyi.common.chat.sse.ConsoleEventSourceListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author ageerle@163.com
|
||||
* date 2025/3/8
|
||||
*/
|
||||
@Slf4j
|
||||
public class PluginTest {
|
||||
|
||||
private OpenAiClient openAiClient;
|
||||
private OpenAiStreamClient openAiStreamClient;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
//可以为null
|
||||
// Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890));
|
||||
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new OpenAILogger());
|
||||
//!!!!千万别再生产或者测试环境打开BODY级别日志!!!!
|
||||
//!!!生产或者测试环境建议设置为这三种级别:NONE,BASIC,HEADERS,!!!
|
||||
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
|
||||
OkHttpClient okHttpClient = new OkHttpClient
|
||||
.Builder()
|
||||
// .proxy(proxy)
|
||||
.addInterceptor(httpLoggingInterceptor)
|
||||
.addInterceptor(new OpenAiResponseInterceptor())
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.writeTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.build();
|
||||
openAiClient = OpenAiClient.builder()
|
||||
//支持多key传入,请求时候随机选择
|
||||
.apiKey(Arrays.asList("sk-xx"))
|
||||
//自定义key的获取策略:默认KeyRandomStrategy
|
||||
//.keyStrategy(new KeyRandomStrategy())
|
||||
.keyStrategy(new KeyRandomStrategy())
|
||||
.okHttpClient(okHttpClient)
|
||||
//自己做了代理就传代理地址,没有可不不传,(关注公众号回复:openai ,获取免费的测试代理地址)
|
||||
.apiHost("https://api.pandarobot.chat/")
|
||||
.build();
|
||||
|
||||
openAiStreamClient = OpenAiStreamClient.builder()
|
||||
//支持多key传入,请求时候随机选择
|
||||
.apiKey(Arrays.asList("sk-xx"))
|
||||
//自定义key的获取策略:默认KeyRandomStrategy
|
||||
.keyStrategy(new KeyRandomStrategy())
|
||||
.authInterceptor(new DynamicKeyOpenAiAuthInterceptor())
|
||||
.okHttpClient(okHttpClient)
|
||||
//自己做了代理就传代理地址,没有可不不传,(关注公众号回复:openai ,获取免费的测试代理地址)
|
||||
.apiHost("https://api.pandarobot.chat/")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void chatFunction() {
|
||||
//模型:GPT_3_5_TURBO_16K_0613
|
||||
Message message = Message.builder().role(Message.Role.USER).content("给我输出一个长度为2的中文词语,并解释下词语对应物品的用途").build();
|
||||
//属性一
|
||||
JSONObject wordLength = new JSONObject();
|
||||
wordLength.put("type", "number");
|
||||
wordLength.put("description", "词语的长度");
|
||||
//属性二
|
||||
JSONObject language = new JSONObject();
|
||||
language.put("type", "string");
|
||||
language.put("enum", Arrays.asList("zh", "en"));
|
||||
language.put("description", "语言类型,例如:zh代表中文、en代表英语");
|
||||
//参数
|
||||
JSONObject properties = new JSONObject();
|
||||
properties.put("wordLength", wordLength);
|
||||
properties.put("language", language);
|
||||
|
||||
Parameters parameters = Parameters.builder()
|
||||
.type("object")
|
||||
.properties(properties)
|
||||
.required(Collections.singletonList("wordLength")).build();
|
||||
Functions functions = Functions.builder()
|
||||
.name("getOneWord")
|
||||
.description("获取一个指定长度和语言类型的词语")
|
||||
.parameters(parameters)
|
||||
.build();
|
||||
|
||||
ChatCompletion chatCompletion = ChatCompletion
|
||||
.builder()
|
||||
.messages(Collections.singletonList(message))
|
||||
.functions(Collections.singletonList(functions))
|
||||
.functionCall("auto")
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
|
||||
|
||||
ChatChoice chatChoice = chatCompletionResponse.getChoices().get(0);
|
||||
log.info("构造的方法值:{}", chatChoice.getMessage().getFunctionCall());
|
||||
log.info("构造的方法名称:{}", chatChoice.getMessage().getFunctionCall().getName());
|
||||
log.info("构造的方法参数:{}", chatChoice.getMessage().getFunctionCall().getArguments());
|
||||
WordParam wordParam = JSONUtil.toBean(chatChoice.getMessage().getFunctionCall().getArguments(), WordParam.class);
|
||||
String oneWord = getOneWord(wordParam);
|
||||
|
||||
FunctionCall functionCall = FunctionCall.builder()
|
||||
.arguments(chatChoice.getMessage().getFunctionCall().getArguments())
|
||||
.name("getOneWord")
|
||||
.build();
|
||||
Message message2 = Message.builder().role(Message.Role.ASSISTANT).content("方法参数").functionCall(functionCall).build();
|
||||
String content
|
||||
= "{ " +
|
||||
"\"wordLength\": \"3\", " +
|
||||
"\"language\": \"zh\", " +
|
||||
"\"word\": \"" + oneWord + "\"," +
|
||||
"\"用途\": [\"直接吃\", \"做沙拉\", \"售卖\"]" +
|
||||
"}";
|
||||
Message message3 = Message.builder().role(Message.Role.FUNCTION).name("getOneWord").content(content).build();
|
||||
List<Message> messageList = Arrays.asList(message, message2, message3);
|
||||
ChatCompletion chatCompletionV2 = ChatCompletion
|
||||
.builder()
|
||||
.messages(messageList)
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponseV2 = openAiClient.chatCompletion(chatCompletionV2);
|
||||
log.info("自定义的方法返回值:{}",chatCompletionResponseV2.getChoices().get(0).getMessage().getContent());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void plugin() {
|
||||
CmdPlugin plugin = new CmdPlugin(CmdReq.class);
|
||||
// 插件名称
|
||||
plugin.setName("命令行工具");
|
||||
// 方法名称
|
||||
plugin.setFunction("openCmd");
|
||||
// 方法说明
|
||||
plugin.setDescription("提供一个命令行指令,比如<记事本>,指令使用中文,以function返回结果为准");
|
||||
|
||||
PluginAbstract.Arg arg = new PluginAbstract.Arg();
|
||||
// 参数名称
|
||||
arg.setName("cmd");
|
||||
// 参数说明
|
||||
arg.setDescription("命令行指令");
|
||||
// 参数类型
|
||||
arg.setType("string");
|
||||
arg.setRequired(true);
|
||||
plugin.setArgs(Collections.singletonList(arg));
|
||||
|
||||
Message message2 = Message.builder().role(Message.Role.USER).content("帮我打开计算器,结合上下文判断指令是否执行成功,只用回复成功或者失败").build();
|
||||
List<Message> messages = new ArrayList<>();
|
||||
messages.add(message2);
|
||||
//有四个重载方法,都可以使用
|
||||
ChatCompletionResponse response = openAiClient.chatCompletionWithPlugin(messages,"gpt-4o-mini",plugin);
|
||||
log.info("自定义的方法返回值:{}", response.getChoices().get(0).getMessage().getContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义返回数据格式
|
||||
*/
|
||||
@Test
|
||||
public void diyReturnDataModelChat() {
|
||||
Message message = Message.builder().role(Message.Role.USER).content("随机输出10个单词,使用json输出").build();
|
||||
ChatCompletion chatCompletion = ChatCompletion
|
||||
.builder()
|
||||
.messages(Collections.singletonList(message))
|
||||
.responseFormat(ResponseFormat.builder().type(ResponseFormat.Type.JSON_OBJECT.getName()).build())
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
|
||||
chatCompletionResponse.getChoices().forEach(e -> System.out.println(e.getMessage()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void streamPlugin() {
|
||||
WeatherPlugin plugin = new WeatherPlugin(WeatherReq.class);
|
||||
plugin.setName("知心天气");
|
||||
plugin.setFunction("getLocationWeather");
|
||||
plugin.setDescription("提供一个地址,方法将会获取该地址的天气的实时温度信息。");
|
||||
PluginAbstract.Arg arg = new PluginAbstract.Arg();
|
||||
arg.setName("location");
|
||||
arg.setDescription("地名");
|
||||
arg.setType("string");
|
||||
arg.setRequired(true);
|
||||
plugin.setArgs(Collections.singletonList(arg));
|
||||
|
||||
// Message message1 = Message.builder().role(Message.Role.USER).content("秦始皇统一了哪六国。").build();
|
||||
Message message2 = Message.builder().role(Message.Role.USER).content("获取上海市的天气现在多少度,然后再给出3个推荐的户外运动。").build();
|
||||
List<Message> messages = new ArrayList<>();
|
||||
// messages.add(message1);
|
||||
messages.add(message2);
|
||||
//默认模型:GPT_3_5_TURBO_16K_0613
|
||||
//有四个重载方法,都可以使用
|
||||
openAiStreamClient.streamChatCompletionWithPlugin(messages, ChatCompletion.Model.GPT_4_1106_PREVIEW.getName(), new ConsoleEventSourceListener(), plugin);
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
try {
|
||||
countDownLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tools使用示例
|
||||
*/
|
||||
@Test
|
||||
public void toolsChat() {
|
||||
Message message = Message.builder().role(Message.Role.USER).content("给我输出一个长度为2的中文词语,并解释下词语对应物品的用途").build();
|
||||
//属性一
|
||||
JSONObject wordLength = new JSONObject();
|
||||
wordLength.put("type", "number");
|
||||
wordLength.put("description", "词语的长度");
|
||||
//属性二
|
||||
JSONObject language = new JSONObject();
|
||||
language.put("type", "string");
|
||||
language.put("enum", Arrays.asList("zh", "en"));
|
||||
language.put("description", "语言类型,例如:zh代表中文、en代表英语");
|
||||
//参数
|
||||
JSONObject properties = new JSONObject();
|
||||
properties.put("wordLength", wordLength);
|
||||
properties.put("language", language);
|
||||
Parameters parameters = Parameters.builder()
|
||||
.type("object")
|
||||
.properties(properties)
|
||||
.required(Collections.singletonList("wordLength")).build();
|
||||
Tools tools = Tools.builder()
|
||||
.type(Tools.Type.FUNCTION.getName())
|
||||
.function(ToolsFunction.builder().name("getOneWord").description("获取一个指定长度和语言类型的词语").parameters(parameters).build())
|
||||
.build();
|
||||
|
||||
ChatCompletion chatCompletion = ChatCompletion
|
||||
.builder()
|
||||
.messages(Collections.singletonList(message))
|
||||
.tools(Collections.singletonList(tools))
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
|
||||
|
||||
ChatChoice chatChoice = chatCompletionResponse.getChoices().get(0);
|
||||
log.info("构造的方法值:{}", chatChoice.getMessage().getToolCalls());
|
||||
|
||||
ToolCalls openAiReturnToolCalls = chatChoice.getMessage().getToolCalls().get(0);
|
||||
WordParam wordParam = JSONUtil.toBean(openAiReturnToolCalls.getFunction().getArguments(), WordParam.class);
|
||||
String oneWord = getOneWord(wordParam);
|
||||
|
||||
|
||||
ToolCallFunction tcf = ToolCallFunction.builder().name("getOneWord").arguments(openAiReturnToolCalls.getFunction().getArguments()).build();
|
||||
ToolCalls tc = ToolCalls.builder().id(openAiReturnToolCalls.getId()).type(ToolCalls.Type.FUNCTION.getName()).function(tcf).build();
|
||||
//构造tool call
|
||||
Message message2 = Message.builder().role(Message.Role.ASSISTANT).content("方法参数").toolCalls(Collections.singletonList(tc)).build();
|
||||
String content
|
||||
= "{ " +
|
||||
"\"wordLength\": \"3\", " +
|
||||
"\"language\": \"zh\", " +
|
||||
"\"word\": \"" + oneWord + "\"," +
|
||||
"\"用途\": [\"直接吃\", \"做沙拉\", \"售卖\"]" +
|
||||
"}";
|
||||
Message message3 = Message.builder().toolCallId(openAiReturnToolCalls.getId()).role(Message.Role.TOOL).name("getOneWord").content(content).build();
|
||||
List<Message> messageList = Arrays.asList(message, message2, message3);
|
||||
ChatCompletion chatCompletionV2 = ChatCompletion
|
||||
.builder()
|
||||
.messages(messageList)
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponseV2 = openAiClient.chatCompletion(chatCompletionV2);
|
||||
log.info("自定义的方法返回值:{}", chatCompletionResponseV2.getChoices().get(0).getMessage().getContent());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* tools流式输出使用示例
|
||||
*/
|
||||
@Test
|
||||
public void streamToolsChat() {
|
||||
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
ConsoleEventSourceListenerV3 eventSourceListener = new ConsoleEventSourceListenerV3(countDownLatch);
|
||||
|
||||
Message message = Message.builder().role(Message.Role.USER).content("给我输出一个长度为2的中文词语,并解释下词语对应物品的用途").build();
|
||||
//属性一
|
||||
JSONObject wordLength = new JSONObject();
|
||||
wordLength.put("type", "number");
|
||||
wordLength.put("description", "词语的长度");
|
||||
//属性二
|
||||
JSONObject language = new JSONObject();
|
||||
language.put("type", "string");
|
||||
language.put("enum", Arrays.asList("zh", "en"));
|
||||
language.put("description", "语言类型,例如:zh代表中文、en代表英语");
|
||||
//参数
|
||||
JSONObject properties = new JSONObject();
|
||||
properties.put("wordLength", wordLength);
|
||||
properties.put("language", language);
|
||||
Parameters parameters = Parameters.builder()
|
||||
.type("object")
|
||||
.properties(properties)
|
||||
.required(Collections.singletonList("wordLength")).build();
|
||||
Tools tools = Tools.builder()
|
||||
.type(Tools.Type.FUNCTION.getName())
|
||||
.function(ToolsFunction.builder().name("getOneWord").description("获取一个指定长度和语言类型的词语").parameters(parameters).build())
|
||||
.build();
|
||||
|
||||
ChatCompletion chatCompletion = ChatCompletion
|
||||
.builder()
|
||||
.messages(Collections.singletonList(message))
|
||||
.tools(Collections.singletonList(tools))
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
openAiStreamClient.streamChatCompletion(chatCompletion, eventSourceListener);
|
||||
|
||||
try {
|
||||
countDownLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
ToolCalls openAiReturnToolCalls = eventSourceListener.getToolCalls();
|
||||
WordParam wordParam = JSONUtil.toBean(openAiReturnToolCalls.getFunction().getArguments(), WordParam.class);
|
||||
String oneWord = getOneWord(wordParam);
|
||||
|
||||
|
||||
ToolCallFunction tcf = ToolCallFunction.builder().name("getOneWord").arguments(openAiReturnToolCalls.getFunction().getArguments()).build();
|
||||
ToolCalls tc = ToolCalls.builder().id(openAiReturnToolCalls.getId()).type(ToolCalls.Type.FUNCTION.getName()).function(tcf).build();
|
||||
//构造tool call
|
||||
Message message2 = Message.builder().role(Message.Role.ASSISTANT).content("方法参数").toolCalls(Collections.singletonList(tc)).build();
|
||||
String content
|
||||
= "{ " +
|
||||
"\"wordLength\": \"3\", " +
|
||||
"\"language\": \"zh\", " +
|
||||
"\"word\": \"" + oneWord + "\"," +
|
||||
"\"用途\": [\"直接吃\", \"做沙拉\", \"售卖\"]" +
|
||||
"}";
|
||||
Message message3 = Message.builder().toolCallId(openAiReturnToolCalls.getId()).role(Message.Role.TOOL).name("getOneWord").content(content).build();
|
||||
List<Message> messageList = Arrays.asList(message, message2, message3);
|
||||
ChatCompletion chatCompletionV2 = ChatCompletion
|
||||
.builder()
|
||||
.messages(messageList)
|
||||
.model(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName())
|
||||
.build();
|
||||
|
||||
|
||||
CountDownLatch countDownLatch1 = new CountDownLatch(1);
|
||||
openAiStreamClient.streamChatCompletion(chatCompletionV2, new ConsoleEventSourceListenerV3(countDownLatch));
|
||||
try {
|
||||
countDownLatch1.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
countDownLatch1.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
static class WordParam {
|
||||
private int wordLength;
|
||||
@Builder.Default
|
||||
private String language = "zh";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取一个词语(根据语言和字符长度查询)
|
||||
* @param wordParam
|
||||
* @return
|
||||
*/
|
||||
public String getOneWord(WordParam wordParam) {
|
||||
|
||||
List<String> zh = Arrays.asList("大香蕉", "哈密瓜", "苹果");
|
||||
List<String> en = Arrays.asList("apple", "banana", "cantaloupe");
|
||||
if (wordParam.getLanguage().equals("zh")) {
|
||||
for (String e : zh) {
|
||||
if (e.length() == wordParam.getWordLength()) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wordParam.getLanguage().equals("en")) {
|
||||
for (String e : en) {
|
||||
if (e.length() == wordParam.getWordLength()) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "西瓜";
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
|
||||
import org.ruoyi.common.chat.openai.plugin.PluginAbstract;
|
||||
|
||||
public class WeatherPlugin extends PluginAbstract<WeatherReq, WeatherResp> {
|
||||
|
||||
public WeatherPlugin(Class<?> r) {
|
||||
super(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeatherResp func(WeatherReq args) {
|
||||
WeatherResp weatherResp = new WeatherResp();
|
||||
weatherResp.setTemp("25到28摄氏度");
|
||||
weatherResp.setLevel(3);
|
||||
return weatherResp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String content(WeatherResp weatherResp) {
|
||||
return "当前天气温度:" + weatherResp.getTemp() + ",风力等级:" + weatherResp.getLevel();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import org.ruoyi.common.chat.openai.plugin.PluginParam;
|
||||
|
||||
@Data
|
||||
public class WeatherReq extends PluginParam {
|
||||
/**
|
||||
* 城市
|
||||
*/
|
||||
private String location;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WeatherResp {
|
||||
/**
|
||||
* 温度
|
||||
*/
|
||||
private String temp;
|
||||
/**
|
||||
* 风力等级
|
||||
*/
|
||||
private Integer level;
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
package org.ruoyi.common.chat.demo;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.zhipu.oapi.ClientV4;
|
||||
import com.zhipu.oapi.Constants;
|
||||
import com.zhipu.oapi.service.v4.tools.*;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
|
||||
import com.zhipu.oapi.service.v4.model.*;
|
||||
import io.reactivex.Flowable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class WebSearchToolsTest {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(WebSearchToolsTest.class);
|
||||
private static final String API_SECRET_KEY = "xx";
|
||||
|
||||
private static final ClientV4 client = new ClientV4.Builder(API_SECRET_KEY)
|
||||
.networkConfig(300, 100, 100, 100, TimeUnit.SECONDS)
|
||||
.connectionPool(new okhttp3.ConnectionPool(8, 1, TimeUnit.SECONDS))
|
||||
.build();
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
// 请自定义自己的业务id
|
||||
private static final String requestIdTemplate = "mycompany-%d";
|
||||
|
||||
|
||||
@Test
|
||||
public void test1() throws JsonProcessingException {
|
||||
|
||||
// json 转换 ArrayList<SearchChatMessage>
|
||||
String jsonString = "[\n" +
|
||||
" {\n" +
|
||||
" \"content\": \"今天武汉天气怎么样\",\n" +
|
||||
" \"role\": \"user\"\n" +
|
||||
" }\n" +
|
||||
" ]";
|
||||
|
||||
ArrayList<SearchChatMessage> messages = new ObjectMapper().readValue(jsonString, new TypeReference<ArrayList<SearchChatMessage>>() {
|
||||
});
|
||||
|
||||
|
||||
String requestId = String.format(requestIdTemplate, System.currentTimeMillis());
|
||||
WebSearchParamsRequest chatCompletionRequest = WebSearchParamsRequest.builder()
|
||||
.model("web-search-pro")
|
||||
.stream(Boolean.TRUE)
|
||||
.messages(messages)
|
||||
.requestId(requestId)
|
||||
.build();
|
||||
WebSearchApiResponse webSearchApiResponse = client.webSearchProStreamingInvoke(chatCompletionRequest);
|
||||
if (webSearchApiResponse.isSuccess()) {
|
||||
AtomicBoolean isFirst = new AtomicBoolean(true);
|
||||
List<ChoiceDelta> choices = new ArrayList<>();
|
||||
AtomicReference<WebSearchPro> lastAccumulator = new AtomicReference<>();
|
||||
|
||||
webSearchApiResponse.getFlowable().map(result -> result)
|
||||
.doOnNext(accumulator -> {
|
||||
{
|
||||
if (isFirst.getAndSet(false)) {
|
||||
logger.info("Response: ");
|
||||
}
|
||||
ChoiceDelta delta = accumulator.getChoices().get(0).getDelta();
|
||||
if (delta != null && delta.getToolCalls() != null) {
|
||||
logger.info("tool_calls: {}", mapper.writeValueAsString(delta.getToolCalls()));
|
||||
}
|
||||
choices.add(delta);
|
||||
lastAccumulator.set(accumulator);
|
||||
|
||||
}
|
||||
})
|
||||
.doOnComplete(() -> System.out.println("Stream completed."))
|
||||
.doOnError(throwable -> System.err.println("Error: " + throwable)) // Handle errors
|
||||
.blockingSubscribe();// Use blockingSubscribe instead of blockingGet()
|
||||
|
||||
WebSearchPro chatMessageAccumulator = lastAccumulator.get();
|
||||
|
||||
webSearchApiResponse.setFlowable(null);// 打印前置空
|
||||
webSearchApiResponse.setData(chatMessageAccumulator);
|
||||
}
|
||||
logger.info("model output: {}", mapper.writeValueAsString(webSearchApiResponse));
|
||||
client.getConfig().getHttpClient().dispatcher().executorService().shutdown();
|
||||
|
||||
client.getConfig().getHttpClient().connectionPool().evictAll();
|
||||
// List all active threads
|
||||
for (Thread t : Thread.getAllStackTraces().keySet()) {
|
||||
logger.info("Thread: " + t.getName() + " State: " + t.getState());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test2() throws JsonProcessingException {
|
||||
|
||||
// json 转换 ArrayList<SearchChatMessage>
|
||||
String jsonString = "[\n" +
|
||||
" {\n" +
|
||||
" \"content\": \"今天天气怎么样\",\n" +
|
||||
" \"role\": \"user\"\n" +
|
||||
" }\n" +
|
||||
" ]";
|
||||
|
||||
ArrayList<SearchChatMessage> messages = new ObjectMapper().readValue(jsonString, new TypeReference<ArrayList<SearchChatMessage>>() {
|
||||
});
|
||||
|
||||
|
||||
String requestId = String.format(requestIdTemplate, System.currentTimeMillis());
|
||||
WebSearchParamsRequest chatCompletionRequest = WebSearchParamsRequest.builder()
|
||||
.model("web-search-pro")
|
||||
.stream(Boolean.FALSE)
|
||||
.messages(messages)
|
||||
.requestId(requestId)
|
||||
.build();
|
||||
WebSearchApiResponse webSearchApiResponse = client.invokeWebSearchPro(chatCompletionRequest);
|
||||
|
||||
logger.info("model output: {}", mapper.writeValueAsString(webSearchApiResponse));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFunctionSSE() throws JsonProcessingException {
|
||||
List<ChatMessage> messages = new ArrayList<>();
|
||||
ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), "成都到北京要多久,天气如何");
|
||||
messages.add(chatMessage);
|
||||
String requestId = String.format(requestIdTemplate, System.currentTimeMillis());
|
||||
// 函数调用参数构建部分
|
||||
List<ChatTool> chatToolList = new ArrayList<>();
|
||||
ChatTool chatTool = new ChatTool();
|
||||
|
||||
chatTool.setType(ChatToolType.FUNCTION.value());
|
||||
ChatFunctionParameters chatFunctionParameters = new ChatFunctionParameters();
|
||||
chatFunctionParameters.setType("object");
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("location", new HashMap<String, Object>() {{
|
||||
put("type", "string");
|
||||
put("description", "城市,如:北京");
|
||||
}});
|
||||
properties.put("unit", new HashMap<String, Object>() {{
|
||||
put("type", "string");
|
||||
put("enum", new ArrayList<String>() {{
|
||||
add("celsius");
|
||||
add("fahrenheit");
|
||||
}});
|
||||
}});
|
||||
chatFunctionParameters.setProperties(properties);
|
||||
ChatFunction chatFunction = ChatFunction.builder()
|
||||
.name("get_weather")
|
||||
.description("Get the current weather of a location")
|
||||
.parameters(chatFunctionParameters)
|
||||
.build();
|
||||
chatTool.setFunction(chatFunction);
|
||||
chatToolList.add(chatTool);
|
||||
HashMap<String, Object> extraJson = new HashMap<>();
|
||||
extraJson.put("temperature", 0.5);
|
||||
extraJson.put("max_tokens", 50);
|
||||
|
||||
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
|
||||
.model(Constants.ModelChatGLM4)
|
||||
.stream(Boolean.TRUE)
|
||||
.messages(messages)
|
||||
.requestId(requestId)
|
||||
.tools(chatToolList)
|
||||
.toolChoice("auto")
|
||||
.extraJson(extraJson)
|
||||
.build();
|
||||
ModelApiResponse sseModelApiResp = client.invokeModelApi(chatCompletionRequest);
|
||||
if (sseModelApiResp.isSuccess()) {
|
||||
AtomicBoolean isFirst = new AtomicBoolean(true);
|
||||
List<Choice> choices = new ArrayList<>();
|
||||
ChatMessageAccumulator chatMessageAccumulator = mapStreamToAccumulator(sseModelApiResp.getFlowable())
|
||||
.doOnNext(accumulator -> {
|
||||
{
|
||||
if (isFirst.getAndSet(false)) {
|
||||
logger.info("Response: ");
|
||||
}
|
||||
if (accumulator.getDelta() != null && accumulator.getDelta().getTool_calls() != null) {
|
||||
String jsonString = mapper.writeValueAsString(accumulator.getDelta().getTool_calls());
|
||||
logger.info("tool_calls: {}", jsonString);
|
||||
}
|
||||
if (accumulator.getDelta() != null && accumulator.getDelta().getContent() != null) {
|
||||
logger.info(accumulator.getDelta().getContent());
|
||||
}
|
||||
choices.add(accumulator.getChoice());
|
||||
}
|
||||
})
|
||||
.doOnComplete(System.out::println)
|
||||
.lastElement()
|
||||
.blockingGet();
|
||||
|
||||
|
||||
ModelData data = new ModelData();
|
||||
data.setChoices(choices);
|
||||
data.setUsage(chatMessageAccumulator.getUsage());
|
||||
data.setId(chatMessageAccumulator.getId());
|
||||
data.setCreated(chatMessageAccumulator.getCreated());
|
||||
data.setRequestId(chatCompletionRequest.getRequestId());
|
||||
sseModelApiResp.setFlowable(null);// 打印前置空
|
||||
sseModelApiResp.setData(data);
|
||||
}
|
||||
logger.info("model output: {}", mapper.writeValueAsString(sseModelApiResp));
|
||||
}
|
||||
|
||||
public static Flowable<ChatMessageAccumulator> mapStreamToAccumulator(Flowable<ModelData> flowable) {
|
||||
return flowable.map(chunk -> {
|
||||
return new ChatMessageAccumulator(chunk.getChoices().get(0).getDelta(), null, chunk.getChoices().get(0), chunk.getUsage(), chunk.getCreated(), chunk.getId());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package org.ruoyi.common.chat.domain.request;
|
||||
|
||||
import org.ruoyi.common.chat.entity.chat.Message;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @sine 2023-04-08
|
||||
*/
|
||||
@Data
|
||||
public class ChatRequest {
|
||||
|
||||
|
||||
private String frequency_penalty;
|
||||
|
||||
private String max_tokens;
|
||||
|
||||
@NotEmpty(message = "对话消息不能为空")
|
||||
List<Message> messages;
|
||||
|
||||
@NotEmpty(message = "传入的模型不能为空")
|
||||
private String model;
|
||||
|
||||
private String presence_penalty;
|
||||
|
||||
private String stream;
|
||||
|
||||
private double temperature;
|
||||
|
||||
private double top_p = 1;
|
||||
|
||||
/**
|
||||
* 知识库id
|
||||
*/
|
||||
private String kid;
|
||||
|
||||
private String userId;
|
||||
//
|
||||
|
||||
//
|
||||
// /**
|
||||
// * gpt的默认设置
|
||||
// */
|
||||
// private String systemMessage = "";
|
||||
//
|
||||
//
|
||||
//
|
||||
// private double temperature = 0.2;
|
||||
//
|
||||
// /**
|
||||
// * 上下文的条数
|
||||
// */
|
||||
// private Integer contentNumber = 10;
|
||||
//
|
||||
// /**
|
||||
// * 是否携带上下文
|
||||
// */
|
||||
// private Boolean usingContext = Boolean.TRUE;
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package org.ruoyi.common.chat.domain.request;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @sine 2023-04-08
|
||||
*/
|
||||
@Data
|
||||
public class Dall3Request {
|
||||
|
||||
@NotEmpty(message = "传入的模型不能为空")
|
||||
private String model;
|
||||
|
||||
@NotEmpty(message = "提示词不能为空")
|
||||
private String prompt;
|
||||
|
||||
/** 图片大小 */
|
||||
@NotEmpty(message = "图片大小不能为空")
|
||||
private String size ;
|
||||
|
||||
/** 图片质量 */
|
||||
@NotEmpty(message = "图片质量不能为空")
|
||||
private String quality;
|
||||
|
||||
/** 图片风格 */
|
||||
@NotEmpty(message = "图片风格不能为空")
|
||||
private String style;
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:金额消耗信息
|
||||
* 金额消耗信息
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-04-08
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 描述:余额查询接口返回值
|
||||
* 余额查询接口返回值
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-18
|
||||
|
||||
@@ -7,7 +7,7 @@ import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:金额消耗列表
|
||||
* 金额消耗列表
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-04-08
|
||||
|
||||
@@ -7,7 +7,6 @@ import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-18
|
||||
|
||||
@@ -7,7 +7,6 @@ import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-18
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 描述:金额消耗列表
|
||||
* 金额消耗列表
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-04-08
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-04-08
|
||||
|
||||
@@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 描述:账户信息
|
||||
* 账户信息
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-04-08
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.util.Map;
|
||||
import static org.ruoyi.common.chat.entity.chat.BaseChatCompletion.Model.GPT_3_5_TURBO;
|
||||
|
||||
/**
|
||||
* 描述: chat模型基础类
|
||||
* chat模型基础类
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 1.1.2
|
||||
|
||||
@@ -12,7 +12,6 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 1.1.2
|
||||
|
||||
@@ -7,7 +7,6 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-02
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述: chat模型参数
|
||||
* chat模型参数
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-03-02
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述: chat答案类
|
||||
* chat答案类
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-03-02
|
||||
|
||||
@@ -11,7 +11,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述: chat模型附带图片的参数
|
||||
* : chat模型附带图片的参数
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 1.1.2
|
||||
|
||||
@@ -6,7 +6,6 @@ import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https://www.unfbx.com
|
||||
* @since 1.1.2
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.ruoyi.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class FastGPTAnswerResponse {
|
||||
private String id;
|
||||
private String object;
|
||||
private long created;
|
||||
private String model;
|
||||
private List<FastGPTChatChoice> choices;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package tech.ordinaryroad.live.chat.client.douyu.client;
|
||||
package org.ruoyi.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -6,15 +6,9 @@ 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 {
|
||||
public class FastGPTChatChoice implements Serializable {
|
||||
private long index;
|
||||
/**
|
||||
* 请求参数stream为true返回是delta
|
||||
@@ -28,4 +22,4 @@ public class ChatChoice implements Serializable {
|
||||
private Message message;
|
||||
@JsonProperty("finish_reason")
|
||||
private String finishReason;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.ruoyi.common.chat.entity.chat;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class FastGPTChatCompletion extends ChatCompletion implements Serializable {
|
||||
|
||||
/**
|
||||
* 是否使用FastGPT提供的上下文
|
||||
*/
|
||||
private String chatId;
|
||||
|
||||
|
||||
/**
|
||||
* 是否返回详细信息;stream模式下会通过event进行区分,非stream模式结果保存在responseData中.
|
||||
*/
|
||||
private boolean detail;
|
||||
|
||||
|
||||
/**
|
||||
* 运行时变量
|
||||
* 模块变量,一个对象,会替换模块中,输入fastgpt框内容里的{{key}}
|
||||
*/
|
||||
private Variables variables;
|
||||
|
||||
/**
|
||||
* responseChatItemId: string | undefined 。
|
||||
* 如果传入,则会将该值作为本次对话的响应消息的 ID,
|
||||
* FastGPT 会自动将该 ID 存入数据库。请确保,
|
||||
* 在当前chatId下,responseChatItemId是唯一的。
|
||||
*/
|
||||
private String responseChatItemId;
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 描述:函数调用返回值
|
||||
* 函数调用返回值
|
||||
*
|
||||
* @author https://www.unfbx.com
|
||||
* @since 2023-06-14
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:方法参数实体类,实例数据如下
|
||||
* 方法参数实体类,实例数据如下
|
||||
* <pre>
|
||||
* {
|
||||
* "name": "get_current_weather",
|
||||
|
||||
@@ -8,7 +8,6 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https://www.unfbx.com
|
||||
* 2023-11-10
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.ruoyi.common.chat.entity.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import org.ruoyi.common.chat.entity.chat.tool.ToolCalls;
|
||||
|
||||
@@ -9,7 +10,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-02
|
||||
@@ -20,6 +21,8 @@ import java.util.List;
|
||||
public class Message extends BaseMessage implements Serializable {
|
||||
|
||||
private Object content;
|
||||
@JsonProperty("reasoning_content")
|
||||
private String reasoningContent;
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
|
||||
@@ -10,8 +10,6 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-02
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
/**
|
||||
* 描述:方法参数类,扩展参数可以继承Parameters自己实现
|
||||
* 方法参数类,扩展参数可以继承Parameters自己实现
|
||||
* 参考:
|
||||
* <pre>
|
||||
* {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.ruoyi.common.chat.entity.chat;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Variables implements Serializable {
|
||||
|
||||
private String uid;
|
||||
|
||||
private String name;
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -7,7 +7,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 描述: 问题类
|
||||
* 问题类
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-11
|
||||
|
||||
@@ -9,7 +9,7 @@ import org.ruoyi.common.chat.entity.common.Usage;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述: 答案类
|
||||
* 答案类
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-11
|
||||
|
||||
@@ -7,7 +7,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -9,7 +9,7 @@ import org.ruoyi.common.chat.entity.common.Usage;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -11,7 +11,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -11,7 +11,7 @@ import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -7,7 +7,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Getter;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Getter;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -7,7 +7,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -7,7 +7,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 描述:文本审核,敏感词鉴别
|
||||
* 文本审核,敏感词鉴别
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -7,7 +7,7 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:
|
||||
*
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* 2023-02-15
|
||||
|
||||
@@ -7,7 +7,7 @@ import lombok.Getter;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 描述:语音转文字
|
||||
* 语音转文字
|
||||
*
|
||||
* @author https:www.unfbx.com
|
||||
* @since 2023-03-02
|
||||
|
||||