Merge remote-tracking branch 'refs/remotes/origin/dev-feature/ai-v1.0' into dev-feature/v1.1

This commit is contained in:
weike001 2025-05-26 15:39:26 +08:00
commit 3be96d9bfc
140 changed files with 12129 additions and 15 deletions

316
nacos/LICENSE Normal file
View File

@ -0,0 +1,316 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (properties) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
------
This product has a bundle logback, which is available under the EPL v1.0 License.
The source code of logback can be found at https://github.com/qos-ch/logback.
Logback LICENSE
---------------
Logback: the reliable, generic, fast and flexible logging framework.
Copyright (C) 1999-2015, QOS.ch. All rights reserved.
This program and the accompanying materials are dual-licensed under
either the terms of the Eclipse Public License v1.0 as published by
the Eclipse Foundation
or (per the licensee's choosing)
under the terms of the GNU Lesser General Public License version 2.1
as published by the Free Software Foundation.
------
This product has a bundle slf4j, which is available under the MIT License.
The source code of slf4j can be found at https://github.com/qos-ch/slf4j.
Copyright (c) 2004-2017 QOS.ch
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------
This product has a bundle javassist, which is available under the ASL2 License.
The source code of javassist can be found at https://github.com/jboss-javassist/javassist.
Copyright (C) 1999- by Shigeru Chiba, All rights reserved.
Javassist (JAVA programming ASSISTant) makes Java bytecode manipulation simple.
It is a class library for editing bytecodes in Java; it enables Java programs to define a new class
at runtime and to modify a class file when the JVM loads it. Unlike other similar bytecode editors,
Javassist provides two levels of API: source level and bytecode level. If the users use the source- level API,
they can edit a class file without knowledge of the specifications of the Java bytecode.
The whole API is designed with only the vocabulary of the Java language.
You can even specify inserted bytecode in the form of source text; Javassist compiles it on the fly.
On the other hand, the bytecode-level API allows the users to directly edit a class file as other editors.
This software is distributed under the Mozilla Public License Version 1.1,
the GNU Lesser General Public License Version 2.1 or later, or the Apache License Version 2.0.
------
This product has a bundle jna, which is available under the ASL2 License.
The source code of jna can be found at https://github.com/java-native-access/jna.
This copy of JNA is licensed under the
Apache (Software) License, version 2.0 ("the License").
See the License for details about distribution rights, and the
specific rights regarding derivate works.
You may obtain a copy of the License at:
http://www.apache.org/licenses/
A copy is also included in the downloadable source code package
containing JNA, in file "AL2.0", under the same directory
as this file.
------
This product has a bundle guava, which is available under the ASL2 License.
The source code of guava can be found at https://github.com/google/guava.
Copyright (C) 2007 The Guava authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
------
This product has a bundle OpenMessaging, which is available under the ASL2 License.
The source code of OpenMessaging can be found at https://github.com/openmessaging/openmessaging.
Copyright (C) 2017 The OpenMessaging authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

36
nacos/NOTICE Normal file
View File

@ -0,0 +1,36 @@
Nacos
Copyright 2018-2019 The Apache Software Foundation
This product includes software developed at
The Alibaba MiddleWare Group.
------
This product has a bundle netty:
The Spring oot Project
=================
Please visit the Netty web site for more information:
* http://netty.io/
Copyright 2014 The Netty Project
The Netty Project licenses this file to you under the Apache License,
version 2.0 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Also, please refer to each LICENSE.<component>.txt file, which is located in
the 'license' directory of the distribution file, for the license terms of the
components that this product depends on.
------
This product has a bundle commons-lang, which includes software from the Spring Framework,
under the Apache License 2.0 (see: StringUtils.containsWhitespace())

40
nacos/bin/shutdown.cmd Normal file
View File

@ -0,0 +1,40 @@
@echo off
:: Copyright 1999-2018 Alibaba Group Holding Ltd.
:: Licensed under the Apache License, Version 2.0 (the "License");
:: you may not use this file except in compliance with the License.
:: You may obtain a copy of the License at
::
:: http://www.apache.org/licenses/LICENSE-2.0
::
:: Unless required by applicable law or agreed to in writing, software
:: distributed under the License is distributed on an "AS IS" BASIS,
:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
:: See the License for the specific language governing permissions and
:: limitations under the License.
if not exist "%JAVA_HOME%\bin\jps.exe" (
echo Please set the JAVA_HOME variable in your environment to the correct JDK directory.
echo JDK8 or later is recommended!
EXIT /B 1
)
setlocal
set "PATH=%JAVA_HOME%\bin;%PATH%"
echo Killing Nacos server...
:: Find and kill Nacos server process
set "NACOS_RUNNING=false"
for /f "tokens=1" %%i in ('jps -m ^| find "nacos.nacos"') do (
set "NACOS_RUNNING=true"
taskkill /F /PID %%i
)
if "%NACOS_RUNNING%"=="true" (
echo Nacos server stopped.
) else (
echo Nacos server is not running.
)
echo Done!

28
nacos/bin/shutdown.sh Normal file
View File

@ -0,0 +1,28 @@
#!/bin/bash
# Copyright 1999-2018 Alibaba Group Holding Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
cd `dirname $0`/../target
target_dir=`pwd`
pid=`pgrep -f nacos.nacos`
if [ -z "$pid" ] ; then
echo "No nacosServer running."
exit -1;
fi
echo "The nacosServer(${pid}) is running..."
kill ${pid}
echo "Send shutdown request to nacosServer(${pid}) OK"

96
nacos/bin/startup.cmd Normal file
View File

@ -0,0 +1,96 @@
@echo off
rem Copyright 1999-2018 Alibaba Group Holding Ltd.
rem Licensed under the Apache License, Version 2.0 (the "License");
rem you may not use this file except in compliance with the License.
rem You may obtain a copy of the License at
rem
rem http://www.apache.org/licenses/LICENSE-2.0
rem
rem Unless required by applicable law or agreed to in writing, software
rem distributed under the License is distributed on an "AS IS" BASIS,
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rem See the License for the specific language governing permissions and
rem limitations under the License.
if not exist "%JAVA_HOME%\bin\java.exe" echo Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better! & EXIT /B 1
set "JAVA=%JAVA_HOME%\bin\java.exe"
setlocal enabledelayedexpansion
set BASE_DIR=%~dp0
rem added double quotation marks to avoid the issue caused by the folder names containing spaces.
rem removed the last 5 chars(which means \bin\) to get the base DIR.
set BASE_DIR="%BASE_DIR:~0,-5%"
set CUSTOM_SEARCH_LOCATIONS=file:%BASE_DIR%/conf/
set MODE="cluster"
set FUNCTION_MODE="all"
set SERVER=nacos-server
set MODE_INDEX=-1
set FUNCTION_MODE_INDEX=-1
set SERVER_INDEX=-1
set EMBEDDED_STORAGE_INDEX=-1
set EMBEDDED_STORAGE=""
set i=0
for %%a in (%*) do (
if "%%a" == "-m" ( set /a MODE_INDEX=!i!+1 )
if "%%a" == "-f" ( set /a FUNCTION_MODE_INDEX=!i!+1 )
if "%%a" == "-s" ( set /a SERVER_INDEX=!i!+1 )
if "%%a" == "-p" ( set /a EMBEDDED_STORAGE_INDEX=!i!+1 )
set /a i+=1
)
set i=0
for %%a in (%*) do (
if %MODE_INDEX% == !i! ( set MODE="%%a" )
if %FUNCTION_MODE_INDEX% == !i! ( set FUNCTION_MODE="%%a" )
if %SERVER_INDEX% == !i! (set SERVER="%%a")
if %EMBEDDED_STORAGE_INDEX% == !i! (set EMBEDDED_STORAGE="%%a")
set /a i+=1
)
rem if nacos startup mode is standalone
if %MODE% == "standalone" (
echo "nacos is starting with standalone"
set "NACOS_OPTS=-Dnacos.standalone=true"
if "%CUSTOM_NACOS_MEMORY%"=="" ( set "CUSTOM_NACOS_MEMORY=-Xms512m -Xmx512m -Xmn256m" )
set "NACOS_JVM_OPTS=%CUSTOM_NACOS_MEMORY%"
)
rem if nacos startup mode is cluster
if %MODE% == "cluster" (
echo "nacos is starting with cluster"
if %EMBEDDED_STORAGE% == "embedded" (
set "NACOS_OPTS=-DembeddedStorage=true"
)
if "%CUSTOM_NACOS_MEMORY%"=="" ( set "CUSTOM_NACOS_MEMORY=-Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m" )
set "NACOS_JVM_OPTS=-server %CUSTOM_NACOS_MEMORY% -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%BASE_DIR%\logs\java_heapdump.hprof -XX:-UseLargePages"
)
rem set nacos's functionMode
if %FUNCTION_MODE% == "config" (
set "NACOS_OPTS=%NACOS_OPTS% -Dnacos.functionMode=config"
)
if %FUNCTION_MODE% == "naming" (
set "NACOS_OPTS=%NACOS_OPTS% -Dnacos.functionMode=naming"
)
rem set nacos options
set "NACOS_OPTS=%NACOS_OPTS% -Dloader.path=%BASE_DIR%/plugins,%BASE_DIR%/plugins/health,%BASE_DIR%/plugins/cmdb,%BASE_DIR%/plugins/selector"
set "NACOS_OPTS=%NACOS_OPTS% -Dnacos.home=%BASE_DIR%"
set "NACOS_OPTS=%NACOS_OPTS% -jar %BASE_DIR%\target\%SERVER%.jar"
rem set nacos spring config location
set "NACOS_CONFIG_OPTS=--spring.config.additional-location=%CUSTOM_SEARCH_LOCATIONS%"
rem set nacos log4j file location
set "NACOS_LOG4J_OPTS=--logging.config=%BASE_DIR%/conf/nacos-logback.xml"
set COMMAND="%JAVA%" %NACOS_JVM_OPTS% %NACOS_OPTS% %NACOS_CONFIG_OPTS% %NACOS_LOG4J_OPTS% nacos.nacos %*
rem start nacos command
%COMMAND%

153
nacos/bin/startup.sh Normal file
View File

@ -0,0 +1,153 @@
#!/bin/bash
# Copyright 1999-2018 Alibaba Group Holding Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
cygwin=false
darwin=false
os400=false
case "`uname`" in
CYGWIN*) cygwin=true;;
Darwin*) darwin=true;;
OS400*) os400=true;;
esac
error_exit ()
{
echo "ERROR: $1 !!"
exit 1
}
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/opt/taobao/java
[ ! -e "$JAVA_HOME/bin/java" ] && unset JAVA_HOME
if [ -z "$JAVA_HOME" ]; then
if $darwin; then
if [ -x '/usr/libexec/java_home' ] ; then
export JAVA_HOME=`/usr/libexec/java_home`
elif [ -d "/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home" ]; then
export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home"
fi
else
JAVA_PATH=`dirname $(readlink -f $(which javac))`
if [ "x$JAVA_PATH" != "x" ]; then
export JAVA_HOME=`dirname $JAVA_PATH 2>/dev/null`
fi
fi
if [ -z "$JAVA_HOME" ]; then
JAVA_PATH=$(which java)
if [ -z "$JAVA_PATH" ]; then
error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better!"
fi
JAVA_HOME=$(dirname "$JAVA_PATH")/..
export JAVA_HOME=$(cd "$JAVA_HOME" && pwd)
fi
fi
export SERVER="nacos-server"
export MODE="cluster"
export FUNCTION_MODE="all"
export MEMBER_LIST=""
export EMBEDDED_STORAGE=""
while getopts ":m:f:s:c:p:" opt
do
case $opt in
m)
MODE=$OPTARG;;
f)
FUNCTION_MODE=$OPTARG;;
s)
SERVER=$OPTARG;;
c)
MEMBER_LIST=$OPTARG;;
p)
EMBEDDED_STORAGE=$OPTARG;;
?)
echo "Unknown parameter"
exit 1;;
esac
done
export JAVA_HOME
export JAVA="$JAVA_HOME/bin/java"
export BASE_DIR=`cd $(dirname $0)/..; pwd`
export CUSTOM_SEARCH_LOCATIONS=file:${BASE_DIR}/conf/
#===========================================================================================
# JVM Configuration
#===========================================================================================
if [[ "${MODE}" == "standalone" ]]; then
JAVA_OPT="${JAVA_OPT} ${CUSTOM_NACOS_MEMORY:- -Xms512m -Xmx512m -Xmn256m}"
JAVA_OPT="${JAVA_OPT} -Dnacos.standalone=true"
else
if [[ "${EMBEDDED_STORAGE}" == "embedded" ]]; then
JAVA_OPT="${JAVA_OPT} -DembeddedStorage=true"
fi
JAVA_OPT="${JAVA_OPT} -server ${CUSTOM_NACOS_MEMORY:- -Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m}"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs/java_heapdump.hprof"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages"
fi
if [[ "${FUNCTION_MODE}" == "config" ]]; then
JAVA_OPT="${JAVA_OPT} -Dnacos.functionMode=config"
elif [[ "${FUNCTION_MODE}" == "naming" ]]; then
JAVA_OPT="${JAVA_OPT} -Dnacos.functionMode=naming"
fi
JAVA_OPT="${JAVA_OPT} -Dnacos.member.list=${MEMBER_LIST}"
JAVA_MAJOR_VERSION=$($JAVA -version 2>&1 | sed -E -n 's/.* version "([0-9]*).*$/\1/p')
if [[ "$JAVA_MAJOR_VERSION" -ge "9" ]] ; then
JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${BASE_DIR}/logs/nacos_gc.log:time,tags:filecount=10,filesize=100m"
else
JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 "
JAVA_OPT_EXT_FIX="-Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${JAVA_HOME}/lib/ext"
JAVA_OPT="${JAVA_OPT} -Xloggc:${BASE_DIR}/logs/nacos_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
fi
JAVA_OPT="${JAVA_OPT} -Dloader.path=${BASE_DIR}/plugins,${BASE_DIR}/plugins/health,${BASE_DIR}/plugins/cmdb,${BASE_DIR}/plugins/selector"
JAVA_OPT="${JAVA_OPT} -Dnacos.home=${BASE_DIR}"
JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/target/${SERVER}.jar"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} --spring.config.additional-location=${CUSTOM_SEARCH_LOCATIONS}"
JAVA_OPT="${JAVA_OPT} --logging.config=${BASE_DIR}/conf/nacos-logback.xml"
JAVA_OPT="${JAVA_OPT} --server.max-http-header-size=524288"
if [ ! -d "${BASE_DIR}/logs" ]; then
mkdir ${BASE_DIR}/logs
fi
echo "$JAVA $JAVA_OPT_EXT_FIX ${JAVA_OPT}"
if [[ "${MODE}" == "standalone" ]]; then
echo "nacos is starting with standalone"
else
echo "nacos is starting with cluster"
fi
# check the start.out log output file
if [ ! -f "${BASE_DIR}/logs/start.out" ]; then
touch "${BASE_DIR}/logs/start.out"
fi
# start
echo "$JAVA $JAVA_OPT_EXT_FIX ${JAVA_OPT}" > ${BASE_DIR}/logs/start.out 2>&1 &
if [[ "$JAVA_OPT_EXT_FIX" == "" ]]; then
nohup "$JAVA" ${JAVA_OPT} nacos.nacos >> ${BASE_DIR}/logs/start.out 2>&1 &
else
nohup "$JAVA" "$JAVA_OPT_EXT_FIX" ${JAVA_OPT} nacos.nacos >> ${BASE_DIR}/logs/start.out 2>&1 &
fi
echo "nacos is starting. you can check the ${BASE_DIR}/logs/start.out"

View File

@ -0,0 +1,27 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
ALTER TABLE `config_info_tag`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;
ALTER TABLE `his_config_info`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL AFTER `src_user`;
ALTER TABLE `config_info`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;
ALTER TABLE `config_info_beta`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;

View File

@ -0,0 +1 @@
Authentication has not been enabled in cluster, please refer to <a href="https://nacos.io/en-us/docs/v2/guide/user/auth.html">Documentation</a> to enable~

View File

@ -0,0 +1 @@
当前集群没有开启鉴权,请参考<a href="https://nacos.io/zh-cn/docs/v2/guide/user/auth.html">文档</a>开启鉴权~

View File

@ -0,0 +1,297 @@
#
# Copyright 1999-2021 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#*************** Spring Boot Related Configurations ***************#
### Default web context path:
server.servlet.contextPath=/nacos
### Include message field
server.error.include-message=ALWAYS
### Default web server port:
server.port=8848
#*************** Network Related Configurations ***************#
### If prefer hostname over ip for Nacos server addresses in cluster.conf:
# nacos.inetutils.prefer-hostname-over-ip=false
### Specify local server's IP:
# nacos.inetutils.ip-address=
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.
# spring.datasource.platform=mysql
spring.sql.init.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.0.17:3306/ruoyi-vue-pro?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root
### Connection pool configuration: hikariCP
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
### the maximum retry times for push
nacos.config.push.maxRetryTime=50
#*************** Naming Module Related Configurations ***************#
### If enable data warmup. If set to false, the server would accept request without local data preparation:
# nacos.naming.data.warmup=true
### If enable the instance auto expiration, kind like of health check of instance:
# nacos.naming.expireInstance=true
### Add in 2.0.0
### The interval to clean empty service, unit: milliseconds.
# nacos.naming.clean.empty-service.interval=60000
### The expired time to clean empty service, unit: milliseconds.
# nacos.naming.clean.empty-service.expired-time=60000
### The interval to clean expired metadata, unit: milliseconds.
# nacos.naming.clean.expired-metadata.interval=5000
### The expired time to clean metadata, unit: milliseconds.
# nacos.naming.clean.expired-metadata.expired-time=60000
### The delay time before push task to execute from service changed, unit: milliseconds.
# nacos.naming.push.pushTaskDelay=500
### The timeout for push task execute, unit: milliseconds.
# nacos.naming.push.pushTaskTimeout=5000
### The delay time for retrying failed push task, unit: milliseconds.
# nacos.naming.push.pushTaskRetryDelay=1000
### Since 2.0.3
### The expired time for inactive client, unit: milliseconds.
# nacos.naming.client.expired.time=180000
#*************** CMDB Module Related Configurations ***************#
### The interval to dump external CMDB in seconds:
# nacos.cmdb.dumpTaskInterval=3600
### The interval of polling data change event in seconds:
# nacos.cmdb.eventTaskInterval=10
### The interval of loading labels in seconds:
# nacos.cmdb.labelTaskInterval=300
### If turn on data loading task:
# nacos.cmdb.loadDataAtStart=false
#***********Metrics for tomcat **************************#
server.tomcat.mbeanregistry.enabled=true
#***********Expose prometheus and health **************************#
#management.endpoints.web.exposure.include=prometheus,health
### Metrics for elastic search
management.metrics.export.elastic.enabled=false
#management.metrics.export.elastic.host=http://localhost:9200
### Metrics for influx
management.metrics.export.influx.enabled=false
#management.metrics.export.influx.db=springboot
#management.metrics.export.influx.uri=http://localhost:8086
#management.metrics.export.influx.auto-create-db=true
#management.metrics.export.influx.consistency=one
#management.metrics.export.influx.compressed=true
#*************** Access Log Related Configurations ***************#
### If turn on the access log:
server.tomcat.accesslog.enabled=true
### file name pattern, one file per hour
server.tomcat.accesslog.rotate=true
server.tomcat.accesslog.file-date-format=.yyyy-MM-dd-HH
### The access log pattern:
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
### The directory of access log:
server.tomcat.basedir=file:.
#*************** Access Control Related Configurations ***************#
### If enable spring security, this option is deprecated in 1.2.0:
#spring.security.enabled=false
### The ignore urls of auth
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
### The auth system to use, currently only 'nacos' and 'ldap' is supported:
nacos.core.auth.system.type=nacos
### If turn on auth system:
nacos.core.auth.enabled=false
### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=true
### Since 1.4.1, Turn on/off white auth for user-agent: nacos-server, only for upgrade from old version.
nacos.core.auth.enable.userAgentAuthWhite=false
### Since 1.4.1, worked when nacos.core.auth.enabled=true and nacos.core.auth.enable.userAgentAuthWhite=false.
### The two properties is the white list for auth and used by identity the request from other server.
nacos.core.auth.server.identity.key=
nacos.core.auth.server.identity.value=
### worked when nacos.core.auth.system.type=nacos
### The token expiration in seconds:
nacos.core.auth.plugin.nacos.token.cache.enable=false
nacos.core.auth.plugin.nacos.token.expire.seconds=18000
### The default token (Base64 String):
nacos.core.auth.plugin.nacos.token.secret.key=
### worked when nacos.core.auth.system.type=ldap\uFF0C{0} is Placeholder,replace login username
#nacos.core.auth.ldap.url=ldap://localhost:389
#nacos.core.auth.ldap.basedc=dc=example,dc=org
#nacos.core.auth.ldap.userDn=cn=admin,${nacos.core.auth.ldap.basedc}
#nacos.core.auth.ldap.password=admin
#nacos.core.auth.ldap.userdn=cn={0},dc=example,dc=org
#nacos.core.auth.ldap.filter.prefix=uid
#nacos.core.auth.ldap.case.sensitive=true
#nacos.core.auth.ldap.ignore.partial.result.exception=false
#*************** Control Plugin Related Configurations ***************#
# plugin type
#nacos.plugin.control.manager.type=nacos
# local control rule storage dir, default ${nacos.home}/data/connection and ${nacos.home}/data/tps
#nacos.plugin.control.rule.local.basedir=${nacos.home}
# external control rule storage type, if exist
#nacos.plugin.control.rule.external.storage=
#*************** Config Change Plugin Related Configurations ***************#
# webhook
#nacos.core.config.plugin.webhook.enabled=false
# It is recommended to use EB https://help.aliyun.com/document_detail/413974.html
#nacos.core.config.plugin.webhook.url=http://localhost:8080/webhook/send?token=***
# The content push max capacity ,byte
#nacos.core.config.plugin.webhook.contentMaxCapacity=102400
# whitelist
#nacos.core.config.plugin.whitelist.enabled=false
# The import file suffixs
#nacos.core.config.plugin.whitelist.suffixs=xml,text,properties,yaml,html
# fileformatcheck,which validate the import file of type and content
#nacos.core.config.plugin.fileformatcheck.enabled=false
#*************** Istio Related Configurations ***************#
### If turn on the MCP server:
nacos.istio.mcp.server.enabled=false
#*************** Core Related Configurations ***************#
### set the WorkerID manually
# nacos.core.snowflake.worker-id=
### Member-MetaData
# nacos.core.member.meta.site=
# nacos.core.member.meta.adweight=
# nacos.core.member.meta.weight=
### MemberLookup
### Addressing pattern category, If set, the priority is highest
# nacos.core.member.lookup.type=[file,address-server]
## Set the cluster list with a configuration file or command-line argument
# nacos.member.list=192.168.16.101:8847?raft_port=8807,192.168.16.101?raft_port=8808,192.168.16.101:8849?raft_port=8809
## for AddressServerMemberLookup
# Maximum number of retries to query the address server upon initialization
# nacos.core.address-server.retry=5
## Server domain name address of [address-server] mode
# address.server.domain=jmenv.tbsite.net
## Server port of [address-server] mode
# address.server.port=8080
## Request address of [address-server] mode
# address.server.url=/nacos/serverlist
#*************** JRaft Related Configurations ***************#
### Sets the Raft cluster election timeout, default value is 5 second
# nacos.core.protocol.raft.data.election_timeout_ms=5000
### Sets the amount of time the Raft snapshot will execute periodically, default is 30 minute
# nacos.core.protocol.raft.data.snapshot_interval_secs=30
### raft internal worker threads
# nacos.core.protocol.raft.data.core_thread_num=8
### Number of threads required for raft business request processing
# nacos.core.protocol.raft.data.cli_service_thread_num=4
### raft linear read strategy. Safe linear reads are used by default, that is, the Leader tenure is confirmed by heartbeat
# nacos.core.protocol.raft.data.read_index_type=ReadOnlySafe
### rpc request timeout, default 5 seconds
# nacos.core.protocol.raft.data.rpc_request_timeout_ms=5000
#*************** Distro Related Configurations ***************#
### Distro data sync delay time, when sync task delayed, task will be merged for same data key. Default 1 second.
# nacos.core.protocol.distro.data.sync.delayMs=1000
### Distro data sync timeout for one sync data, default 3 seconds.
# nacos.core.protocol.distro.data.sync.timeoutMs=3000
### Distro data sync retry delay time when sync data failed or timeout, same behavior with delayMs, default 3 seconds.
# nacos.core.protocol.distro.data.sync.retryDelayMs=3000
### Distro data verify interval time, verify synced data whether expired for a interval. Default 5 seconds.
# nacos.core.protocol.distro.data.verify.intervalMs=5000
### Distro data verify timeout for one verify, default 3 seconds.
# nacos.core.protocol.distro.data.verify.timeoutMs=3000
### Distro data load retry delay when load snapshot data failed, default 30 seconds.
# nacos.core.protocol.distro.data.load.retryDelayMs=30000
### enable to support prometheus service discovery
#nacos.prometheus.metrics.enabled=true
### Since 2.3
#*************** Grpc Configurations ***************#
## sdk grpc(between nacos server and client) configuration
## Sets the maximum message size allowed to be received on the server.
#nacos.remote.server.grpc.sdk.max-inbound-message-size=10485760
## Sets the time(milliseconds) without read activity before sending a keepalive ping. The typical default is two hours.
#nacos.remote.server.grpc.sdk.keep-alive-time=7200000
## Sets a time(milliseconds) waiting for read activity after sending a keepalive ping. Defaults to 20 seconds.
#nacos.remote.server.grpc.sdk.keep-alive-timeout=20000
## Sets a time(milliseconds) that specify the most aggressive keep-alive time clients are permitted to configure. The typical default is 5 minutes
#nacos.remote.server.grpc.sdk.permit-keep-alive-time=300000
## cluster grpc(inside the nacos server) configuration
#nacos.remote.server.grpc.cluster.max-inbound-message-size=10485760
## Sets the time(milliseconds) without read activity before sending a keepalive ping. The typical default is two hours.
#nacos.remote.server.grpc.cluster.keep-alive-time=7200000
## Sets a time(milliseconds) waiting for read activity after sending a keepalive ping. Defaults to 20 seconds.
#nacos.remote.server.grpc.cluster.keep-alive-timeout=20000
## Sets a time(milliseconds) that specify the most aggressive keep-alive time clients are permitted to configure. The typical default is 5 minutes
#nacos.remote.server.grpc.cluster.permit-keep-alive-time=300000
## open nacos default console ui
#nacos.console.ui.enabled=true

View File

@ -0,0 +1,271 @@
#
# Copyright 1999-2021 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#*************** Spring Boot Related Configurations ***************#
### Default web context path:
server.servlet.contextPath=/nacos
### Include message field
server.error.include-message=ALWAYS
### Default web server port:
server.port=8848
#*************** Network Related Configurations ***************#
### If prefer hostname over ip for Nacos server addresses in cluster.conf:
# nacos.inetutils.prefer-hostname-over-ip=false
### Specify local server's IP:
# nacos.inetutils.ip-address=
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.
# spring.datasource.platform=mysql
# spring.sql.init.platform=mysql
### Count of DB:
# db.num=1
### Connect URL of DB:
# db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
# db.user.0=nacos
# db.password.0=nacos
### Connection pool configuration: hikariCP
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
### the maximum retry times for push
nacos.config.push.maxRetryTime=50
#*************** Naming Module Related Configurations ***************#
### If enable data warmup. If set to false, the server would accept request without local data preparation:
# nacos.naming.data.warmup=true
### If enable the instance auto expiration, kind like of health check of instance:
# nacos.naming.expireInstance=true
### will be removed and replaced by `nacos.naming.clean` properties
nacos.naming.empty-service.auto-clean=true
nacos.naming.empty-service.clean.initial-delay-ms=50000
nacos.naming.empty-service.clean.period-time-ms=30000
### Add in 2.0.0
### The interval to clean empty service, unit: milliseconds.
# nacos.naming.clean.empty-service.interval=60000
### The expired time to clean empty service, unit: milliseconds.
# nacos.naming.clean.empty-service.expired-time=60000
### The interval to clean expired metadata, unit: milliseconds.
# nacos.naming.clean.expired-metadata.interval=5000
### The expired time to clean metadata, unit: milliseconds.
# nacos.naming.clean.expired-metadata.expired-time=60000
### The delay time before push task to execute from service changed, unit: milliseconds.
# nacos.naming.push.pushTaskDelay=500
### The timeout for push task execute, unit: milliseconds.
# nacos.naming.push.pushTaskTimeout=5000
### The delay time for retrying failed push task, unit: milliseconds.
# nacos.naming.push.pushTaskRetryDelay=1000
### Since 2.0.3
### The expired time for inactive client, unit: milliseconds.
# nacos.naming.client.expired.time=180000
#*************** CMDB Module Related Configurations ***************#
### The interval to dump external CMDB in seconds:
# nacos.cmdb.dumpTaskInterval=3600
### The interval of polling data change event in seconds:
# nacos.cmdb.eventTaskInterval=10
### The interval of loading labels in seconds:
# nacos.cmdb.labelTaskInterval=300
### If turn on data loading task:
# nacos.cmdb.loadDataAtStart=false
#*************** Metrics Related Configurations ***************#
### Metrics for prometheus
#management.endpoints.web.exposure.include=*
### Metrics for elastic search
management.metrics.export.elastic.enabled=false
#management.metrics.export.elastic.host=http://localhost:9200
### Metrics for influx
management.metrics.export.influx.enabled=false
#management.metrics.export.influx.db=springboot
#management.metrics.export.influx.uri=http://localhost:8086
#management.metrics.export.influx.auto-create-db=true
#management.metrics.export.influx.consistency=one
#management.metrics.export.influx.compressed=true
#*************** Access Log Related Configurations ***************#
### If turn on the access log:
server.tomcat.accesslog.enabled=true
### The access log pattern:
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
### The directory of access log:
server.tomcat.basedir=file:.
#*************** Access Control Related Configurations ***************#
### If enable spring security, this option is deprecated in 1.2.0:
#spring.security.enabled=false
### The ignore urls of auth, is deprecated in 1.2.0:
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
### The auth system to use, currently only 'nacos' and 'ldap' is supported:
nacos.core.auth.system.type=nacos
### If turn on auth system:
nacos.core.auth.enabled=false
### worked when nacos.core.auth.system.type=ldap{0} is Placeholder,replace login username
#nacos.core.auth.system.type=ldap
#nacos.core.auth.ldap.url=ldap://localhost:389
#nacos.core.auth.ldap.basedc=dc=example,dc=org
#nacos.core.auth.ldap.userDn=cn=admin,${nacos.core.auth.ldap.basedc}
#nacos.core.auth.ldap.password=admin
#nacos.core.auth.ldap.userdn=cn={0},dc=example,dc=org
#nacos.core.auth.ldap.filter.prefix=uid
#nacos.core.auth.ldap.case.sensitive=true
#nacos.core.auth.ldap.ignore.partial.result.exception=false
### worked when nacos.core.auth.system.type=nacos
### The token expiration in seconds:
nacos.core.auth.plugin.nacos.token.cache.enable=false
nacos.core.auth.plugin.nacos.token.expire.seconds=18000
### The default token (Base64 String):
nacos.core.auth.plugin.nacos.token.secret.key=
### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=true
### Since 1.4.1, Turn on/off white auth for user-agent: nacos-server, only for upgrade from old version.
nacos.core.auth.enable.userAgentAuthWhite=false
### Since 1.4.1, worked when nacos.core.auth.enabled=true and nacos.core.auth.enable.userAgentAuthWhite=false.
### The two properties is the white list for auth and used by identity the request from other server.
#nacos.core.auth.server.identity.key=example
#nacos.core.auth.server.identity.value=example
#*************** Istio Related Configurations ***************#
### If turn on the MCP server:
nacos.istio.mcp.server.enabled=false
#*************** Core Related Configurations ***************#
### set the WorkerID manually
# nacos.core.snowflake.worker-id=
### Member-MetaData
# nacos.core.member.meta.site=
# nacos.core.member.meta.adweight=
# nacos.core.member.meta.weight=
### MemberLookup
### Addressing pattern category, If set, the priority is highest
# nacos.core.member.lookup.type=[file,address-server]
## Set the cluster list with a configuration file or command-line argument
# nacos.member.list=192.168.16.101:8847?raft_port=8807,192.168.16.101?raft_port=8808,192.168.16.101:8849?raft_port=8809
## for AddressServerMemberLookup
# Maximum number of retries to query the address server upon initialization
# nacos.core.address-server.retry=5
## Server domain name address of [address-server] mode
# address.server.domain=jmenv.tbsite.net
## Server port of [address-server] mode
# address.server.port=8080
## Request address of [address-server] mode
# address.server.url=/nacos/serverlist
#*************** JRaft Related Configurations ***************#
### Sets the Raft cluster election timeout, default value is 5 second
# nacos.core.protocol.raft.data.election_timeout_ms=5000
### Sets the amount of time the Raft snapshot will execute periodically, default is 30 minute
# nacos.core.protocol.raft.data.snapshot_interval_secs=30
### raft internal worker threads
# nacos.core.protocol.raft.data.core_thread_num=8
### Number of threads required for raft business request processing
# nacos.core.protocol.raft.data.cli_service_thread_num=4
### raft linear read strategy. Safe linear reads are used by default, that is, the Leader tenure is confirmed by heartbeat
# nacos.core.protocol.raft.data.read_index_type=ReadOnlySafe
### rpc request timeout, default 5 seconds
# nacos.core.protocol.raft.data.rpc_request_timeout_ms=5000
#*************** Distro Related Configurations ***************#
### Distro data sync delay time, when sync task delayed, task will be merged for same data key. Default 1 second.
# nacos.core.protocol.distro.data.sync.delayMs=1000
### Distro data sync timeout for one sync data, default 3 seconds.
# nacos.core.protocol.distro.data.sync.timeoutMs=3000
### Distro data sync retry delay time when sync data failed or timeout, same behavior with delayMs, default 3 seconds.
# nacos.core.protocol.distro.data.sync.retryDelayMs=3000
### Distro data verify interval time, verify synced data whether expired for a interval. Default 5 seconds.
# nacos.core.protocol.distro.data.verify.intervalMs=5000
### Distro data verify timeout for one verify, default 3 seconds.
# nacos.core.protocol.distro.data.verify.timeoutMs=3000
### Distro data load retry delay when load snapshot data failed, default 30 seconds.
# nacos.core.protocol.distro.data.load.retryDelayMs=30000
### enable to support prometheus service discovery
#nacos.prometheus.metrics.enabled=true
### Since 2.3
#*************** Grpc Configurations ***************#
## sdk grpc(between nacos server and client) configuration
## Sets the maximum message size allowed to be received on the server.
#nacos.remote.server.grpc.sdk.max-inbound-message-size=10485760
## Sets the time(milliseconds) without read activity before sending a keepalive ping. The typical default is two hours.
#nacos.remote.server.grpc.sdk.keep-alive-time=7200000
## Sets a time(milliseconds) waiting for read activity after sending a keepalive ping. Defaults to 20 seconds.
#nacos.remote.server.grpc.sdk.keep-alive-timeout=20000
## Sets a time(milliseconds) that specify the most aggressive keep-alive time clients are permitted to configure. The typical default is 5 minutes
#nacos.remote.server.grpc.sdk.permit-keep-alive-time=300000
## cluster grpc(inside the nacos server) configuration
#nacos.remote.server.grpc.cluster.max-inbound-message-size=10485760
## Sets the time(milliseconds) without read activity before sending a keepalive ping. The typical default is two hours.
#nacos.remote.server.grpc.cluster.keep-alive-time=7200000
## Sets a time(milliseconds) waiting for read activity after sending a keepalive ping. Defaults to 20 seconds.
#nacos.remote.server.grpc.cluster.keep-alive-timeout=20000
## Sets a time(milliseconds) that specify the most aggressive keep-alive time clients are permitted to configure. The typical default is 5 minutes
#nacos.remote.server.grpc.cluster.permit-keep-alive-time=300000

View File

@ -0,0 +1,21 @@
#
# Copyright 1999-2021 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#it is ip
#example
192.168.16.101:8847
192.168.16.102
192.168.16.103

View File

@ -0,0 +1 @@
当前节点已关闭Nacos开源控制台使用请修改application.properties中的nacos.console.ui.enabled参数为true打开开源控制台使用详情查看<a href="https://nacos.io/zh-cn/docs/v2/guide/admin/console-guide.html">文档</a>中关于<code>关闭默认控制台部分</code>。

227
nacos/conf/derby-schema.sql Normal file
View File

@ -0,0 +1,227 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
CREATE SCHEMA nacos AUTHORIZATION nacos;
CREATE TABLE config_info (
id bigint NOT NULL generated by default as identity,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) default '',
app_name varchar(128),
content CLOB,
md5 varchar(32) DEFAULT NULL,
gmt_create timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
gmt_modified timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
src_user varchar(128) DEFAULT NULL,
src_ip varchar(50) DEFAULT NULL,
c_desc varchar(256) DEFAULT NULL,
c_use varchar(64) DEFAULT NULL,
effect varchar(64) DEFAULT NULL,
type varchar(64) DEFAULT NULL,
c_schema LONG VARCHAR DEFAULT NULL,
encrypted_data_key LONG VARCHAR DEFAULT NULL,
constraint configinfo_id_key PRIMARY KEY (id),
constraint uk_configinfo_datagrouptenant UNIQUE (data_id,group_id,tenant_id));
CREATE INDEX configinfo_dataid_key_idx ON config_info(data_id);
CREATE INDEX configinfo_groupid_key_idx ON config_info(group_id);
CREATE INDEX configinfo_dataid_group_key_idx ON config_info(data_id, group_id);
CREATE TABLE his_config_info (
id bigint NOT NULL,
nid bigint NOT NULL generated by default as identity,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) default '',
app_name varchar(128),
content CLOB,
md5 varchar(32) DEFAULT NULL,
gmt_create timestamp NOT NULL DEFAULT '2010-05-05 00:00:00.000',
gmt_modified timestamp NOT NULL DEFAULT '2010-05-05 00:00:00.000',
src_user varchar(128),
src_ip varchar(50) DEFAULT NULL,
op_type char(10) DEFAULT NULL,
encrypted_data_key LONG VARCHAR DEFAULT NULL,
constraint hisconfiginfo_nid_key PRIMARY KEY (nid));
CREATE INDEX hisconfiginfo_dataid_key_idx ON his_config_info(data_id);
CREATE INDEX hisconfiginfo_gmt_create_idx ON his_config_info(gmt_create);
CREATE INDEX hisconfiginfo_gmt_modified_idx ON his_config_info(gmt_modified);
CREATE TABLE config_info_beta (
id bigint NOT NULL generated by default as identity,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) default '',
app_name varchar(128),
content CLOB,
beta_ips varchar(1024),
md5 varchar(32) DEFAULT NULL,
gmt_create timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
gmt_modified timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
src_user varchar(128),
src_ip varchar(50) DEFAULT NULL,
encrypted_data_key LONG VARCHAR DEFAULT NULL,
constraint configinfobeta_id_key PRIMARY KEY (id),
constraint uk_configinfobeta_datagrouptenant UNIQUE (data_id,group_id,tenant_id));
CREATE TABLE config_info_tag (
id bigint NOT NULL generated by default as identity,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) default '',
tag_id varchar(128) NOT NULL,
app_name varchar(128),
content CLOB,
md5 varchar(32) DEFAULT NULL,
gmt_create timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
gmt_modified timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
src_user varchar(128),
src_ip varchar(50) DEFAULT NULL,
constraint configinfotag_id_key PRIMARY KEY (id),
constraint uk_configinfotag_datagrouptenanttag UNIQUE (data_id,group_id,tenant_id,tag_id));
CREATE TABLE config_info_aggr (
id bigint NOT NULL generated by default as identity,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) default '',
datum_id varchar(255) NOT NULL,
app_name varchar(128),
content CLOB,
gmt_modified timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
constraint configinfoaggr_id_key PRIMARY KEY (id),
constraint uk_configinfoaggr_datagrouptenantdatum UNIQUE (data_id,group_id,tenant_id,datum_id));
CREATE TABLE app_list (
id bigint NOT NULL generated by default as identity,
app_name varchar(128) NOT NULL,
is_dynamic_collect_disabled smallint DEFAULT 0,
last_sub_info_collected_time timestamp DEFAULT '1970-01-01 08:00:00.0',
sub_info_lock_owner varchar(128),
sub_info_lock_time timestamp DEFAULT '1970-01-01 08:00:00.0',
constraint applist_id_key PRIMARY KEY (id),
constraint uk_appname UNIQUE (app_name));
CREATE TABLE app_configdata_relation_subs (
id bigint NOT NULL generated by default as identity,
app_name varchar(128) NOT NULL,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
gmt_modified timestamp DEFAULT '2010-05-05 00:00:00',
constraint configdatarelationsubs_id_key PRIMARY KEY (id),
constraint uk_app_sub_config_datagroup UNIQUE (app_name, data_id, group_id));
CREATE TABLE app_configdata_relation_pubs (
id bigint NOT NULL generated by default as identity,
app_name varchar(128) NOT NULL,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
gmt_modified timestamp DEFAULT '2010-05-05 00:00:00',
constraint configdatarelationpubs_id_key PRIMARY KEY (id),
constraint uk_app_pub_config_datagroup UNIQUE (app_name, data_id, group_id));
CREATE TABLE config_tags_relation (
id bigint NOT NULL,
tag_name varchar(128) NOT NULL,
tag_type varchar(64) DEFAULT NULL,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) DEFAULT '',
nid bigint NOT NULL generated by default as identity,
constraint config_tags_id_key PRIMARY KEY (nid),
constraint uk_configtagrelation_configidtag UNIQUE (id, tag_name, tag_type));
CREATE INDEX config_tags_tenant_id_idx ON config_tags_relation(tenant_id);
CREATE TABLE group_capacity (
id bigint NOT NULL generated by default as identity,
group_id varchar(128) DEFAULT '',
quota int DEFAULT 0,
usage int DEFAULT 0,
max_size int DEFAULT 0,
max_aggr_count int DEFAULT 0,
max_aggr_size int DEFAULT 0,
max_history_count int DEFAULT 0,
gmt_create timestamp DEFAULT '2010-05-05 00:00:00',
gmt_modified timestamp DEFAULT '2010-05-05 00:00:00',
constraint group_capacity_id_key PRIMARY KEY (id),
constraint uk_group_id UNIQUE (group_id));
CREATE TABLE tenant_capacity (
id bigint NOT NULL generated by default as identity,
tenant_id varchar(128) DEFAULT '',
quota int DEFAULT 0,
usage int DEFAULT 0,
max_size int DEFAULT 0,
max_aggr_count int DEFAULT 0,
max_aggr_size int DEFAULT 0,
max_history_count int DEFAULT 0,
gmt_create timestamp DEFAULT '2010-05-05 00:00:00',
gmt_modified timestamp DEFAULT '2010-05-05 00:00:00',
constraint tenant_capacity_id_key PRIMARY KEY (id),
constraint uk_tenant_id UNIQUE (tenant_id));
CREATE TABLE tenant_info (
id bigint NOT NULL generated by default as identity,
kp varchar(128) NOT NULL,
tenant_id varchar(128) DEFAULT '',
tenant_name varchar(128) DEFAULT '',
tenant_desc varchar(256) DEFAULT NULL,
create_source varchar(32) DEFAULT NULL,
gmt_create bigint NOT NULL,
gmt_modified bigint NOT NULL,
constraint tenant_info_id_key PRIMARY KEY (id),
constraint uk_tenant_info_kptenantid UNIQUE (kp,tenant_id));
CREATE INDEX tenant_info_tenant_id_idx ON tenant_info(tenant_id);
CREATE TABLE users (
username varchar(50) NOT NULL PRIMARY KEY,
password varchar(500) NOT NULL,
enabled boolean NOT NULL DEFAULT true
);
CREATE TABLE roles (
username varchar(50) NOT NULL,
role varchar(50) NOT NULL,
constraint uk_username_role UNIQUE (username,role)
);
CREATE TABLE permissions (
role varchar(50) NOT NULL,
resource varchar(512) NOT NULL,
action varchar(8) NOT NULL,
constraint uk_role_permission UNIQUE (role,resource,action)
);
/******************************************/
/* ipv6 support */
/******************************************/
ALTER TABLE `config_info_tag`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;
ALTER TABLE `his_config_info`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL AFTER `src_user`;
ALTER TABLE `config_info`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;
ALTER TABLE `config_info_beta`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;

210
nacos/conf/mysql-schema.sql Normal file
View File

@ -0,0 +1,210 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/******************************************/
/* 表名称 = config_info */
/******************************************/
CREATE TABLE `config_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) DEFAULT NULL COMMENT 'group_id',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`c_desc` varchar(256) DEFAULT NULL COMMENT 'configuration description',
`c_use` varchar(64) DEFAULT NULL COMMENT 'configuration usage',
`effect` varchar(64) DEFAULT NULL COMMENT '配置生效的描述',
`type` varchar(64) DEFAULT NULL COMMENT '配置的类型',
`c_schema` text COMMENT '配置的模式',
`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
/******************************************/
/* 表名称 = config_info_aggr */
/******************************************/
CREATE TABLE `config_info_aggr` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
`content` longtext NOT NULL COMMENT '内容',
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';
/******************************************/
/* 表名称 = config_info_beta */
/******************************************/
CREATE TABLE `config_info_beta` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';
/******************************************/
/* 表名称 = config_info_tag */
/******************************************/
CREATE TABLE `config_info_tag` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';
/******************************************/
/* 表名称 = config_tags_relation */
/******************************************/
CREATE TABLE `config_tags_relation` (
`id` bigint(20) NOT NULL COMMENT 'id',
`tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
`tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`nid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增长标识',
PRIMARY KEY (`nid`),
UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';
/******************************************/
/* 表名称 = group_capacity */
/******************************************/
CREATE TABLE `group_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID空字符表示整个集群',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额0表示使用默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限单位为字节0表示使用默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数0表示使用默认值',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限单位为字节0表示使用默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';
/******************************************/
/* 表名称 = his_config_info */
/******************************************/
CREATE TABLE `his_config_info` (
`id` bigint(20) unsigned NOT NULL COMMENT 'id',
`nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增标识',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`op_type` char(10) DEFAULT NULL COMMENT 'operation type',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',
PRIMARY KEY (`nid`),
KEY `idx_gmt_create` (`gmt_create`),
KEY `idx_gmt_modified` (`gmt_modified`),
KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';
/******************************************/
/* 表名称 = tenant_capacity */
/******************************************/
CREATE TABLE `tenant_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额0表示使用默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限单位为字节0表示使用默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限单位为字节0表示使用默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';
CREATE TABLE `tenant_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`kp` varchar(128) NOT NULL COMMENT 'kp',
`tenant_id` varchar(128) default '' COMMENT 'tenant_id',
`tenant_name` varchar(128) default '' COMMENT 'tenant_name',
`tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
`create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
`gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
`gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
CREATE TABLE `users` (
`username` varchar(50) NOT NULL PRIMARY KEY COMMENT 'username',
`password` varchar(500) NOT NULL COMMENT 'password',
`enabled` boolean NOT NULL COMMENT 'enabled'
);
CREATE TABLE `roles` (
`username` varchar(50) NOT NULL COMMENT 'username',
`role` varchar(50) NOT NULL COMMENT 'role',
UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);
CREATE TABLE `permissions` (
`role` varchar(50) NOT NULL COMMENT 'role',
`resource` varchar(128) NOT NULL COMMENT 'resource',
`action` varchar(8) NOT NULL COMMENT 'action',
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);

View File

@ -0,0 +1,797 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 1999-2018 Alibaba Group Holding Ltd.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<configuration scan="true" scanPeriod="10 seconds">
<springProperty scope="context" name="logPath" source="nacos.logs.path" defaultValue="${nacos.home}/logs"/>
<property name="LOG_HOME" value="${logPath}"/>
<appender name="cmdb-main"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${nacos.home}/logs/cmdb-main.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${nacos.home}/logs/cmdb-main.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="naming-server"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-server.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-server.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="async-naming-server" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="naming-server"/>
</appender>
<appender name="naming-raft"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-raft.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-raft.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="async-naming-raft" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="naming-raft"/>
</appender>
<appender name="naming-distro"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-distro.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-distro.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="async-naming-distro" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="naming-distro"/>
</appender>
<appender name="naming-event"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-event.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-event.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="async-naming-event" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="naming-event"/>
</appender>
<appender name="naming-push"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-push.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-push.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="naming-rt"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-rt.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-rt.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="naming-performance"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-performance.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-performance.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--config module logback config-->
<appender name="dumpFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-dump.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-dump.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="pullFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-pull.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-pull.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>20MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>128MB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="fatalFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-fatal.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-fatal.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>20MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>128MB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="memoryFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-memory.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-memory.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>20MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>128MB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="pullCheckFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-pull-check.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-pull-check.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="clientLog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-client-request.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-client-request.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date|%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="traceLog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-trace.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-trace.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date|%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="notifyLog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-notify.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-notify.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="startLog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-server.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-server.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>512MB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="rootFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/nacos.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/nacos.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>512MB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="nacos-address"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/nacos-address.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/nacos-address.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="istio-main"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/istio-main.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/istio-main.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="core-auth"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/core-auth.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/core-auth.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="protocol-raft"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/protocol-raft.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/protocol-raft.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="protocol-distro"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/protocol-distro.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/protocol-distro.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="nacos-cluster"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/nacos-cluster.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/nacos-cluster.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="alipay-jraft"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/alipay-jraft.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/alipay-jraft.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--TPS control -->
<appender name="plugin-control-connection"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/plugin-control-connection.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/plugin-control-connection.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>2GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="plugin-control-tps"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/plugin-control-tps.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/plugin-control-tps.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>2GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="plugin-control"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/plugin-control.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/plugin-control.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>14</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="remote"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/remote.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/remote.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="remote-digest"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/remote-digest.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/remote-digest.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="remote-push"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/remote-push.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/remote-push.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="nacos-persistence"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/nacos-persistence.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/nacos-persistence.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<logger name="com.alibaba.nacos.address.main" additivity="false">
<level value="INFO"/>
<appender-ref ref="nacos-address"/>
</logger>
<logger name="com.alibaba.nacos.cmdb.main" additivity="false">
<level value="INFO"/>
<appender-ref ref="cmdb-main"/>
</logger>
<logger name="com.alibaba.nacos.core.remote" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="remote"/>
</logger>
<logger name="com.alibaba.nacos.core.remote.push" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="remote-push"/>
</logger>
<logger name="com.alibaba.nacos.core.remote.digest" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="remote-digest"/>
</logger>
<!-- TPS Control-->
<logger name="com.alibaba.nacos.plugin.control" additivity="false">
<level value="INFO"/>
<appender-ref ref="plugin-control"/>
</logger>
<logger name="com.alibaba.nacos.plugin.control.tps" additivity="false">
<level value="INFO"/>
<appender-ref ref="plugin-control-tps"/>
</logger>
<logger name="com.alibaba.nacos.plugin.control.connection" additivity="false">
<level value="INFO"/>
<appender-ref ref="plugin-control-connection"/>
</logger>
<logger name="com.alibaba.nacos.naming.main" additivity="false">
<level value="INFO"/>
<appender-ref ref="async-naming-server"/>
</logger>
<logger name="com.alibaba.nacos.naming.raft" additivity="false">
<level value="INFO"/>
<appender-ref ref="async-naming-raft"/>
</logger>
<logger name="com.alibaba.nacos.naming.distro" additivity="false">
<level value="INFO"/>
<appender-ref ref="async-naming-distro"/>
</logger>
<logger name="com.alibaba.nacos.naming.event" additivity="false">
<level value="INFO"/>
<appender-ref ref="async-naming-event"/>
</logger>
<logger name="com.alibaba.nacos.naming.push" additivity="false">
<level value="INFO"/>
<appender-ref ref="naming-push"/>
</logger>
<logger name="com.alibaba.nacos.naming.rt" additivity="false">
<level value="INFO"/>
<appender-ref ref="naming-rt"/>
</logger>
<logger name="com.alibaba.nacos.naming.performance" additivity="false">
<level value="INFO"/>
<appender-ref ref="naming-performance"/>
</logger>
<logger name="com.alibaba.nacos.config.dumpLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="dumpFile"/>
</logger>
<logger name="com.alibaba.nacos.config.pullLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="pullFile"/>
</logger>
<logger name="com.alibaba.nacos.config.pullCheckLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="pullCheckFile"/>
</logger>
<logger name="com.alibaba.nacos.config.fatal" additivity="false">
<level value="INFO"/>
<appender-ref ref="fatalFile"/>
</logger>
<logger name="com.alibaba.nacos.config.monitorLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="memoryFile"/>
</logger>
<logger name="com.alibaba.nacos.config.clientLog" additivity="false">
<level value="info"/>
<appender-ref ref="clientLog"/>
</logger>
<logger name="com.alibaba.nacos.config.notifyLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="notifyLog"/>
</logger>
<logger name="com.alibaba.nacos.config.traceLog" additivity="false">
<level value="info"/>
<appender-ref ref="traceLog"/>
</logger>
<logger name="com.alibaba.nacos.config.startLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="startLog"/>
</logger>
<logger name="com.alibaba.nacos.istio.main" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="istio-main"/>
</logger>
<logger name="com.alibaba.nacos.core.auth" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="core-auth"/>
</logger>
<logger name="com.alibaba.nacos.core.protocol.raft" additivity="false">
<level value="INFO"/>
<appender-ref ref="protocol-raft"/>
</logger>
<logger name="com.alipay.sofa.jraft" additivity="false">
<level value="INFO"/>
<appender-ref ref="alipay-jraft"/>
</logger>
<logger name="com.alibaba.nacos.core.protocol.distro" additivity="false">
<level value="INFO"/>
<appender-ref ref="protocol-distro"/>
</logger>
<logger name="com.alibaba.nacos.core.cluster" additivity="false">
<level value="INFO"/>
<appender-ref ref="nacos-cluster"/>
</logger>
<logger name="com.alibaba.nacos.persistence" additivity="false">
<level value="INFO"/>
<appender-ref ref="nacos-persistence"/>
</logger>
<springProfile name="standalone">
<logger name="org.springframework">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<logger name="org.apache.catalina.startup.DigesterFactory">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<logger name="org.apache.catalina.util.LifecycleBase">
<appender-ref ref="CONSOLE"/>
<level value="ERROR"/>
</logger>
<logger name="org.apache.coyote.http11.Http11NioProtocol">
<appender-ref ref="CONSOLE"/>
<level value="WARN"/>
</logger>
<logger name="org.apache.tomcat.util.net.NioSelectorPool">
<appender-ref ref="CONSOLE"/>
<level value="WARN"/>
</logger>
</springProfile>
<logger name="com.alibaba.nacos.core.listener.StartingApplicationListener">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<logger name="com.alibaba.nacos.common.notify.NotifyCenter">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<logger name="com.alibaba.nacos.sys.file.WatchFileCenter">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<logger name="com.alibaba.nacos.common.executor.ThreadPoolManager">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<root>
<level value="INFO"/>
<appender-ref ref="rootFile"/>
</root>
</configuration>

View File

@ -22,6 +22,7 @@
<module>yudao-module-mall</module>
<module>yudao-module-erp</module>
<module>yudao-module-crm</module>
<module>yudao-module-langchat</module>
<!-- 友情提示:基于 Spring AI 实现 LLM 大模型的接入,需要使用 JDK17 版本,详细可见 https://doc.iocoder.cn/ai/build/ -->
<!-- <module>yudao-module-ai</module>-->
</modules>
@ -33,7 +34,7 @@
<properties>
<revision>2.3.0-jdk8-SNAPSHOT</revision>
<!-- Maven 相关 -->
<java.version>1.8</java.version>
<java.version>17</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>

View File

@ -3,7 +3,7 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.0.17:8848 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项
@ -61,30 +61,30 @@ spring:
primary: master
datasource:
master:
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
url: jdbc:mysql://192.168.0.17:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
# url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例
# url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro # SQLServer 连接的示例
# url: jdbc:dm://10.211.55.4:5236?schema=RUOYI_VUE_PRO # DM 连接的示例
username: root
password: chinasoft@123
password: root
# username: sa # SQL Server 连接的示例
# password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W # SQL Server 连接的示例
# username: SYSDBA # DM 连接的示例
# password: SYSDBA # DM 连接的示例
slave: # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
url: jdbc:mysql://192.168.0.17:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
username: root
password: chinasoft@123
password: root
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 10.31.0.128 # 地址
host: 192.168.0.17 # 地址
port: 6379 # 端口
database: 0 # 数据库索引
# password: 123456 # 密码,建议生产环境开启
password: 123456 # 密码,建议生产环境开启
--- #################### MQ 消息队列相关配置 ####################

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-langchat</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<description>芋道项目基础脚手架</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro/yudao-module-langchat</url>
<dependencies>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-env</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-redis</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-rpc</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2021.0.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-job</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mq</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.7.18</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-justauth</artifactId>
<version>1.0.8</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
<version>4.6.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
<version>4.6.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId>
<version>1.0.8</version>
<scope>compile</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>huaweicloud</id>
<name>huawei</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</repository>
<repository>
<id>aliyunmaven</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
</project>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<modules>
<module>yudao-module-langchat-api</module>
<module>yudao-module-langchat-biz</module>
</modules>
<artifactId>yudao-module-langchat</artifactId>
<packaging>pom</packaging>
<name>${project.artifactId}</name>
<description>
</description>
</project>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-langchat</artifactId>
<version>${revision}</version>
</parent>
<artifactId>yudao-module-langchat-api</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
langchat 模块 API暴露给其它模块调用
</description>
<dependencies>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.enums;
/**
* @author tycoding
* @since 2024/1/15
*/
public interface CacheConst {
/**
* 系统所有Redis缓存Key前缀 prefix
*/
String REDIS_KEY_PREFIX = "langchat:";
/**
* Auth缓存前缀
*/
String AUTH_PREFIX = REDIS_KEY_PREFIX + "auth:";
/**
* Auth Session缓存前缀
*/
String AUTH_SESSION_PREFIX = AUTH_PREFIX + "session:";
/**
* Auth Session缓存变量前缀
*/
String AUTH_USER_INFO_KEY = "USER_INFO";
/**
* Auth Token缓存变量前缀
*/
String AUTH_TOKEN_INFO_KEY = "TOKEN_INFO";
/**
* 用户信息缓存
*/
String USER_DETAIL_KEY = REDIS_KEY_PREFIX + "user_details";
/**
* 验证码缓存前缀
*/
String CAPTCHA_PREFIX = REDIS_KEY_PREFIX + "auth:captcha:";
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.langchat.enums;
import lombok.AllArgsConstructor;
/**
* @author GB
* @desc
* @since 2024-08-21
*/
@AllArgsConstructor
public enum ChatErrorEnum {
API_KEY_IS_NULL(1000, "模型 %s %s api key 为空,请检查配置"),
BASE_URL_IS_NULL(1003, "模型 %s %s base url 为空,请检查配置"),
SECRET_KEY_IS_NULL(1005, "模型 %s %s base secret Key 为空,请检查配置"),
;
/**
* 错误码
*/
private int errorCode;
/**
* 错误描述用于展示给用户
*/
private String errorDesc;
public int getErrorCode() {
return this.errorCode;
}
public String getErrorDesc(String modelName, String type) {
return this.errorDesc.formatted(modelName, type);
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.enums;
/**
* @author tycoding
* @since 2024/6/6
*/
public interface EmbedConst {
String ORIGIN_TYPE_INPUT = "INPUT";
String ORIGIN_TYPE_UPLOAD = "UPLOAD";
String KNOWLEDGE = "knowledgeId";
String FILENAME = "docsName";
String CLAZZ_NAME_OPENAI = "OpenAiEmbeddingModel";
String CLAZZ_NAME_QIANFAN = "QianfanEmbeddingModel";
String CLAZZ_NAME_QIANWEN = "QwenEmbeddingModel";
String CLAZZ_NAME_ZHIPU = "ZhipuAiEmbeddingModel";
String CLAZZ_NAME_OLLAMA = "OllamaEmbeddingModel";
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.enums;
import lombok.Getter;
/**
* @author tycoding
* @since 2024/10/28
*/
@Getter
public enum EmbedStoreEnum {
REDIS,
PGVECTOR,
MILVUS,
;
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.enums;
/**
* @author tycoding
* @since 2024/1/6
*/
public interface ModelConst {
String TEXT_SUFFIX = "_text";
String IMAGE_SUFFIX = "_image";
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.enums;
import lombok.Getter;
/**
* @author tycoding
* @since 2024/6/16
*/
@Getter
public enum ProviderEnum {
OPENAI,
AZURE_OPENAI,
GEMINI,
OLLAMA,
CLAUDE,
Q_FAN,
Q_WEN,
ZHIPU,
YI,
DOUYIN,
DEEPSEEK,
SILICON,
SPARK,
;
}

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-langchat-biz</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<description>芋道项目基础脚手架</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro/yudao-module-langchat-biz</url>
<dependencies>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-env</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-redis</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-rpc</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2021.0.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-job</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mq</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.7.18</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-justauth</artifactId>
<version>1.0.8</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
<version>4.6.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
<version>4.6.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId>
<version>1.0.8</version>
<scope>compile</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>huaweicloud</id>
<name>huawei</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</repository>
<repository>
<id>aliyunmaven</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
</project>

View File

@ -0,0 +1,258 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-langchat</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-module-langchat-biz</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<properties>
<langchain4j.version>1.0.0-beta1</langchain4j.version>
</properties>
<description>
</description>
<dependencies>
<!--langchat4j-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-core</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-redis</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-pgvector</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-milvus</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-document-parser-apache-tika</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-qianfan</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-dashscope</artifactId>
<version>${langchain4j.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-zhipu-ai</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<!-- OSS -->
<dependency>
<groupId>org.dromara.x-file-storage</groupId>
<artifactId>x-file-storage-core</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.12.1</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.16.1</version>
</dependency>
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.6.137</version>
</dependency>
<!-- Spring Cloud 基础 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-env</artifactId>
</dependency>
<!-- 依赖服务 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-langchat-api</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
</dependency>
<!-- 业务组件 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId>
</dependency>
<!-- DB 相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-redis</artifactId>
</dependency>
<!-- RPC 远程调用相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-rpc</artifactId>
</dependency>
<!-- Registry 注册中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Config 配置中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- Job 定时任务相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-job</artifactId>
</dependency>
<!-- 消息队列相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mq</artifactId>
</dependency>
<!-- 服务保障相关 TODO 芋艿:暂时去掉 -->
<!-- <dependency>-->
<!-- <groupId>cn.iocoder.cloud</groupId>-->
<!-- <artifactId>yudao-spring-boot-starter-protection</artifactId>-->
<!-- </dependency>-->
<!-- Test 测试相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- 监控相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
</dependency>
<!-- 三方云服务相关 -->
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-justauth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) -->
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId> <!-- 微信登录(公众号) -->
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId> <!-- 微信登录(小程序) -->
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId> <!-- 验证码,一般用于登录使用 -->
</dependency>
</dependencies>
<build>
<!-- 设置构建的 jar 包名 -->
<finalName>${project.artifactId}</finalName>
<plugins>
<!-- 打包 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat;
import cn.iocoder.yudao.module.langchat.config.EnableFileStorage;
import cn.iocoder.yudao.module.langchat.config.SpringFileStorageProperties;
import cn.iocoder.yudao.module.langchat.properties.ChatProps;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
/**
* @author tycoding
* @since 2024/2/4
*/
@EnableFileStorage
@SpringBootApplication
@EnableConfigurationProperties({
SpringFileStorageProperties.class,
ChatProps.class
})
public class LangChatApplication {
public static void main(String[] args) {
SpringApplication.run(LangChatApplication.class, args);
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义日志记录切面注解
*
* @author tycoding
* @since 2024/4/15
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiLog {
String value() default "";
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.component;
import org.springframework.context.ApplicationEvent;
/**
* @author tycoding
* @since 2024/6/16
*/
public class EmbeddingRefreshEvent extends ApplicationEvent {
private static final long serialVersionUID = 4109980679877560773L;
public EmbeddingRefreshEvent(Object source) {
super(source);
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.component;
import lombok.Getter;
/**
* @author tycoding
* @since 2024/6/16
*/
@Getter
public enum ModelTypeEnum {
CHAT,
EMBEDDING,
TEXT_IMAGE,
WEB_SEARCH;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.component;
import org.springframework.context.ApplicationEvent;
/**
* @author tycoding
* @since 2024/6/16
*/
public class ProviderRefreshEvent extends ApplicationEvent {
private static final long serialVersionUID = 4109980679877560773L;
public ProviderRefreshEvent(Object source) {
super(source);
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.component;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.stereotype.Service;
/**
* @author tycoding
* @since 2024/1/19
*/
@Service
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static void publishEvent(ApplicationEvent event) {
if (applicationContext == null) {
return;
}
applicationContext.publishEvent(event);
}
public <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
}
public void registerBean(String beanName, Object beanInstance) {
BeanDefinitionRegistry beanDefinitionRegistry =
(BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition((Class<Object>) beanInstance.getClass(), () -> beanInstance);
BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
}
public void unregisterBean(String beanName) {
BeanDefinitionRegistry beanDefinitionRegistry =
(BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
if (beanDefinitionRegistry.containsBeanDefinition(beanName)) {
beanDefinitionRegistry.removeBeanDefinition(beanName);
}
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.config;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* 启用文件存储会自动根据配置文件进行加载
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FileStorageAutoConfiguration.class, SpringFileStorageProperties.class})
public @interface EnableFileStorage {}

View File

@ -0,0 +1,203 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.config;
import cn.iocoder.yudao.module.langchat.wrapper.MultipartFileWrapperAdapter;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.core.FileStorageService;
import org.dromara.x.file.storage.core.FileStorageServiceBuilder;
import org.dromara.x.file.storage.core.aspect.FileStorageAspect;
import org.dromara.x.file.storage.core.file.FileWrapperAdapter;
import org.dromara.x.file.storage.core.platform.FileStorage;
import org.dromara.x.file.storage.core.platform.FileStorageClientFactory;
import org.dromara.x.file.storage.core.recorder.DefaultFileRecorder;
import org.dromara.x.file.storage.core.recorder.FileRecorder;
import org.dromara.x.file.storage.core.tika.ContentTypeDetect;
import org.dromara.x.file.storage.core.tika.DefaultTikaFactory;
import org.dromara.x.file.storage.core.tika.TikaContentTypeDetect;
import org.dromara.x.file.storage.core.tika.TikaFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Configuration
@ConditionalOnMissingBean(FileStorageService.class)
public class FileStorageAutoConfiguration {
@Autowired
private SpringFileStorageProperties properties;
@Autowired
private ApplicationContext applicationContext;
/**
* 当没有找到 FileRecorder 时使用默认的 FileRecorder
*/
@Bean
@ConditionalOnMissingBean(FileRecorder.class)
public FileRecorder fileRecorder() {
log.warn("没有找到 FileRecorder 的实现类,文件上传之外的部分功能无法正常使用,必须实现该接口才能使用完整功能!");
return new DefaultFileRecorder();
}
/**
* Tika 工厂类型用于识别上传的文件的 MINE
*/
@Bean
@ConditionalOnMissingBean(TikaFactory.class)
public TikaFactory tikaFactory() {
return new DefaultTikaFactory();
}
/**
* 识别文件的 MIME 类型
*/
@Bean
@ConditionalOnMissingBean(ContentTypeDetect.class)
public ContentTypeDetect contentTypeDetect(TikaFactory tikaFactory) {
return new TikaContentTypeDetect(tikaFactory);
}
/**
* 文件存储服务
*/
@Bean(destroyMethod = "destroy")
public FileStorageService fileStorageService(
FileRecorder fileRecorder,
@Autowired(required = false) List<List<? extends FileStorage>> fileStorageLists,
@Autowired(required = false) List<FileStorageAspect> aspectList,
@Autowired(required = false) List<FileWrapperAdapter> fileWrapperAdapterList,
ContentTypeDetect contentTypeDetect,
@Autowired(required = false) List<List<FileStorageClientFactory<?>>> clientFactoryList) {
if (fileStorageLists == null) fileStorageLists = new ArrayList<>();
if (aspectList == null) aspectList = new ArrayList<>();
if (fileWrapperAdapterList == null) fileWrapperAdapterList = new ArrayList<>();
if (clientFactoryList == null) clientFactoryList = new ArrayList<>();
FileStorageServiceBuilder builder = FileStorageServiceBuilder.create(properties.toFileStorageProperties())
.setFileRecorder(fileRecorder)
.setAspectList(aspectList)
.setContentTypeDetect(contentTypeDetect)
.setFileWrapperAdapterList(fileWrapperAdapterList)
.setClientFactoryList(clientFactoryList);
fileStorageLists.forEach(builder::addFileStorage);
if (properties.getEnableByteFileWrapper()) {
builder.addByteFileWrapperAdapter();
}
if (properties.getEnableUriFileWrapper()) {
builder.addUriFileWrapperAdapter();
}
if (properties.getEnableInputStreamFileWrapper()) {
builder.addInputStreamFileWrapperAdapter();
}
if (properties.getEnableLocalFileWrapper()) {
builder.addLocalFileWrapperAdapter();
}
if (properties.getEnableHttpServletRequestFileWrapper()) {
if (FileStorageServiceBuilder.doesNotExistClass("javax.servlet.http.HttpServletRequest")
&& FileStorageServiceBuilder.doesNotExistClass("jakarta.servlet.http.HttpServletRequest")) {
log.warn(
"当前未检测到 Servlet 环境,无法加载 HttpServletRequest 的文件包装适配器请将参数【dromara.x-file-storage.enable-http-servlet-request-file-wrapper】设置为 【false】来消除此警告");
} else {
builder.addHttpServletRequestFileWrapperAdapter();
}
}
if (properties.getEnableMultipartFileWrapper()) {
if (FileStorageServiceBuilder.doesNotExistClass("org.springframework.web.multipart.MultipartFile")) {
log.warn(
"当前未检测到 SpringWeb 环境,无法加载 MultipartFile 的文件包装适配器请将参数【dromara.x-file-storage.enable-multipart-file-wrapper】设置为 【false】来消除此警告");
} else {
builder.addFileWrapperAdapter(new MultipartFileWrapperAdapter());
}
}
if (FileStorageServiceBuilder.doesNotExistClass("org.springframework.web.servlet.config.annotation.WebMvcConfigurer")) {
long localAccessNum = properties.getLocal().stream()
.filter(SpringFileStorageProperties.SpringLocalConfig::getEnableStorage)
.filter(SpringFileStorageProperties.SpringLocalConfig::getEnableAccess)
.count();
long localPlusAccessNum = properties.getLocalPlus().stream()
.filter(SpringFileStorageProperties.SpringLocalPlusConfig::getEnableStorage)
.filter(SpringFileStorageProperties.SpringLocalPlusConfig::getEnableAccess)
.count();
if (localAccessNum + localPlusAccessNum > 0) {
log.warn("当前未检测到 SpringWeb 环境,无法开启本地存储平台的本地访问功能,请将关闭本地访问来消除此警告");
}
}
return builder.build();
}
/**
* FileStorageService 注入自己的代理对象不然会导致针对 FileStorageService 的代理方法不生效
*/
@EventListener(ContextRefreshedEvent.class)
public void onContextRefreshedEvent() {
FileStorageService service = applicationContext.getBean(FileStorageService.class);
service.setSelf(service);
}
/**
* 本地存储文件访问自动配置类
*/
@Configuration
@ConditionalOnClass(name = "org.springframework.web.servlet.config.annotation.WebMvcConfigurer")
public static class FileStorageLocalFileAccessAutoConfiguration {
@Autowired
private SpringFileStorageProperties properties;
/**
* 配置本地存储的访问地址
*/
@Bean
public WebMvcConfigurer fileStorageWebMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addResourceHandlers(@NonNull ResourceHandlerRegistry registry) {
for (SpringFileStorageProperties.SpringLocalConfig local : properties.getLocal()) {
if (local.getEnableStorage() && local.getEnableAccess()) {
registry.addResourceHandler(local.getPathPatterns())
.addResourceLocations("file:" + local.getBasePath());
}
}
for (SpringFileStorageProperties.SpringLocalPlusConfig local : properties.getLocalPlus()) {
if (local.getEnableStorage() && local.getEnableAccess()) {
registry.addResourceHandler(local.getPathPatterns())
.addResourceLocations("file:" + local.getStoragePath());
}
}
}
};
}
}
}

View File

@ -0,0 +1,449 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.config;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.x.file.storage.core.FileStorageProperties;
import org.dromara.x.file.storage.core.FileStorageProperties.*;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Data
@Accessors(chain = true)
@Component
@ConditionalOnMissingBean(SpringFileStorageProperties.class)
@ConfigurationProperties(prefix = "langchat.oss")
public class SpringFileStorageProperties {
/**
* 默认存储平台
*/
private String defaultPlatform = "local";
/**
* 缩略图后缀例如.min.jpg.png
*/
private String thumbnailSuffix = ".min.jpg";
/**
* 上传时不支持元数据时抛出异常
*/
private Boolean uploadNotSupportMetadataThrowException = true;
/**
* 上传时不支持 ACL 时抛出异常
*/
private Boolean uploadNotSupportAclThrowException = true;
/**
* 复制时不支持元数据时抛出异常
*/
private Boolean copyNotSupportMetadataThrowException = true;
/**
* 复制时不支持 ACL 时抛出异常
*/
private Boolean copyNotSupportAclThrowException = true;
/**
* 移动时不支持元数据时抛出异常
*/
private Boolean moveNotSupportMetadataThrowException = true;
/**
* 移动时不支持 ACL 时抛出异常
*/
private Boolean moveNotSupportAclThrowException = true;
/**
* 启用 byte[] 文件包装适配器
*/
private Boolean enableByteFileWrapper = true;
/**
* 启用 URI 文件包装适配器包含 URL String
*/
private Boolean enableUriFileWrapper = true;
/**
* 启用 InputStream 文件包装适配器
*/
private Boolean enableInputStreamFileWrapper = true;
/**
* 启用本地文件包装适配器
*/
private Boolean enableLocalFileWrapper = true;
/**
* 启用 HttpServletRequest 文件包装适配器
*/
private Boolean enableHttpServletRequestFileWrapper = true;
/**
* 启用 MultipartFile 文件包装适配器
*/
private Boolean enableMultipartFileWrapper = true;
/**
* 本地存储
*/
@Deprecated
private List<? extends SpringLocalConfig> local = new ArrayList<>();
/**
* 本地存储
*/
private List<? extends SpringLocalPlusConfig> localPlus = new ArrayList<>();
/**
* 华为云 OBS
*/
private List<? extends SpringHuaweiObsConfig> huaweiObs = new ArrayList<>();
/**
* 阿里云 OSS
*/
private List<? extends SpringAliyunOssConfig> aliyunOss = new ArrayList<>();
/**
* 七牛云 Kodo
*/
private List<? extends SpringQiniuKodoConfig> qiniuKodo = new ArrayList<>();
/**
* 腾讯云 COS
*/
private List<? extends SpringTencentCosConfig> tencentCos = new ArrayList<>();
/**
* 百度云 BOS
*/
private List<? extends SpringBaiduBosConfig> baiduBos = new ArrayList<>();
/**
* 又拍云 USS
*/
private List<? extends SpringUpyunUssConfig> upyunUss = new ArrayList<>();
/**
* MinIO USS
*/
private List<? extends SpringMinioConfig> minio = new ArrayList<>();
/**
* Amazon S3
*/
private List<? extends SpringAmazonS3Config> amazonS3 = new ArrayList<>();
/**
* FTP
*/
private List<? extends SpringFtpConfig> ftp = new ArrayList<>();
/**
* FTP
*/
private List<? extends SpringSftpConfig> sftp = new ArrayList<>();
/**
* WebDAV
*/
private List<? extends SpringWebDavConfig> webdav = new ArrayList<>();
/**
* GoogleCloud Storage
*/
private List<? extends SpringGoogleCloudStorageConfig> googleCloudStorage = new ArrayList<>();
/**
* FastDFS
*/
private List<? extends SpringFastDfsConfig> fastdfs = new ArrayList<>();
/**
* Azure Blob Storage
*/
private List<? extends SpringAzureBlobStorageConfig> azureBlob = new ArrayList<>();
/**
* 转换成 FileStorageProperties 并过滤掉没有启用的存储平台
*/
public FileStorageProperties toFileStorageProperties() {
FileStorageProperties properties = new FileStorageProperties();
properties.setDefaultPlatform(defaultPlatform);
properties.setThumbnailSuffix(thumbnailSuffix);
properties.setUploadNotSupportMetadataThrowException(uploadNotSupportMetadataThrowException);
properties.setUploadNotSupportAclThrowException(uploadNotSupportAclThrowException);
properties.setCopyNotSupportMetadataThrowException(copyNotSupportMetadataThrowException);
properties.setCopyNotSupportAclThrowException(copyNotSupportAclThrowException);
properties.setMoveNotSupportMetadataThrowException(moveNotSupportMetadataThrowException);
properties.setMoveNotSupportAclThrowException(moveNotSupportAclThrowException);
properties.setLocal(
local.stream().filter(SpringLocalConfig::getEnableStorage).collect(Collectors.toList()));
properties.setLocalPlus(localPlus.stream()
.filter(SpringLocalPlusConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setHuaweiObs(huaweiObs.stream()
.filter(SpringHuaweiObsConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setAliyunOss(aliyunOss.stream()
.filter(SpringAliyunOssConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setQiniuKodo(qiniuKodo.stream()
.filter(SpringQiniuKodoConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setTencentCos(tencentCos.stream()
.filter(SpringTencentCosConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setBaiduBos(
baiduBos.stream().filter(SpringBaiduBosConfig::getEnableStorage).collect(Collectors.toList()));
properties.setUpyunUss(
upyunUss.stream().filter(SpringUpyunUssConfig::getEnableStorage).collect(Collectors.toList()));
properties.setMinio(
minio.stream().filter(SpringMinioConfig::getEnableStorage).collect(Collectors.toList()));
properties.setAmazonS3(
amazonS3.stream().filter(SpringAmazonS3Config::getEnableStorage).collect(Collectors.toList()));
properties.setFtp(ftp.stream().filter(SpringFtpConfig::getEnableStorage).collect(Collectors.toList()));
properties.setSftp(
sftp.stream().filter(SpringSftpConfig::getEnableStorage).collect(Collectors.toList()));
properties.setWebdav(
webdav.stream().filter(SpringWebDavConfig::getEnableStorage).collect(Collectors.toList()));
properties.setGoogleCloudStorage(googleCloudStorage.stream()
.filter(SpringGoogleCloudStorageConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setFastdfs(
fastdfs.stream().filter(SpringFastDfsConfig::getEnableStorage).collect(Collectors.toList()));
properties.setAzureBlob(azureBlob.stream()
.filter(SpringAzureBlobStorageConfig::getEnableStorage)
.collect(Collectors.toList()));
return properties;
}
/**
* 本地存储
*/
@Deprecated
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringLocalConfig extends LocalConfig {
/**
* 本地存储访问路径
*/
private String[] pathPatterns = new String[0];
/**
* 启用本地存储
*/
private Boolean enableStorage = false;
/**
* 启用本地访问
*/
private Boolean enableAccess = false;
}
/**
* 本地存储升级版
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringLocalPlusConfig extends LocalPlusConfig {
/**
* 本地存储访问路径
*/
private String[] pathPatterns = new String[0];
/**
* 启用本地存储
*/
private Boolean enableStorage = false;
/**
* 启用本地访问
*/
private Boolean enableAccess = false;
}
/**
* 华为云 OBS
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringHuaweiObsConfig extends HuaweiObsConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* 阿里云 OSS
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringAliyunOssConfig extends AliyunOssConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* 七牛云 Kodo
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringQiniuKodoConfig extends QiniuKodoConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* 腾讯云 COS
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringTencentCosConfig extends TencentCosConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* 百度云 BOS
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringBaiduBosConfig extends BaiduBosConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* 又拍云 USS
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringUpyunUssConfig extends UpyunUssConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* MinIO
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringMinioConfig extends MinioConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* Amazon S3
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringAmazonS3Config extends AmazonS3Config {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* FTP
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringFtpConfig extends FtpConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* SFTP
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringSftpConfig extends SftpConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* WebDAV
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringWebDavConfig extends WebDavConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* GoogleCloud Storage
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringGoogleCloudStorageConfig extends GoogleCloudStorageConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* FastDFS Storage
* @author XS <wanghaiqi@beeplay123.com>
* @date 2023/10/23
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringFastDfsConfig extends FastDfsConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* AzureBlob Storage
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringAzureBlobStorageConfig extends AzureBlobStorageConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.constant;
/**
* @author tycoding
* @since 2024/1/15
*/
public interface CommonConst {
/**
* UTF-8 编码
*/
String UTF_8 = "utf-8";
/**
* 菜单类型menu
*/
String MENU_TYPE_MENU = "menu";
/**
* 菜单类型button
*/
String MENU_TYPE_BUTTON = "button";
/**
* 菜单默认Icon图标
*/
String MENU_ICON = "alert";
String LAYOUT = "Layout";
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.hutool.core.lang.Dict;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.entity.AigcApp;
import cn.iocoder.yudao.module.langchat.entity.AigcAppApi;
import cn.iocoder.yudao.module.langchat.entity.AigcKnowledge;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcAppApiService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcAppService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcKnowledgeService;
import cn.iocoder.yudao.module.langchat.store.AppStore;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@RestController
@RequiredArgsConstructor
@RequestMapping("/aigc/app")
public class AigcAppController {
private final AigcAppService aigcAppService;
private final AigcAppApiService aigcAppApiService;
private final AppStore appStore;
private final AigcKnowledgeService knowledgeService;
@GetMapping("/channel/api/{appId}")
@TenantIgnore
public CommonResult<AigcAppApi> getApiChanel(@PathVariable String appId) {
List<AigcAppApi> list = aigcAppApiService.list(Wrappers.<AigcAppApi>lambdaQuery().eq(AigcAppApi::getAppId, appId));
return CommonResult.success(list.isEmpty() ? null : list.get(0));
}
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcApp>> list(AigcApp data) {
return CommonResult.success(aigcAppService.list(data));
}
@GetMapping("/page")
@TenantIgnore
public CommonResult<Dict> page(AigcApp data, QueryPage queryPage) {
return CommonResult.success(MybatisUtil.getData(aigcAppService.page(MybatisUtil.wrap(data, queryPage),
Wrappers.<AigcApp>lambdaQuery()
.like(StringUtils.isNotEmpty(data.getName()), AigcApp::getName, data.getName())
)));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcApp> findById(@PathVariable String id) {
AigcApp app = aigcAppService.getById(id);
return CommonResult.success(app);
}
@PostMapping
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:app:add')")
public CommonResult add(@RequestBody AigcApp data) {
data.setCreateTime(new Date());
data.setSaveTime(new Date());
aigcAppService.save(data);
appStore.init();
return CommonResult.success(null);
}
@PutMapping
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:app:update')")
public CommonResult update(@RequestBody AigcApp data) {
// 校验知识库是否是同纬度
List<String> knowledgeIds = data.getKnowledgeIds();
if (knowledgeIds != null && !knowledgeIds.isEmpty()) {
List<AigcKnowledge> list = knowledgeService.list(Wrappers.<AigcKnowledge>lambdaQuery().in(AigcKnowledge::getId, knowledgeIds));
Set<String> modelIds = new HashSet<>();
Set<String> storeIds = new HashSet<>();
list.forEach(know -> {
modelIds.add(know.getEmbedModelId());
storeIds.add(know.getEmbedStoreId());
});
if (modelIds.size() > 1) {
return CommonResult.error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "请选择相同向量库数据源配置的知识库");
}
if (storeIds.size() > 1) {
return CommonResult.error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "请选择相同向量模型配置的知识库");
// throw new ServiceException("请选择相同向量模型配置的知识库");
}
}
data.setSaveTime(new Date());
aigcAppService.updateById(data);
appStore.init();
return CommonResult.success(null);
}
@DeleteMapping("/{id}")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:app:delete')")
public CommonResult delete(@PathVariable String id) {
aigcAppService.removeById(id);
appStore.init();
return CommonResult.success(null);
}
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.entity.AigcDocs;
import cn.iocoder.yudao.module.langchat.mapper.AigcDocsMapper;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import cn.iocoder.yudao.module.langchat.service.core.EmbeddingService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author tycoding
* @since 2024/4/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/chat/aigc/docs")
public class AigcDocsController {
private final AigcDocsMapper docsMapper;
private final EmbeddingService embeddingService;
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcDocs>> list(AigcDocs data) {
return CommonResult.success(docsMapper.selectList(Wrappers.<AigcDocs>lambdaQuery().orderByDesc(AigcDocs::getCreateTime)));
}
@GetMapping("/page")
@TenantIgnore
public CommonResult list(AigcDocs data, QueryPage queryPage) {
Page<AigcDocs> page = new Page<>(queryPage.getPageNo(), queryPage.getPageSize());
return CommonResult.success(MybatisUtil.getData(docsMapper.selectPage(page, Wrappers.<AigcDocs>lambdaQuery()
.eq(data.getKnowledgeId() != null, AigcDocs::getKnowledgeId, data.getKnowledgeId())
.eq(data.getSliceStatus() != null, AigcDocs::getSliceStatus, data.getSliceStatus())
.orderByDesc(AigcDocs::getCreateTime)
)));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcDocs> findById(@PathVariable String id) {
return CommonResult.success(docsMapper.selectById(id));
}
@PostMapping
@ApiLog("新增文档")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:add')")
public CommonResult add(@RequestBody AigcDocs data) {
docsMapper.insert(data);
return CommonResult.success("success");
}
@PutMapping
@ApiLog("修改文档")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:update')")
public CommonResult update(@RequestBody AigcDocs data) {
docsMapper.updateById(data);
return CommonResult.success("success");
}
@DeleteMapping("/{id}")
@ApiLog("删除文档")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:delete')")
@Transactional
public CommonResult delete(@PathVariable String id) {
// 删除切面数据
embeddingService.clearDocSlices(id);
// 删除文档
docsMapper.deleteById(id);
return CommonResult.success("success");
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.entity.AigcDocsSlice;
import cn.iocoder.yudao.module.langchat.mapper.AigcDocsSliceMapper;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* @author tycoding
* @since 2024/4/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/chat/aigc/docs/slice")
public class AigcDocsSliceController {
private final AigcDocsSliceMapper docsSliceMapper;
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcDocsSlice>> list(AigcDocsSlice data) {
return CommonResult.success(docsSliceMapper.selectList(Wrappers.<AigcDocsSlice>lambdaQuery().orderByDesc(AigcDocsSlice::getCreateTime)));
}
@GetMapping("/page")
@TenantIgnore
public CommonResult list(AigcDocsSlice data, QueryPage queryPage) {
Page<AigcDocsSlice> page = new Page<>(queryPage.getPageNo(), queryPage.getPageSize());
return CommonResult.success(MybatisUtil.getData(docsSliceMapper.selectPage(page, Wrappers.<AigcDocsSlice>lambdaQuery()
.eq(data.getKnowledgeId() != null, AigcDocsSlice::getKnowledgeId, data.getKnowledgeId())
.eq(data.getDocsId() != null, AigcDocsSlice::getDocsId, data.getDocsId())
.orderByDesc(AigcDocsSlice::getCreateTime)
)));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcDocsSlice> findById(@PathVariable String id) {
return CommonResult.success(docsSliceMapper.selectById(id));
}
@PostMapping
@ApiLog("新增切片数据")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:slice:add')")
public CommonResult add(@RequestBody AigcDocsSlice data) {
data.setCreateTime(new Date());
docsSliceMapper.insert(data);
return CommonResult.success("success");
}
@PutMapping
@ApiLog("修改切片数据")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:slice:update')")
public CommonResult update(@RequestBody AigcDocsSlice data) {
docsSliceMapper.updateById(data);
return CommonResult.success("success");
}
@DeleteMapping("/{id}")
@ApiLog("删除切片数据")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:slice:delete')")
public CommonResult delete(@PathVariable String id) {
docsSliceMapper.deleteById(id);
return CommonResult.success("success");
}
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.component.EmbeddingRefreshEvent;
import cn.iocoder.yudao.module.langchat.entity.AigcEmbedStore;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcEmbedStoreService;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.component.SpringContextHolder;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author tycoding
* @since 2024/4/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/chat/aigc/embed-store")
public class AigcEmbedStoreController {
private final AigcEmbedStoreService embedStoreService;
private final SpringContextHolder contextHolder;
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcEmbedStore>> list(AigcEmbedStore data) {
List<AigcEmbedStore> list = embedStoreService.list(Wrappers.lambdaQuery());
list.forEach(this::hide);
return CommonResult.success(list);
}
@GetMapping("/page")
@TenantIgnore
public CommonResult<Dict> page(AigcEmbedStore embedStore, QueryPage queryPage) {
IPage<AigcEmbedStore> page = embedStoreService.page(MybatisUtil.wrap(embedStore, queryPage),
Wrappers.lambdaQuery());
page.getRecords().forEach(this::hide);
return CommonResult.success(MybatisUtil.getData(page));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcEmbedStore> findById(@PathVariable String id) {
AigcEmbedStore store = embedStoreService.getById(id);
hide(store);
return CommonResult.success(store);
}
@PostMapping
@ApiLog("新增向量库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:embed-store:add')")
public CommonResult<AigcEmbedStore> add(@RequestBody AigcEmbedStore data) {
if (StrUtil.isNotBlank(data.getPassword()) && data.getPassword().contains("*")) {
data.setPassword(null);
}
embedStoreService.save(data);
SpringContextHolder.publishEvent(new EmbeddingRefreshEvent(data));
return CommonResult.success(data);
}
@PutMapping
@ApiLog("修改向量库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:embed-store:update')")
public CommonResult update(@RequestBody AigcEmbedStore data) {
if (StrUtil.isNotBlank(data.getPassword()) && data.getPassword().contains("*")) {
data.setPassword(null);
}
embedStoreService.updateById(data);
SpringContextHolder.publishEvent(new EmbeddingRefreshEvent(data));
return CommonResult.success("success");
}
@DeleteMapping("/{id}")
@ApiLog("删除向量库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:embed-store:delete')")
public CommonResult delete(@PathVariable String id) {
AigcEmbedStore store = embedStoreService.getById(id);
if (store != null) {
embedStoreService.removeById(id);
contextHolder.unregisterBean(id);
}
return CommonResult.success("success");
}
private void hide(AigcEmbedStore data) {
if (data == null || StrUtil.isBlank(data.getPassword())) {
return;
}
String key = StrUtil.hide(data.getPassword(), 0, data.getPassword().length());
data.setPassword(key);
}
}

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.entity.AigcDocs;
import cn.iocoder.yudao.module.langchat.entity.AigcEmbedStore;
import cn.iocoder.yudao.module.langchat.entity.AigcKnowledge;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.mapper.AigcDocsMapper;
import cn.iocoder.yudao.module.langchat.provider.KnowledgeStoreFactory;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcEmbedStoreService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcKnowledgeService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcModelService;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author tycoding
* @since 2024/4/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/chat/aigc/knowledge")
public class AigcKnowledgeController {
private final AigcKnowledgeService kbService;
private final AigcDocsMapper docsMapper;
private final AigcEmbedStoreService embedStoreService;
private final AigcModelService modelService;
private final KnowledgeStoreFactory knowledgeStore;
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcKnowledge>> list(AigcKnowledge data) {
List<AigcKnowledge> list = kbService.list(Wrappers.<AigcKnowledge>lambdaQuery().orderByDesc(AigcKnowledge::getCreateTime));
build(list);
return CommonResult.success(list);
}
private void build(List<AigcKnowledge> records) {
Map<String, List<AigcEmbedStore>> embedStoreMap = embedStoreService.list().stream().collect(Collectors.groupingBy(AigcEmbedStore::getId));
Map<String, List<AigcModel>> embedModelMap = modelService.list().stream().collect(Collectors.groupingBy(AigcModel::getId));
Map<String, List<AigcDocs>> docsMap = docsMapper.selectList(Wrappers.lambdaQuery()).stream().collect(Collectors.groupingBy(AigcDocs::getKnowledgeId));
records.forEach(item -> {
List<AigcDocs> docs = docsMap.get(item.getId());
if (docs != null) {
item.setDocsNum(docs.size());
item.setTotalSize(docs.stream().filter(d -> d.getSize() != null).mapToLong(AigcDocs::getSize).sum());
}
if (item.getEmbedModelId() != null) {
List<AigcModel> list = embedModelMap.get(item.getEmbedModelId());
item.setEmbedModel(list == null ? null : list.get(0));
}
if (item.getEmbedStoreId() != null) {
List<AigcEmbedStore> list = embedStoreMap.get(item.getEmbedStoreId());
item.setEmbedStore(list == null ? null : list.get(0));
}
});
}
@GetMapping("/page")
@TenantIgnore
public CommonResult list(AigcKnowledge data, QueryPage queryPage) {
Page<AigcKnowledge> page = new Page<>(queryPage.getPageNo(), queryPage.getPageSize());
LambdaQueryWrapper<AigcKnowledge> queryWrapper = Wrappers.<AigcKnowledge>lambdaQuery()
.like(!StrUtil.isBlank(data.getName()), AigcKnowledge::getName, data.getName())
.orderByDesc(AigcKnowledge::getCreateTime);
Page<AigcKnowledge> iPage = kbService.page(page, queryWrapper);
build(iPage.getRecords());
return CommonResult.success(MybatisUtil.getData(iPage));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcKnowledge> findById(@PathVariable String id) {
AigcKnowledge knowledge = kbService.getById(id);
if (knowledge.getEmbedStoreId() != null) {
knowledge.setEmbedStore(embedStoreService.getById(knowledge.getEmbedStoreId()));
}
if (knowledge.getEmbedModelId() != null) {
knowledge.setEmbedModel(modelService.getById(knowledge.getEmbedModelId()));
}
return CommonResult.success(knowledge);
}
@PostMapping
@ApiLog("新增知识库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:knowledge:add')")
public CommonResult add(@RequestBody AigcKnowledge data) {
data.setCreateTime(String.valueOf(System.currentTimeMillis()));
kbService.save(data);
knowledgeStore.init();
return CommonResult.success("success");
}
@PutMapping
@ApiLog("更新知识库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:knowledge:update')")
public CommonResult update(@RequestBody AigcKnowledge data) {
kbService.updateById(data);
knowledgeStore.init();
return CommonResult.success("success");
}
@DeleteMapping("/{id}")
@ApiLog("删除知识库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:knowledge:delete')")
public CommonResult delete(@PathVariable String id) {
kbService.removeKnowledge(id);
knowledgeStore.init();
return CommonResult.success("success");
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.entity.AigcMessage;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcMessageService;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
/**
* @author tycoding
* @since 2024/1/19
*/
@RequestMapping("/chat/aigc/message")
@RestController
@AllArgsConstructor
public class AigcMessageController {
private final AigcMessageService aigcMessageService;
@GetMapping("/page")
@TenantIgnore
public CommonResult list(AigcMessage data, QueryPage queryPage) {
LambdaQueryWrapper<AigcMessage> queryWrapper = Wrappers.<AigcMessage>lambdaQuery()
.like(!StrUtil.isBlank(data.getMessage()), AigcMessage::getMessage, data.getMessage())
.like(!StrUtil.isBlank(data.getUsername()), AigcMessage::getUsername, data.getUsername())
.eq(!StrUtil.isBlank(data.getRole()), AigcMessage::getRole, data.getRole())
.orderByDesc(AigcMessage::getCreateTime);
IPage<AigcMessage> iPage = aigcMessageService.page(MybatisUtil.wrap(data, queryPage), queryWrapper);
return CommonResult.success(MybatisUtil.getData(iPage));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult getById(@PathVariable String id) {
return CommonResult.success(aigcMessageService.getById(id));
}
@DeleteMapping("/{id}")
@ApiLog("删除会话消息")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:message:delete')")
public CommonResult del(@PathVariable String id) {
return CommonResult.success(aigcMessageService.removeById(id));
}
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.component.ProviderRefreshEvent;
import cn.iocoder.yudao.module.langchat.component.SpringContextHolder;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcModelService;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author tycoding
* @since 2024/4/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/chat/aigc/model")
public class AigcModelController {
private final AigcModelService modelService;
private final SpringContextHolder contextHolder;
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcModel>> list(AigcModel data) {
return CommonResult.success(modelService.list(data));
}
@GetMapping("/page")
@TenantIgnore
public CommonResult list(AigcModel data, QueryPage queryPage) {
Page<AigcModel> iPage = modelService.page(data, queryPage);
return CommonResult.success(MybatisUtil.getData(iPage));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcModel> findById(@PathVariable String id) {
return CommonResult.success(modelService.selectById(id));
}
@PostMapping
@ApiLog("添加模型")
@PreAuthorize("@ss.hasPermission('aigc:model:add')")
@TenantIgnore
public CommonResult add(@RequestBody AigcModel data) {
if (StrUtil.isNotBlank(data.getApiKey()) && data.getApiKey().contains("*")) {
data.setApiKey(null);
}
if (StrUtil.isNotBlank(data.getSecretKey()) && data.getSecretKey().contains("*")) {
data.setSecretKey(null);
}
modelService.save(data);
SpringContextHolder.publishEvent(new ProviderRefreshEvent(data));
return CommonResult.success("success");
}
@PutMapping
@ApiLog("修改模型")
@PreAuthorize("@ss.hasPermission('aigc:model:update')")
@TenantIgnore
public CommonResult update(@RequestBody AigcModel data) {
if (StrUtil.isNotBlank(data.getApiKey()) && data.getApiKey().contains("*")) {
data.setApiKey(null);
}
if (StrUtil.isNotBlank(data.getSecretKey()) && data.getSecretKey().contains("*")) {
data.setSecretKey(null);
}
modelService.updateById(data);
SpringContextHolder.publishEvent(new ProviderRefreshEvent(data));
return CommonResult.success("success");
}
@DeleteMapping("/{id}")
@ApiLog("删除模型")
@PreAuthorize("@ss.hasPermission('aigc:model:delete')")
@TenantIgnore
public CommonResult delete(@PathVariable String id) {
modelService.removeById(id);
// Delete dynamically registered beans, according to ID
contextHolder.unregisterBean(id);
return CommonResult.success("success");
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.langchat.entity.AigcOss;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcOssService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* @author tycoding
* @since 2024/1/19
*/
@RequestMapping("/aigc/oss")
@RestController
@AllArgsConstructor
public class AigcOssController {
private final AigcOssService aigcOssService;
@GetMapping("/list")
public CommonResult list() {
List<AigcOss> list = aigcOssService.list(Wrappers.<AigcOss>lambdaQuery()
.eq(AigcOss::getUserId, SecurityFrameworkUtils.getLoginUserId())
.orderByDesc(AigcOss::getCreateTime)
);
return CommonResult.success(null);
}
@PostMapping("/upload")
public CommonResult upload(MultipartFile file) {
return CommonResult.success(aigcOssService.upload(file, String.valueOf(SecurityFrameworkUtils.getLoginUserId())));
}
@PutMapping
public CommonResult update(@RequestBody AigcOss data) {
aigcOssService.updateById(data);
return CommonResult.success(null);
}
@DeleteMapping("/{id}")
public CommonResult delete(@PathVariable String id) {
aigcOssService.removeById(id);
return CommonResult.success(null);
}
}

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.endpoint;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.langchat.dal.dto.ChatReq;
import cn.iocoder.yudao.module.langchat.dal.dto.ChatRes;
import cn.iocoder.yudao.module.langchat.dal.dto.ImageR;
import cn.iocoder.yudao.module.langchat.dal.dto.PromptConst;
import cn.iocoder.yudao.module.langchat.entity.AigcApp;
import cn.iocoder.yudao.module.langchat.entity.AigcMessage;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.enums.RoleEnum;
import cn.iocoder.yudao.module.langchat.properties.ChatProps;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcAppService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcMessageService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcModelService;
import cn.iocoder.yudao.module.langchat.service.core.ChatService;
import cn.iocoder.yudao.module.langchat.service.core.impl.PersistentChatMemoryStore;
import cn.iocoder.yudao.module.langchat.utils.PromptUtil;
import cn.iocoder.yudao.module.langchat.utils.StreamEmitter;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author tycoding
* @since 2024/1/30
*/
@Slf4j
@RequestMapping("/aigc")
@RestController
@AllArgsConstructor
public class ChatEndpoint {
private final ChatService chatService;
private final AigcMessageService messageService;
private final AigcModelService aigcModelService;
private final AigcAppService appService;
private final ChatProps chatProps;
@PostMapping("/chat/completions")
public SseEmitter chat(@RequestBody ChatReq req) {
StreamEmitter emitter = new StreamEmitter();
req.setEmitter(emitter);
req.setUserId(String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
req.setUsername(SecurityFrameworkUtils.getLoginUserNickname());
ExecutorService executor = Executors.newSingleThreadExecutor();
req.setExecutor(executor);
return emitter.streaming(executor, () -> {
chatService.chat(req);
});
}
@GetMapping("/app/info")
public CommonResult<AigcApp> appInfo(@RequestParam String appId, String conversationId) {
AigcApp app = appService.getById(appId);
if (StrUtil.isBlank(conversationId)) {
conversationId = app.getId();
}
if (StrUtil.isNotBlank(app.getPrompt())) {
// initialize chat memory
SystemMessage message = new SystemMessage(app.getPrompt());
PersistentChatMemoryStore.init(conversationId, message);
}
return CommonResult.success(app);
}
@GetMapping("/chat/messages/{conversationId}")
public CommonResult messages(@PathVariable String conversationId) {
List<AigcMessage> list = messageService.getMessages(conversationId, String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
// initialize chat memory
List<ChatMessage> chatMessages = new ArrayList<>();
list.forEach(item -> {
if (chatMessages.size() >= chatProps.getMemoryMaxMessage()) {
return;
}
if (item.getRole().equals(RoleEnum.ASSISTANT.getName())) {
chatMessages.add(new AiMessage(item.getMessage()));
} else {
chatMessages.add(new UserMessage(item.getMessage()));
}
});
PersistentChatMemoryStore.init(conversationId, chatMessages);
return CommonResult.success(list);
}
@DeleteMapping("/chat/messages/clean/{conversationId}")
public CommonResult cleanMessage(@PathVariable String conversationId) {
messageService.clearMessage(conversationId);
// clean chat memory
PersistentChatMemoryStore.clean(conversationId);
return CommonResult.success(null);
}
@PostMapping("/chat/mindmap")
public CommonResult mindmap(@RequestBody ChatReq req) {
req.setPrompt(PromptUtil.build(req.getMessage(), PromptConst.MINDMAP));
return CommonResult.success(new ChatRes(chatService.text(req)));
}
@PostMapping("/chat/image")
public CommonResult image(@RequestBody ImageR req) {
req.setPrompt(PromptUtil.build(req.getMessage(), PromptConst.IMAGE));
return CommonResult.success(chatService.image(req));
}
@GetMapping("/chat/getImageModels")
public CommonResult<List<AigcModel>> getImageModels() {
List<AigcModel> list = aigcModelService.getImageModels();
list.forEach(i -> {
i.setApiKey(null);
i.setSecretKey(null);
});
return CommonResult.success(list);
}
}

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.endpoint;
import ch.qos.logback.core.net.LoginAuthenticator;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.dal.dto.ChatReq;
import cn.iocoder.yudao.module.langchat.dal.dto.EmbeddingR;
import cn.iocoder.yudao.module.langchat.entity.AigcDocs;
import cn.iocoder.yudao.module.langchat.entity.AigcDocsSlice;
import cn.iocoder.yudao.module.langchat.entity.AigcOss;
import cn.iocoder.yudao.module.langchat.enums.EmbedConst;
import cn.iocoder.yudao.module.langchat.mapper.AigcDocsMapper;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcKnowledgeService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcOssService;
import cn.iocoder.yudao.module.langchat.service.core.EmbeddingService;
import cn.iocoder.yudao.module.langchat.service.core.LangEmbeddingService;
import cn.iocoder.yudao.module.langchat.task.TaskManager;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.concurrent.Executors;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
/**
* @author tycoding
* @since 2024/4/25
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/chat/aigc/embedding")
public class EmbeddingEndpoint {
private final LangEmbeddingService langEmbeddingService;
private final AigcKnowledgeService aigcKnowledgeService;
private final AigcDocsMapper aigcDocsMapper;
private final AigcOssService aigcOssService;
private final EmbeddingService embeddingService;
@PostMapping("/text")
@PreAuthorize("@ss.hasPermission('aigc:embedding:text')")
@TenantIgnore
public CommonResult text(@RequestBody AigcDocs data) {
if (StrUtil.isBlankIfStr(data.getContent())) {
throw new ServiceException(-1003,"文档内容不能为空");
}
if (StrUtil.isBlank(data.getId())) {
aigcKnowledgeService.addDocs(data);
}
data.setType(EmbedConst.ORIGIN_TYPE_INPUT).setSliceStatus(false);
try {
EmbeddingR embeddingR = langEmbeddingService.embeddingText(
new ChatReq().setMessage(data.getContent())
.setDocsName(data.getType())
.setDocsId(data.getId())
.setKnowledgeId(data.getKnowledgeId()));
aigcKnowledgeService.addDocsSlice(new AigcDocsSlice()
.setKnowledgeId(data.getKnowledgeId())
.setDocsId(data.getId())
.setVectorId(embeddingR.getVectorId())
.setName(data.getName())
.setContent(embeddingR.getText())
);
aigcKnowledgeService.updateDocs(new AigcDocs().setId(data.getId()).setSliceStatus(true).setSliceNum(1));
} catch (Exception e) {
e.printStackTrace();
// del data
aigcKnowledgeService.removeSlicesOfDoc(data.getId());
}
return CommonResult.success("success");
}
@PostMapping("/docs/{knowledgeId}")
@PreAuthorize("@ss.hasPermission('aigc:embedding:docs')")
@TenantIgnore
public CommonResult docs(MultipartFile file, @PathVariable String knowledgeId) {
// 1.1 获得用户信息
String userId = getLoginUserId().toString();
AigcOss oss = aigcOssService.upload(file, userId);
AigcDocs data = new AigcDocs()
.setName(oss.getOriginalFilename())
.setSliceStatus(false)
.setUrl(oss.getUrl())
.setSize(file.getSize())
.setType(EmbedConst.ORIGIN_TYPE_UPLOAD)
.setKnowledgeId(knowledgeId);
aigcKnowledgeService.addDocs(data);
TaskManager.submitTask(userId, Executors.callable(() -> {
embeddingService.embedDocsSlice(data, oss.getUrl());
}));
return CommonResult.success("success");
}
@GetMapping("/re-embed/{docsId}")
@TenantIgnore
public CommonResult reEmbed(@PathVariable String docsId) {
String userId = getLoginUserId().toString();
AigcDocs docs = aigcDocsMapper.selectById(docsId);
if (docs == null) {
throw new ServiceException(-1003,"没有查询到文档数据");
}
if (EmbedConst.ORIGIN_TYPE_INPUT.equals(docs.getType())) {
text(docs);
}
if (EmbedConst.ORIGIN_TYPE_UPLOAD.equals(docs.getType())) {
// clear before re-embed
embeddingService.clearDocSlices(docsId);
TaskManager.submitTask(userId, Executors.callable(() -> {
embeddingService.embedDocsSlice(docs, docs.getUrl());
}));
}
return CommonResult.success("success");
}
@PostMapping("/search")
@TenantIgnore
public CommonResult search(@RequestBody AigcDocs data) {
return CommonResult.success(embeddingService.search(data));
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.dal.dto;
import cn.iocoder.yudao.module.langchat.utils.StreamEmitter;
import dev.langchain4j.model.input.Prompt;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
/**
* @author tycoding
* @since 2024/1/30
*/
@Data
@Accessors(chain = true)
public class ChatReq {
private String appId;
private String modelId;
private String modelName;
private String modelProvider;
private String message;
private String conversationId;
private String userId;
private String username;
private String chatId;
private String promptText;
private String docsName;
private String knowledgeId;
private List<String> knowledgeIds = new ArrayList<>();
private String docsId;
private String url;
private String role;
private Prompt prompt;
private StreamEmitter emitter;
private Executor executor;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.dal.dto;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author tycoding
* @since 2024/1/29
*/
@Data
@Accessors(chain = true)
public class ChatRes {
private boolean isDone = false;
private String message;
private Integer usedToken;
private long time;
public ChatRes(String message) {
this.message = message;
}
public ChatRes(Integer usedToken, long startTime) {
this.isDone = true;
this.usedToken = usedToken;
this.time = System.currentTimeMillis() - startTime;
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.dal.dto;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author tycoding
* @since 2024/4/26
*/
@Data
@Accessors(chain = true)
public class EmbeddingR {
/**
* 写入到vector store的ID
*/
private String vectorId;
/**
* 文档ID
*/
private String docsId;
/**
* 知识库ID
*/
private String knowledgeId;
/**
* Embedding后切片的文本
*/
private String text;
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.dal.dto;
import dev.langchain4j.model.input.Prompt;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author tycoding
* @since 2024/1/6
*/
@Data
@Accessors(chain = true)
public class ImageR {
private String modelId;
private String modelName;
private String modelProvider;
private Prompt prompt;
/**
* 内容
*/
private String message;
/**
* 质量
*/
private String quality;
/**
* 尺寸
*/
private String size;
/**
* 风格
*/
private String style;
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.dal.dto;
/**
* @author tycoding
* @since 2024/3/1
*/
public interface PromptConst {
String QUESTION = "question";
String EMPTY = """
------
{{question}}
------
""";
String DOCUMENT = "You are good at analyzing documents. Please analyze my questions according to the following documents, question: [{{question}}], [docs]";
String MINDMAP = """
# Role
You are a Markdown outline format engineer who focuses on answering user questions. You can quickly and accurately convert user questions into refined Markdown outline titles, and refine the specific details of each title.
## Skills
### Skill 1: Identify user question intent
- Accurately understand the specific content and needs of user questions.
### Skill 2: Convert to Markdown outline
- Simplify user questions into Markdown outline-style titles.
### Skill 3: Return to user
- Return the optimized outline to the user.
## Constraints
- Only return the organized Markdown format content, without other explanation information
- Answer the question in the language used by the user.
- Return the answer in Markdown style, keep the main title as concise as possible; and refine the specific step information of each main title in the subtitle.
""";
String WRITE = """
# 角色
你是一名专业文案撰写师你擅长运用行业领域相关知识以专业的视角为用户生成Markdown文档
## 技能
### 技能 1: 写作
- 提取用户输入的主题和关键信息
### 技能 2: 专业知识应用
- 了解相关行业的相关知识
- 在撰写内容时运用专业的语言和视角
### 技能 3: 遵循Markdown格式
- 拆分文档内容以Markdown大纲格式分段内容更易于用户阅读
## 限制
- 只讨论写作相关的话题不要返回其他任何内容和解释
- 始终以用户输入的信息为主题撰写内容
""";
String IMAGE = """
Please generate the corresponding pictures according to the following requirements.
""";
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.ibatis.type.JdbcType;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author tycoding
* @since 2024/7/26
*/
@Data
@TableName(autoResultMap = true)
@Accessors(chain = true)
public class AigcApp implements Serializable {
private static final long serialVersionUID = -94917153262781949L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String modelId;
@TableField(typeHandler = FastjsonTypeHandler.class, jdbcType = JdbcType.VARCHAR)
private List<String> knowledgeIds;
/**
* 名称
*/
private String name;
private String cover;
/**
* Prompt
*/
private String prompt;
/**
* 应用描述
*/
private String des;
/**
* 创建时间
*/
private Date saveTime;
private Date createTime;
@TableField(exist = false)
private AigcModel model;
@TableField(exist = false)
private List<AigcKnowledge> knowledges = new ArrayList<>();
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author tycoding
* @since 2024/7/26
*/
@Data
@Accessors(chain = true)
public class AigcAppApi implements Serializable {
private static final long serialVersionUID = -94917153262781949L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String appId;
private String apiKey;
private String channel;
private Date createTime;
@TableField(exist = false)
private AigcApp app;
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author tycoding
* @since 2024/1/4
*/
@Data
@Accessors(chain = true)
public class AigcConversation implements Serializable {
private static final long serialVersionUID = -19545329638997333L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 提示词ID
*/
private String promptId;
/**
* 用户ID
*/
private String userId;
/**
* 会话标题
*/
private String title;
/**
* 创建时间
*/
private Date createTime;
/**
* 用户名
*/
@TableField(exist = false)
private String username;
/**
* 对话次数
*/
@TableField(exist = false)
private Integer chatTotal;
/**
* Token消耗量
*/
@TableField(exist = false)
private Integer tokenUsed;
/**
* 最后一次对话时间
*/
@TableField(exist = false)
private Date endTime;
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author tycoding
* @since 2024/4/15
*/
@Data
@Accessors(chain = true)
public class AigcDocs implements Serializable {
private static final long serialVersionUID = 548724967827903685L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 知识库ID
*/
private String knowledgeId;
/**
* 名称
*/
private String name;
/**
* 类型
*/
private String type;
/**
* 来源
*/
private String origin;
private String url;
/**
* 文件大小
*/
private Long size;
/**
* 切片数量
*/
private Integer sliceNum;
/**
* 切片状态
*/
private Boolean sliceStatus;
/**
* 文档内容
*/
private String content;
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author tycoding
* @since 2024/4/15
*/
@Data
@Accessors(chain = true)
public class AigcDocsSlice implements Serializable {
private static final long serialVersionUID = -3093489071059867065L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 向量库的ID
*/
private String vectorId;
/**
* 文档ID
*/
private String docsId;
/**
* 知识库ID
*/
private String knowledgeId;
/**
* 文档名称
*/
private String name;
/**
* 切片内容
*/
private String content;
/**
* 字符数量
*/
private Integer wordNum;
/**
* 是否Embedding
*/
private Boolean status = false;
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* @author tycoding
* @since 2024/10/28
*/
@Data
@TableName(autoResultMap = true)
public class AigcEmbedStore implements Serializable {
private static final long serialVersionUID = 548724967827903685L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String name;
private String provider;
private String host;
private Integer port;
private String username;
private String password;
private String databaseName;
private String tableName;
private Integer dimension;
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* @author tycoding
* @since 2024/4/15
*/
@Data
@TableName(autoResultMap = true)
public class AigcKnowledge implements Serializable {
private static final long serialVersionUID = 548724967827903685L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String embedStoreId;
private String embedModelId;
/**
* 知识库名称
*/
private String name;
/**
* 封面
*/
private String cover;
/**
* 描述
*/
private String des;
/**
* 创建时间
*/
private String createTime;
@TableField(exist = false)
private Integer docsNum = 0;
@TableField(exist = false)
private Long totalSize = 0L;
@TableField(exist = false)
private List<AigcDocs> docs = new ArrayList<>();
@TableField(exist = false)
private AigcEmbedStore embedStore;
@TableField(exist = false)
private AigcModel embedModel;
}

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author tycoding
* @since 2024/1/4
*/
@Data
@Accessors(chain = true)
public class AigcMessage implements Serializable {
private static final long serialVersionUID = -19545329638997333L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 消息ID
*/
private String chatId;
/**
* 会话ID
*/
private String conversationId;
/**
* 用户ID
*/
private String userId;
/**
* 用户名
*/
private String username;
/**
* 请求IP
*/
private String ip;
private Integer tokens;
private Integer promptTokens;
/**
* 角色userassistant
*/
private String role;
/**
* 消息内容
*/
private String model;
/**
* 消息内容
*/
private String message;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author tycoding
* @since 2024/1/4
*/
@Data
@Accessors(chain = true)
public class AigcModel implements Serializable {
private static final long serialVersionUID = -19545329638997333L;
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String type;
private String model;
private String provider;
private String name;
private Integer responseLimit;
private Double temperature = 0.2;
private Double topP = 0.0;
private String apiKey;
private String secretKey;
private String baseUrl;
private String endpoint;
private String geminiLocation;
private String geminiProject;
private String azureDeploymentName;
private String imageSize;
private String imageQuality;
private String imageStyle;
private Integer dimension;
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @author tycoding
* @since 2024/1/6
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
public class AigcOss extends OssR {
private static final long serialVersionUID = -250127374910520163L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 用户ID
*/
private String userId;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* OSS 文件对象
*
* @author tycoding
* @since 2024/1/30
*/
@Data
@Accessors(chain = true)
public class OssR implements Serializable {
private static final long serialVersionUID = 5117927170776709434L;
private String ossId;
private String url;
private Long size;
private String filename;
private String originalFilename;
private String basePath;
private String path;
private String ext;
private String contentType;
private String platform;
private Date createTime;
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 部门表(Dept)实体类
*
* @author tycoding
* @since 2024/4/15
*/
@Data
@Accessors(chain = true)
public class SysDept implements Serializable {
private static final long serialVersionUID = -94917153262781949L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 上级部门ID
*/
private String parentId;
/**
* 部门名称
*/
private String name;
/**
* 排序
*/
private Integer orderNo;
/**
* 描述
*/
private String des;
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 角色表(Role)实体类
*
* @author tycoding
* @since 2024/4/15
*/
@Data
@Accessors(chain = true)
public class SysRole implements Serializable {
private static final long serialVersionUID = 547891924677981054L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 角色名称
*/
private String name;
/**
* 角色别名
*/
private String code;
/**
* 描述
*/
private String des;
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* 用户表(User)实体类
*
* @author tycoding
* @since 2024/4/15
*/
@Data
@Accessors(chain = true)
@TableName("sys_user")
public class SysUser implements Serializable {
private static final long serialVersionUID = -94827981963832107L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 真实姓名
*/
private String realName;
/**
* 性别
*/
private String sex;
/**
* 邮箱
*/
private String email;
/**
* 部门ID
*/
private String deptId;
/**
* 头像
*/
private String avatar;
/**
* 手机
*/
private String phone;
/**
* 状态 0锁定 1有效
*/
private Boolean status;
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
/**
* 自定义Oauth2 授权成功后存储的用户数据
*
* @author tycoding
* @since 2024/4/15
*/
@Data
@Accessors(chain = true)
public class UserInfo extends SysUser implements Serializable {
private static final long serialVersionUID = 547891924677981054L;
/**
* 用户所属部门
*/
private SysDept dept;
/**
* 部门名称
*/
private String deptName;
/**
* 角色ID列表
*/
private List<String> roleIds;
/**
* 用户角色列表
*/
private List<SysRole> roles;
/**
* 用户权限标识
*/
private Set<String> perms;
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.enums;
import lombok.Getter;
/**
* @author tycoding
* @since 2024/2/20
*/
@Getter
public enum RoleEnum {
USER("user"),
ASSISTANT("assistant"),
SYSTEM("system"),
;
private final String name;
RoleEnum(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,6 @@
/**
* 属于 system 模块的 framework 封装
*
* @author 芋道源码
*/
package cn.iocoder.yudao.module.langchat.framework;

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.langchat.framework.security;
import cn.iocoder.yudao.framework.common.enums.RpcConstants;
/**
* API 相关的枚举
*
* @author 芋道源码
*/
public class ApiConstants {
/**
* 服务名
*
* 注意需要保证和 spring.application.name 保持一致
*/
public static final String NAME = "langChat-server";
public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/langChat";
public static final String VERSION = "1.0.0";
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.langchat.framework.security.config;
import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
import cn.iocoder.yudao.module.langchat.framework.security.ApiConstants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
/**
* System 模块的 Security 配置
*/
@Configuration(proxyBeanMethods = false, value = "systemSecurityConfiguration")
public class SecurityConfiguration {
@Bean("systemAuthorizeRequestsCustomizer")
public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
return new AuthorizeRequestsCustomizer() {
@Override
public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
// TODO 芋艿这个每个项目都需要重复配置得捉摸有没通用的方案
// Swagger 接口文档
registry.requestMatchers("/v3/api-docs/**").permitAll()
.requestMatchers("/webjars/**").permitAll()
.requestMatchers("/swagger-ui").permitAll()
.requestMatchers("/swagger-ui/**").permitAll();
// Druid 监控
registry.requestMatchers("/druid/**").permitAll();
// Spring Boot Actuator 的安全配置
registry.requestMatchers("/actuator").permitAll()
.requestMatchers("/actuator/**").permitAll();
// RPC 服务的安全配置
registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
}
};
}
}

View File

@ -0,0 +1,4 @@
/**
* 占位
*/
package cn.iocoder.yudao.module.langchat.framework.security.core;

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.mapper;
import cn.iocoder.yudao.module.langchat.entity.AigcAppApi;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tycoding
* @since 2024/7/26
*/
@Mapper
public interface AigcAppApiMapper extends BaseMapper<AigcAppApi> {
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.mapper;
import cn.iocoder.yudao.module.langchat.entity.AigcApp;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tycoding
* @since 2024/7/26
*/
@Mapper
public interface AigcAppMapper extends BaseMapper<AigcApp> {
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.mapper;
import cn.iocoder.yudao.module.langchat.entity.AigcConversation;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tycoding
* @since 2024/1/4
*/
@Mapper
public interface AigcConversationMapper extends BaseMapper<AigcConversation> {
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.mapper;
import cn.iocoder.yudao.module.langchat.entity.AigcDocs;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tycoding
* @since 2024/4/15
*/
@Mapper
public interface AigcDocsMapper extends BaseMapper<AigcDocs> {
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.mapper;
import cn.iocoder.yudao.module.langchat.entity.AigcDocsSlice;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tycoding
* @since 2024/4/15
*/
@Mapper
public interface AigcDocsSliceMapper extends BaseMapper<AigcDocsSlice> {
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.mapper;
import cn.iocoder.yudao.module.langchat.entity.AigcEmbedStore;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tycoding
* @since 2024/10/28
*/
@Mapper
public interface AigcEmbedStoreMapper extends BaseMapper<AigcEmbedStore> {
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.mapper;
import cn.iocoder.yudao.module.langchat.entity.AigcKnowledge;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tycoding
* @since 2024/4/15
*/
@Mapper
public interface AigcKnowledgeMapper extends BaseMapper<AigcKnowledge> {
}

View File

@ -0,0 +1,136 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.mapper;
import cn.hutool.core.lang.Dict;
import cn.iocoder.yudao.module.langchat.entity.AigcMessage;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author tycoding
* @since 2024/1/4
*/
@Mapper
public interface AigcMessageMapper extends BaseMapper<AigcMessage> {
@Select("""
WITH RECURSIVE DateRange AS (
SELECT CURDATE() AS date
UNION ALL
SELECT date - INTERVAL 1 DAY
FROM DateRange
WHERE date > DATE_SUB(CURDATE(), INTERVAL 31 DAY)
)
SELECT
d.date,
COALESCE(COUNT(*), 0) AS tokens
FROM
DateRange d
LEFT JOIN
aigc_message m
ON
DATE(m.create_time) = d.date
AND m.role = 'assistant'
GROUP BY
d.date
ORDER BY
d.date DESC;
""")
List<Dict> getReqChartBy30();
@Select("""
SELECT
COALESCE(DATE_FORMAT(create_time, '%Y-%m'), 0) as month,
COALESCE(COUNT(*), 0) as count
FROM
aigc_message
WHERE
create_time >= DATE_SUB(CURDATE(), INTERVAL 1 YEAR)
AND role = 'assistant'
GROUP BY
month
ORDER BY
month ASC;
""")
List<Dict> getReqChart();
@Select("""
WITH RECURSIVE DateRange AS (
SELECT CURDATE() AS date
UNION ALL
SELECT date - INTERVAL 1 DAY
FROM DateRange
WHERE date > DATE_SUB(CURDATE(), INTERVAL 31 DAY)
)
SELECT
d.date,
COALESCE(SUM(m.tokens), 0) AS tokens
FROM
DateRange d
LEFT JOIN
aigc_message m
ON
DATE(m.create_time) = d.date
AND m.role = 'assistant'
GROUP BY
d.date
ORDER BY
d.date DESC;
""")
List<Dict> getTokenChartBy30();
@Select("""
SELECT
COALESCE(DATE_FORMAT(create_time, '%Y-%m'), 0) as month,
COALESCE(SUM(tokens), 0) as count
FROM
aigc_message
WHERE
create_time >= DATE_SUB(CURDATE(), INTERVAL 1 YEAR)
AND role = 'assistant'
GROUP BY
month
ORDER BY
month ASC;
""")
List<Dict> getTokenChart();
@Select("""
SELECT
COALESCE(COUNT(*), 0) AS totalReq,
COALESCE(SUM( CASE WHEN DATE ( create_time ) = CURDATE() THEN 1 ELSE 0 END ), 0) AS curReq
FROM
aigc_message
WHERE
role = 'assistant'
""")
Dict getCount();
@Select("""
SELECT
COALESCE(SUM(tokens), 0) AS totalToken,
COALESCE(SUM(CASE WHEN DATE(create_time) = CURDATE() THEN tokens ELSE 0 END), 0) AS curToken
FROM
aigc_message;
""")
Dict getTotalSum();
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.mapper;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tycoding
* @since 2024/4/15
*/
@Mapper
public interface AigcModelMapper extends BaseMapper<AigcModel> {
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.mapper;
import cn.iocoder.yudao.module.langchat.entity.AigcOss;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tycoding
* @since 2024/1/19
*/
@Mapper
public interface AigcOssMapper extends BaseMapper<AigcOss> {
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.mapper;
import cn.hutool.core.lang.Dict;
import cn.iocoder.yudao.module.langchat.entity.SysUser;
import cn.iocoder.yudao.module.langchat.entity.UserInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
/**
* 用户表(User)表数据库访问层
*
* @author tycoding
* @since 2024/4/15
*/
@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {
@Select("""
SELECT
COALESCE(COUNT(*), 0) AS totalUser,
COALESCE(SUM( CASE WHEN YEAR ( create_time ) = YEAR ( CURDATE()) AND MONTH ( create_time ) = MONTH ( CURDATE()) THEN 1 ELSE 0 END ), 0) AS curUser
FROM
sys_user;
""")
Dict getCount();
IPage<UserInfo> page(IPage<SysUser> page, UserInfo user, String ignoreId, String ignoreName);
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author tycoding
* @since 2024/8/21
*/
@Data
@ConfigurationProperties("langchat.chat")
public class ChatProps {
/**
* 上下文的长度
*/
private Integer memoryMaxMessage = 20;
/**
* 前端渲染的消息长度过长会导致页面渲染卡顿
*/
private Integer previewMaxMessage = 100;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author tycoding
* @since 2024/4/15
*/
@Data
@Component
@ConfigurationProperties(prefix = "langchat")
public class LangChatProps {
}

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.provider;
import cn.iocoder.yudao.module.langchat.entity.AigcKnowledge;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.store.embedding.EmbeddingStore;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
/**
* @author tycoding
* @since 2024/3/8
*/
@Slf4j
@Component
@AllArgsConstructor
public class EmbeddingProvider {
private final EmbeddingStoreFactory embeddingStoreFactory;
private final KnowledgeStoreFactory knowledgeStoreFactory;
private final ModelStoreFactory modelStoreFactory;
public static DocumentSplitter splitter() {
return DocumentSplitters.recursive(300, 20);
}
public EmbeddingModel getEmbeddingModel(List<String> knowledgeIds) {
List<String> storeIds = new ArrayList<>();
knowledgeIds.forEach(id -> {
if (knowledgeStoreFactory.containsKnowledge(id)) {
AigcKnowledge data = knowledgeStoreFactory.getKnowledge(id);
if (data.getEmbedModelId() != null) {
storeIds.add(data.getEmbedModelId());
}
}
});
if (storeIds.isEmpty()) {
throw new UnsupportedOperationException("知识库缺少Embedding Model配置请先检查配置");
}
HashSet<String> filterIds = new HashSet<>(storeIds);
if (filterIds.size() > 1) {
throw new UnsupportedOperationException("存在多个不同Embedding Model的知识库请先检查配置");
}
return modelStoreFactory.getEmbeddingModel(storeIds.get(0));
}
public EmbeddingModel getEmbeddingModel(String knowledgeId) {
if (knowledgeStoreFactory.containsKnowledge(knowledgeId)) {
AigcKnowledge data = knowledgeStoreFactory.getKnowledge(knowledgeId);
if (modelStoreFactory.containsEmbeddingModel(data.getEmbedModelId())) {
return modelStoreFactory.getEmbeddingModel(data.getEmbedModelId());
}
}
throw new UnsupportedOperationException("没有找到匹配的Embedding向量数据库");
}
public EmbeddingStore<TextSegment> getEmbeddingStore(String knowledgeId) {
if (knowledgeStoreFactory.containsKnowledge(knowledgeId)) {
AigcKnowledge data = knowledgeStoreFactory.getKnowledge(knowledgeId);
if (embeddingStoreFactory.containsEmbeddingStore(data.getEmbedStoreId())) {
return embeddingStoreFactory.getEmbeddingStore(data.getEmbedStoreId());
}
}
throw new UnsupportedOperationException("没有找到匹配的Embedding向量数据库");
}
public EmbeddingStore<TextSegment> getEmbeddingStore(List<String> knowledgeIds) {
List<String> storeIds = new ArrayList<>();
knowledgeIds.forEach(id -> {
if (knowledgeStoreFactory.containsKnowledge(id)) {
AigcKnowledge data = knowledgeStoreFactory.getKnowledge(id);
if (data.getEmbedStoreId() != null) {
storeIds.add(data.getEmbedStoreId());
}
}
});
if (storeIds.isEmpty()) {
throw new UnsupportedOperationException("知识库缺少Embedding Store配置请先检查配置");
}
HashSet<String> filterIds = new HashSet<>(storeIds);
if (filterIds.size() > 1) {
throw new UnsupportedOperationException("存在多个不同Embedding Store数据源的知识库请先检查配置");
}
return embeddingStoreFactory.getEmbeddingStore(storeIds.get(0));
}
}

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.provider;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.langchat.enums.EmbedStoreEnum;
import cn.iocoder.yudao.module.langchat.entity.AigcEmbedStore;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcEmbedStoreService;
import dev.langchain4j.community.store.embedding.redis.RedisEmbeddingStore;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.milvus.MilvusEmbeddingStore;
import dev.langchain4j.store.embedding.pgvector.PgVectorEmbeddingStore;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author tycoding
* @since 2024/10/28
*/
@Slf4j
@Component
public class EmbeddingStoreFactory {
@Autowired
private AigcEmbedStoreService aigcEmbedStoreService;
private final List<AigcEmbedStore> modelStore = new ArrayList<>();
private final Map<String, EmbeddingStore<TextSegment>> embedStoreMap = new ConcurrentHashMap<>();
@Async
@PostConstruct
public void init() {
modelStore.clear();
List<AigcEmbedStore> list = aigcEmbedStoreService.list();
list.forEach(embed -> {
try {
if (EmbedStoreEnum.REDIS.name().equalsIgnoreCase(embed.getProvider())) {
RedisEmbeddingStore.Builder builder = RedisEmbeddingStore.builder()
.host(embed.getHost())
.port(embed.getPort())
.indexName(embed.getDatabaseName())
.dimension(embed.getDimension());
if (StrUtil.isNotBlank(embed.getUsername()) && StrUtil.isNotBlank(embed.getPassword())) {
builder.user(embed.getUsername()).password(embed.getPassword());
}
EmbeddingStore<TextSegment> store = builder.build();
embedStoreMap.put(embed.getId(), store);
}
if (EmbedStoreEnum.PGVECTOR.name().equalsIgnoreCase(embed.getProvider())) {
EmbeddingStore<TextSegment> store = PgVectorEmbeddingStore.builder()
.host(embed.getHost())
.port(embed.getPort())
.database(embed.getDatabaseName())
.dimension(embed.getDimension())
.user(embed.getUsername())
.password(embed.getPassword())
.table(embed.getTableName())
.indexListSize(1)
.useIndex(true)
.createTable(true)
.dropTableFirst(false)
.build();
embedStoreMap.put(embed.getId(), store);
}
if (EmbedStoreEnum.MILVUS.name().equalsIgnoreCase(embed.getProvider())) {
EmbeddingStore<TextSegment> store = MilvusEmbeddingStore.builder()
.host(embed.getHost())
.port(embed.getPort())
.databaseName(embed.getDatabaseName())
.dimension(embed.getDimension())
.username(embed.getUsername())
.password(embed.getPassword())
.collectionName(embed.getTableName())
.build();
embedStoreMap.put(embed.getId(), store);
}
modelStore.add(embed);
} catch (Exception e) {
e.printStackTrace();
log.error("向量数据库初始化失败:[{}] --- [{}],数据库配置信息:[{}]", embed.getName(), embed.getProvider(), embed);
}
});
modelStore.forEach(i -> log.info("已成功注册Embedding Store{} 配置信息:{}", i.getProvider(), i));
}
public EmbeddingStore<TextSegment> getEmbeddingStore(String embeddingId) {
return embedStoreMap.get(embeddingId);
}
public boolean containsEmbeddingStore(String embeddingId) {
return embedStoreMap.containsKey(embeddingId);
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.provider;
import cn.iocoder.yudao.module.langchat.entity.AigcEmbedStore;
import cn.iocoder.yudao.module.langchat.entity.AigcKnowledge;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcEmbedStoreService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcKnowledgeService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcModelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* @author tycoding
* @since 2024/10/29
*/
@Slf4j
@Component
public class KnowledgeStoreFactory {
@Autowired
private AigcKnowledgeService knowledgeService;
@Autowired
private AigcModelService modelService;
@Autowired
private AigcEmbedStoreService embedStoreService;
private final Map<String, AigcKnowledge> knowledgeMap = new ConcurrentHashMap<>();
@Async
@PostConstruct
public void init() {
knowledgeMap.clear();
List<AigcKnowledge> list = knowledgeService.list();
Map<String, List<AigcModel>> modelMap = modelService.list().stream().collect(Collectors.groupingBy(AigcModel::getId));
Map<String, List<AigcEmbedStore>> storeMap = embedStoreService.list().stream().collect(Collectors.groupingBy(AigcEmbedStore::getId));
list.forEach(know -> {
if (know.getEmbedModelId() != null) {
List<AigcModel> models = modelMap.get(know.getEmbedModelId());
know.setEmbedModel(models == null ? null : models.get(0));
}
if (know.getEmbedStoreId() != null) {
List<AigcEmbedStore> stores = storeMap.get(know.getEmbedStoreId());
know.setEmbedStore(stores == null ? null : stores.get(0));
}
knowledgeMap.put(know.getId(), know);
});
}
public AigcKnowledge getKnowledge(String knowledgeId) {
return knowledgeMap.get(knowledgeId);
}
public boolean containsKnowledge(String knowledgeId) {
return knowledgeMap.containsKey(knowledgeId);
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.provider;
import cn.hutool.core.util.ObjectUtil;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.image.ImageModel;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
/**
* @author tycoding
* @since 2024/3/8
*/
@Component
@AllArgsConstructor
public class ModelProvider {
private final ModelStoreFactory modelStoreFactory;
public StreamingChatLanguageModel stream(String modelId) {
StreamingChatLanguageModel streamingChatModel = modelStoreFactory.getStreamingChatModel(modelId);
if (ObjectUtil.isNotEmpty(streamingChatModel)) {
return streamingChatModel;
}
throw new RuntimeException("没有匹配到模型,请检查模型配置!");
}
public ChatLanguageModel text(String modelId) {
ChatLanguageModel chatLanguageModel = modelStoreFactory.getChatLanguageModel(modelId);
if (ObjectUtil.isNotEmpty(chatLanguageModel)) {
return chatLanguageModel;
}
throw new RuntimeException("没有匹配到模型,请检查模型配置!");
}
public ImageModel image(String modelId) {
ImageModel imageModel = modelStoreFactory.getImageModel(modelId);
if (ObjectUtil.isNotEmpty(imageModel)) {
return imageModel;
}
throw new RuntimeException("没有匹配到模型,请检查模型配置!");
}
}

View File

@ -0,0 +1,174 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.provider;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.langchat.enums.ModelConst;
import cn.iocoder.yudao.module.langchat.component.ModelTypeEnum;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.provider.build.ModelBuildHandler;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcModelService;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.image.ImageModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author tycoding
* @since 2024/6/16
*/
@Configuration
@Slf4j
public class ModelStoreFactory {
@Autowired
private AigcModelService aigcModelService;
@Autowired
private List<ModelBuildHandler> modelBuildHandlers;
private final List<AigcModel> modelStore = new ArrayList<>();
private final Map<String, StreamingChatLanguageModel> streamingChatMap = new ConcurrentHashMap<>();
private final Map<String, ChatLanguageModel> chatLanguageMap = new ConcurrentHashMap<>();
private final Map<String, EmbeddingModel> embeddingModelMap = new ConcurrentHashMap<>();
private final Map<String, ImageModel> imageModelMap = new ConcurrentHashMap<>();
@Async
@PostConstruct
public void init() {
modelStore.clear();
streamingChatMap.clear();
chatLanguageMap.clear();
embeddingModelMap.clear();
imageModelMap.clear();
List<AigcModel> list = aigcModelService.list();
list.forEach(model -> {
if (Objects.equals(model.getBaseUrl(), "")) {
model.setBaseUrl(null);
}
chatHandler(model);
embeddingHandler(model);
imageHandler(model);
});
modelStore.forEach(i -> log.info("已成功注册模型:{} -- {} 模型配置:{}", i.getProvider(), i.getType(), i));
}
private void chatHandler(AigcModel model) {
try {
String type = model.getType();
if (!ModelTypeEnum.CHAT.name().equals(type)) {
return;
}
modelBuildHandlers.forEach(x -> {
StreamingChatLanguageModel streamingChatLanguageModel = x.buildStreamingChat(model);
if (ObjectUtil.isNotEmpty(streamingChatLanguageModel)) {
streamingChatMap.put(model.getId(), streamingChatLanguageModel);
modelStore.add(model);
}
ChatLanguageModel languageModel = x.buildChatLanguageModel(model);
if (ObjectUtil.isNotEmpty(languageModel)) {
chatLanguageMap.put(model.getId() + ModelConst.TEXT_SUFFIX, languageModel);
}
});
} catch (Exception e) {
log.error("model 【 id: {} name: {}】streaming chat 配置报错", model.getId(), model.getName());
}
}
private void embeddingHandler(AigcModel model) {
try {
String type = model.getType();
if (!ModelTypeEnum.EMBEDDING.name().equals(type)) {
return;
}
modelBuildHandlers.forEach(x -> {
EmbeddingModel embeddingModel = x.buildEmbedding(model);
if (ObjectUtil.isNotEmpty(embeddingModel)) {
embeddingModelMap.put(model.getId(), embeddingModel);
modelStore.add(model);
}
});
} catch (Exception e) {
log.error("model 【id{} name{}】 embedding 配置报错", model.getId(), model.getName());
}
}
private void imageHandler(AigcModel model) {
try {
String type = model.getType();
if (!ModelTypeEnum.TEXT_IMAGE.name().equals(type)) {
return;
}
modelBuildHandlers.forEach(x -> {
ImageModel imageModel = x.buildImage(model);
if (ObjectUtil.isNotEmpty(imageModel)) {
imageModelMap.put(model.getId(), imageModel);
modelStore.add(model);
}
});
} catch (Exception e) {
log.error("model 【id{} name{}】 image 配置报错", model.getId(), model.getName());
}
}
public StreamingChatLanguageModel getStreamingChatModel(String modelId) {
return streamingChatMap.get(modelId);
}
public boolean containsStreamingChatModel(String modelId) {
return streamingChatMap.containsKey(modelId);
}
public ChatLanguageModel getChatLanguageModel(String modelId) {
return chatLanguageMap.get(modelId + ModelConst.TEXT_SUFFIX);
}
public boolean containsChatLanguageModel(String modelId) {
return chatLanguageMap.containsKey(modelId + ModelConst.TEXT_SUFFIX);
}
public EmbeddingModel getEmbeddingModel(String modelId) {
return embeddingModelMap.get(modelId);
}
public boolean containsEmbeddingModel(String modelId) {
return embeddingModelMap.containsKey(modelId);
}
public ImageModel getImageModel(String modelId) {
return imageModelMap.get(modelId);
}
public boolean containsImageModel(String modelId) {
return imageModelMap.containsKey(modelId);
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.provider.build;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.image.ImageModel;
import org.springframework.stereotype.Component;
/**
* @author GB
* @since 2024-08-18 09:57
*/
public interface ModelBuildHandler {
/**
* 判断是不是当前模型
*/
boolean whetherCurrentModel(AigcModel model);
/**
* basic check
*/
boolean basicCheck(AigcModel model);
/**
* streaming chat build
*/
StreamingChatLanguageModel buildStreamingChat(AigcModel model);
/**
* chat build
*/
ChatLanguageModel buildChatLanguageModel(AigcModel model);
/**
* embedding config
*/
EmbeddingModel buildEmbedding(AigcModel model);
/**
* image config
*/
ImageModel buildImage(AigcModel model);
}

View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.provider.build;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.enums.ChatErrorEnum;
import cn.iocoder.yudao.module.langchat.enums.ProviderEnum;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.image.ImageModel;
import dev.langchain4j.model.ollama.OllamaChatModel;
import dev.langchain4j.model.ollama.OllamaEmbeddingModel;
import dev.langchain4j.model.ollama.OllamaStreamingChatModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.time.Duration;
/**
* @author GB
* @since 2024-08-19 10:08
*/
@Slf4j
@Component
public class OllamaModelBuildHandler implements ModelBuildHandler {
@Override
public boolean whetherCurrentModel(AigcModel model) {
return ProviderEnum.OLLAMA.name().equals(model.getProvider());
}
@Override
public boolean basicCheck(AigcModel model) {
if (StringUtils.isBlank(model.getBaseUrl())) {
throw new ServiceException(ChatErrorEnum.BASE_URL_IS_NULL.getErrorCode(),
ChatErrorEnum.BASE_URL_IS_NULL.getErrorDesc(ProviderEnum.OLLAMA.name(), model.getType()));
}
return true;
}
@Override
public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return OllamaStreamingChatModel
.builder()
.baseUrl(model.getBaseUrl())
.modelName(model.getModel())
.temperature(model.getTemperature())
.topP(model.getTopP())
.logRequests(true)
.logResponses(true)
.timeout(Duration.ofMinutes(10))
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("Ollama streaming chat 配置报错", e);
return null;
}
}
@Override
public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return OllamaChatModel
.builder()
.baseUrl(model.getBaseUrl())
.modelName(model.getModel())
.temperature(model.getTemperature())
.topP(model.getTopP())
.logRequests(true)
.logResponses(true)
.timeout(Duration.ofMinutes(10))
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("Ollama chat 配置报错", e);
return null;
}
}
@Override
public EmbeddingModel buildEmbedding(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return OllamaEmbeddingModel
.builder()
.baseUrl(model.getBaseUrl())
.modelName(model.getModel())
.logRequests(true)
.logResponses(true)
.timeout(Duration.ofMinutes(10))
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("Ollama embedding 配置报错", e);
return null;
}
}
@Override
public ImageModel buildImage(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return null;
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("Ollama image 配置报错", e);
return null;
}
}
}

View File

@ -0,0 +1,199 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.provider.build;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.enums.ChatErrorEnum;
import cn.iocoder.yudao.module.langchat.enums.ProviderEnum;
import cn.iocoder.yudao.module.langchat.properties.LangChatProps;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.image.ImageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.model.openai.OpenAiImageModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.Duration;
/**
* @author tycoding
* @since 2024-08-19 10:08
*/
@Slf4j
@Component
@AllArgsConstructor
public class OpenAIModelBuildHandler implements ModelBuildHandler {
private final LangChatProps props;
/**
* 合并处理支持OpenAI接口的模型
*/
@Override
public boolean whetherCurrentModel(AigcModel model) {
String provider = model.getProvider();
return ProviderEnum.OPENAI.name().equals(provider) ||
ProviderEnum.GEMINI.name().equals(provider) ||
ProviderEnum.CLAUDE.name().equals(provider) ||
ProviderEnum.AZURE_OPENAI.name().equals(provider) ||
ProviderEnum.DOUYIN.name().equals(provider) ||
ProviderEnum.YI.name().equals(provider) ||
ProviderEnum.SILICON.name().equals(provider) ||
ProviderEnum.DEEPSEEK.name().equals(provider) ||
ProviderEnum.SPARK.name().equals(provider)
;
}
@Override
public boolean basicCheck(AigcModel model) {
String apiKey = model.getApiKey();
if (StrUtil.isBlank(apiKey)) {
throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(model.getProvider().toUpperCase(), model.getType()));
}
return true;
}
@Override
public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return OpenAiStreamingChatModel
.builder()
.apiKey(model.getApiKey())
.baseUrl(model.getBaseUrl())
.modelName(model.getModel())
.maxTokens(model.getResponseLimit())
.temperature(model.getTemperature())
.logRequests(true)
.logResponses(true)
.topP(model.getTopP())
.timeout(Duration.ofMinutes(10))
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error(model.getProvider() + " Streaming Chat 模型配置报错", e);
return null;
}
}
@Override
public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return OpenAiChatModel
.builder()
.apiKey(model.getApiKey())
.baseUrl(model.getBaseUrl())
.modelName(model.getModel())
.maxTokens(model.getResponseLimit())
.temperature(model.getTemperature())
.logRequests(true)
.logResponses(true)
.topP(model.getTopP())
.timeout(Duration.ofMinutes(10))
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error(model.getProvider() + " Chat 模型配置报错", e);
return null;
}
}
@Override
public EmbeddingModel buildEmbedding(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
OpenAiEmbeddingModel openAiEmbeddingModel = OpenAiEmbeddingModel
.builder()
.apiKey(model.getApiKey())
.baseUrl(model.getBaseUrl())
.modelName(model.getModel())
.dimensions(model.getDimension())
.logRequests(true)
.logResponses(true)
.dimensions(1024)
.timeout(Duration.ofMinutes(10))
.build();
return openAiEmbeddingModel;
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error(model.getProvider() + " Embedding 模型配置报错", e);
return null;
}
}
@Override
public ImageModel buildImage(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return OpenAiImageModel
.builder()
.apiKey(model.getApiKey())
.baseUrl(model.getBaseUrl())
.modelName(model.getModel())
.size(model.getImageSize())
.quality(model.getImageQuality())
.style(model.getImageStyle())
.logRequests(true)
.logResponses(true)
.timeout(Duration.ofMinutes(10))
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error(model.getProvider() + " Image 模型配置报错", e);
return null;
}
}
}

View File

@ -0,0 +1,165 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.provider.build;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.enums.ChatErrorEnum;
import cn.iocoder.yudao.module.langchat.enums.ProviderEnum;
import dev.langchain4j.community.model.qianfan.QianfanChatModel;
import dev.langchain4j.community.model.qianfan.QianfanEmbeddingModel;
import dev.langchain4j.community.model.qianfan.QianfanStreamingChatModel;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.image.ImageModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
/**
* @author GB
* @since 2024-08-19 10:08
*/
@Slf4j
@Component
public class QFanModelBuildHandler implements ModelBuildHandler {
@Override
public boolean whetherCurrentModel(AigcModel model) {
return ProviderEnum.Q_FAN.name().equals(model.getProvider());
}
@Override
public boolean basicCheck(AigcModel model) {
if (StringUtils.isBlank(model.getApiKey())) {
throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(ProviderEnum.Q_FAN.name(), model.getType()));
}
if (StringUtils.isBlank(model.getSecretKey())) {
throw new ServiceException(ChatErrorEnum.SECRET_KEY_IS_NULL.getErrorCode(),
ChatErrorEnum.SECRET_KEY_IS_NULL.getErrorDesc(ProviderEnum.Q_FAN.name(), model.getType()));
}
return true;
}
@Override
public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return QianfanStreamingChatModel
.builder()
.apiKey(model.getApiKey())
.secretKey(model.getSecretKey())
.modelName(model.getModel())
.baseUrl(model.getBaseUrl())
.temperature(model.getTemperature())
.topP(model.getTopP())
.logRequests(true)
.logResponses(true)
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("Qianfan streaming chat 配置报错", e);
return null;
}
}
@Override
public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return QianfanChatModel
.builder()
.apiKey(model.getApiKey())
.secretKey(model.getSecretKey())
.modelName(model.getModel())
.baseUrl(model.getBaseUrl())
.temperature(model.getTemperature())
.topP(model.getTopP())
.logRequests(true)
.logResponses(true)
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("Qianfan chat 配置报错", e);
return null;
}
}
@Override
public EmbeddingModel buildEmbedding(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return QianfanEmbeddingModel
.builder()
.apiKey(model.getApiKey())
.modelName(model.getModel())
.secretKey(model.getSecretKey())
.logRequests(true)
.logResponses(true)
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("Qianfan embedding 配置报错", e);
return null;
}
}
@Override
public ImageModel buildImage(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return null;
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("Qianfan image 配置报错", e);
return null;
}
}
}

View File

@ -0,0 +1,154 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.provider.build;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.enums.ChatErrorEnum;
import cn.iocoder.yudao.module.langchat.enums.ProviderEnum;
import dev.langchain4j.community.model.dashscope.QwenChatModel;
import dev.langchain4j.community.model.dashscope.QwenEmbeddingModel;
import dev.langchain4j.community.model.dashscope.QwenStreamingChatModel;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.image.ImageModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
/**
* @author GB
* @since 2024-08-19 10:08
*/
@Slf4j
@Component
public class QWenModelBuildHandler implements ModelBuildHandler {
@Override
public boolean whetherCurrentModel(AigcModel model) {
return ProviderEnum.Q_WEN.name().equals(model.getProvider());
}
@Override
public boolean basicCheck(AigcModel model) {
if (StringUtils.isBlank(model.getApiKey())) {
throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(ProviderEnum.Q_WEN.name(), model.getType()));
}
return true;
}
@Override
public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
try {
return QwenStreamingChatModel
.builder()
.apiKey(model.getApiKey())
.modelName(model.getModel())
.baseUrl(model.getBaseUrl())
.maxTokens(model.getResponseLimit())
.temperature(Float.parseFloat(model.getTemperature().toString()))
.topP(model.getTopP())
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("qian wen streaming chat 配置报错", e);
return null;
}
}
@Override
public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return QwenChatModel
.builder()
.apiKey(model.getApiKey())
.modelName(model.getModel())
.baseUrl(model.getBaseUrl())
.enableSearch(true)
.maxTokens(model.getResponseLimit())
.temperature(Float.parseFloat(model.getTemperature().toString()))
.topP(model.getTopP())
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("qian wen chat 配置报错", e);
return null;
}
}
@Override
public EmbeddingModel buildEmbedding(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return QwenEmbeddingModel
.builder()
.apiKey(model.getApiKey())
.modelName(model.getModel())
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("qian wen embedding 配置报错", e);
return null;
}
}
@Override
public ImageModel buildImage(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return null;
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("qian wen image 配置报错", e);
return null;
}
}
}

View File

@ -0,0 +1,192 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.provider.build;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.enums.ChatErrorEnum;
import cn.iocoder.yudao.module.langchat.enums.ProviderEnum;
import cn.iocoder.yudao.module.langchat.properties.LangChatProps;
import dev.langchain4j.community.model.zhipu.ZhipuAiChatModel;
import dev.langchain4j.community.model.zhipu.ZhipuAiEmbeddingModel;
import dev.langchain4j.community.model.zhipu.ZhipuAiImageModel;
import dev.langchain4j.community.model.zhipu.ZhipuAiStreamingChatModel;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.image.ImageModel;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.time.Duration;
/**
* @author GB
* @since 2024-08-19
*/
@Slf4j
@Component
@AllArgsConstructor
public class ZhipuModelBuildHandler implements ModelBuildHandler {
private final LangChatProps props;
@Override
public boolean whetherCurrentModel(AigcModel model) {
return ProviderEnum.ZHIPU.name().equals(model.getProvider());
}
@Override
public boolean basicCheck(AigcModel model) {
if (StringUtils.isBlank(model.getApiKey())) {
throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(ProviderEnum.ZHIPU.name(), model.getType()));
}
return true;
}
@Override
public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return ZhipuAiStreamingChatModel
.builder()
.apiKey(model.getApiKey())
.baseUrl(model.getBaseUrl())
.model(model.getModel())
.maxToken(model.getResponseLimit())
.temperature(model.getTemperature())
.topP(model.getTopP())
.logRequests(true)
.logResponses(true)
.callTimeout(Duration.ofMinutes(10))
.connectTimeout(Duration.ofMinutes(10))
.writeTimeout(Duration.ofMinutes(10))
.readTimeout(Duration.ofMinutes(10))
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("zhipu streaming chat 配置报错", e);
return null;
}
}
@Override
public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return ZhipuAiChatModel
.builder()
.apiKey(model.getApiKey())
.baseUrl(model.getBaseUrl())
.model(model.getModel())
.maxToken(model.getResponseLimit())
.temperature(model.getTemperature())
.topP(model.getTopP())
.logRequests(true)
.logResponses(true)
.callTimeout(Duration.ofMinutes(10))
.connectTimeout(Duration.ofMinutes(10))
.writeTimeout(Duration.ofMinutes(10))
.readTimeout(Duration.ofMinutes(10))
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("zhipu chat 配置报错", e);
return null;
}
}
@Override
public EmbeddingModel buildEmbedding(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return ZhipuAiEmbeddingModel
.builder()
.apiKey(model.getApiKey())
.model(model.getModel())
.baseUrl(model.getBaseUrl())
.logRequests(true)
.logResponses(true)
.callTimeout(Duration.ofMinutes(10))
.connectTimeout(Duration.ofMinutes(10))
.writeTimeout(Duration.ofMinutes(10))
.readTimeout(Duration.ofMinutes(10))
.dimensions(1024)
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("zhipu embedding 配置报错", e);
return null;
}
}
@Override
public ImageModel buildImage(AigcModel model) {
try {
if (!whetherCurrentModel(model)) {
return null;
}
if (!basicCheck(model)) {
return null;
}
return ZhipuAiImageModel
.builder()
.apiKey(model.getApiKey())
.model(model.getModel())
.baseUrl(model.getBaseUrl())
.logRequests(true)
.logResponses(true)
.callTimeout(Duration.ofMinutes(10))
.connectTimeout(Duration.ofMinutes(10))
.writeTimeout(Duration.ofMinutes(10))
.readTimeout(Duration.ofMinutes(10))
.build();
} catch (ServiceException e) {
log.error(e.getMessage());
throw e;
} catch (Exception e) {
log.error("zhipu image 配置报错", e);
return null;
}
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.service.aigc;
import cn.iocoder.yudao.module.langchat.entity.AigcAppApi;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author tycoding
* @since 2024/7/26
*/
public interface AigcAppApiService extends IService<AigcAppApi> {
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.service.aigc;
import cn.iocoder.yudao.module.langchat.entity.AigcApp;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @author tycoding
* @since 2024/7/26
*/
public interface AigcAppService extends IService<AigcApp> {
List<AigcApp> list(AigcApp data);
AigcApp getById(String id);
}

Some files were not shown because too many files have changed in this diff Show More