├── .gitignore ├── LICENSE ├── README.md └── llm_chat_java_hello ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── HELP.md ├── http └── del.http ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── github │ │ └── xiaoymin │ │ └── llm │ │ ├── LlmChatJavaHelloApplication.java │ │ ├── command │ │ ├── AddTxtCommand.java │ │ └── ChatCommand.java │ │ ├── compoents │ │ ├── LoadStartup.java │ │ ├── TxtChunk.java │ │ └── VectorStorage.java │ │ ├── config │ │ └── LLmProperties.java │ │ ├── domain │ │ ├── llm │ │ │ ├── ChunkResult.java │ │ │ ├── EmbeddingResult.java │ │ │ ├── ZhipuChatCompletion.java │ │ │ └── ZhipuResult.java │ │ └── store │ │ │ └── ElasticVectorData.java │ │ ├── listener │ │ └── ConsoleEventSourceListener.java │ │ ├── llm │ │ └── ZhipuAI.java │ │ └── utils │ │ └── LLMUtils.java └── resources │ ├── application.yml │ ├── data │ ├── 001.txt │ └── 002.txt │ └── logback-local.xml └── test └── java └── com └── github └── xiaoymin └── llm └── LlmChatJavaHelloApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | replay_pid* 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LlmInAction 2 | 3 | 大模型LLM,RAG实战,公众号“八一菜刀”同步更新 4 | 5 | ![](https://www.xiaominfo.com/images/website/mp/qrcode_mini.jpg) 6 | 7 | 8 | ## 文章列表 9 | 10 | - [开篇-续写AI技术新篇,融汇工程化实践](https://mp.weixin.qq.com/s/rFclAZiPOrTTtpt4gvY_tg) 11 | - [实战0-1,Java开发者也能看懂的大模型应用开发实践](https://mp.weixin.qq.com/s/UeMSA35L5oCSLAk6RxSMgw) 12 | > 视频:[https://www.bilibili.com/video/BV1Uw411A7qD](https://www.bilibili.com/video/BV1Uw411A7qD/?spm_id_from=333.999.0.0&vd_source=ef34098d916a578698508a43063099ac) 13 | > 14 | > 代码:[llm_chat_java_hello](llm_chat_java_hello) 15 | - [用好大模型?这5种实用的Prompt框架你一定要看看!](https://www.xiaominfo.com/posts/use-prompt-framework/) 16 | - [TorchV的RAG实践分享(一)——RAG的定位、技术选型和RAG技术文章目录](https://mp.weixin.qq.com/s/4D1XxrYcBS5UO6wazPWihg) 17 | - [基于Apple MLX框架的M1设备上大模型微调实践](https://www.xiaominfo.com/2023/12/17/apple-mlx-lora-action/) 18 | - [TorchV的RAG实践分享(二):基于ElasticSearch的混合检索实战&原理分析](https://mp.weixin.qq.com/s/EBaGXFOnNHmF_rj_NLf_Ww) 19 | - [TorchV的RAG实践分享(三):解析llama_index的数据存储结构和召回策略过程](https://www.xiaominfo.com/2024/01/14/torchv-rag-3/) 20 | - [TorchV的RAG实践分享(四)——开放试用](https://www.luxiangdong.com/2024/01/25/lanuch-1/?utm_source=xiaoymin) 21 | - [创业:大模型RAG系统三个月的开发心得和思考](https://www.xiaominfo.com/2024/04/01/torchv-summary-01/) 22 | - [我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈](https://www.xiaominfo.com/2024/07/03/torchv-think/) 23 | - [RAG工程实践拦路虎之一:PDF格式解析杂谈](https://www.xiaominfo.com/2024/07/08/torchv-pdf-01/) 24 | - [记录QWen2-72B-Instruct模型安装部署过程](https://mp.weixin.qq.com/s/7MzqwEXHKwZdnZ0Ud5Oejw) 25 | - [非结构化数据解析 &GenAI的应用探索和实践(文字稿)](https://mp.weixin.qq.com/s/1nV7XTGSQ6C9sW-122teWg) 26 | - [AIGC时代的淘金者,TorchV这一年的心路历程](https://mp.weixin.qq.com/s/AwdEn8it4VDyz0JWEGYw9Q) 27 | -------------------------------------------------------------------------------- /llm_chat_java_hello/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /llm_chat_java_hello/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoymin/LlmInAction/72e7590eb8701355790f0609351eab108c2c93d4/llm_chat_java_hello/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /llm_chat_java_hello/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar 19 | -------------------------------------------------------------------------------- /llm_chat_java_hello/HELP.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ### Reference Documentation 4 | 5 | For further reference, please consider the following sections: 6 | 7 | * [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) 8 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.7.16/maven-plugin/reference/html/) 9 | * [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.7.16/maven-plugin/reference/html/#build-image) 10 | * [Spring Shell](https://spring.io/projects/spring-shell) 11 | 12 | -------------------------------------------------------------------------------- /llm_chat_java_hello/http/del.http: -------------------------------------------------------------------------------- 1 | DELETE http://k8s.local.cn:30134/llm_action_rag_20231011 -------------------------------------------------------------------------------- /llm_chat_java_hello/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | -------------------------------------------------------------------------------- /llm_chat_java_hello/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /llm_chat_java_hello/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.16 9 | 10 | 11 | 12 | 13 | 14 | com.github.xiaoymin 15 | llm_chat_java_hello 16 | 1.0.0 17 | llm_chat_java_hello 18 | llm_chat_java_hello 19 | 20 | 1.8 21 | 2.1.13 22 | 23 | 24 | 25 | org.springframework.shell 26 | spring-shell-starter 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-data-elasticsearch 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter 35 | 36 | 37 | org.projectlombok 38 | lombok 39 | 40 | 41 | io.milvus 42 | milvus-sdk-java 43 | 2.2.7 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-test 48 | test 49 | 50 | 51 | cn.hutool 52 | hutool-all 53 | 5.8.21 54 | 55 | 56 | com.squareup.okhttp3 57 | okhttp 58 | 59 | 60 | com.squareup.okhttp3 61 | okhttp-sse 62 | 63 | 64 | 65 | 66 | 67 | org.springframework.shell 68 | spring-shell-dependencies 69 | ${spring-shell.version} 70 | pom 71 | import 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.springframework.boot 80 | spring-boot-maven-plugin 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/LlmChatJavaHelloApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | 7 | @SpringBootApplication 8 | public class LlmChatJavaHelloApplication { 9 | 10 | public static void main(String[] args) { 11 | SpringApplication.run(LlmChatJavaHelloApplication.class, args); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/command/AddTxtCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.command; 2 | 3 | import com.github.xiaoymin.llm.compoents.TxtChunk; 4 | import com.github.xiaoymin.llm.compoents.VectorStorage; 5 | import com.github.xiaoymin.llm.domain.llm.ChunkResult; 6 | import com.github.xiaoymin.llm.domain.llm.EmbeddingResult; 7 | import com.github.xiaoymin.llm.llm.ZhipuAI; 8 | import lombok.AllArgsConstructor; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.shell.standard.ShellComponent; 11 | import org.springframework.shell.standard.ShellMethod; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * @author xiaoymin@foxmail.com 17 | * 2023/10/06 12:50 18 | * @since llm_chat_java_hello 19 | */ 20 | @Slf4j 21 | @AllArgsConstructor 22 | @ShellComponent 23 | public class AddTxtCommand { 24 | 25 | final TxtChunk txtChunk; 26 | final VectorStorage vectorStorage; 27 | final ZhipuAI zhipuAI; 28 | 29 | @ShellMethod(value = "add local txt data") 30 | public String add(String doc){ 31 | log.info("start add doc."); 32 | // 加载 33 | List chunkResults= txtChunk.chunk(doc); 34 | // embedding 35 | List embeddingResults=zhipuAI.embedding(chunkResults); 36 | // store vector 37 | String collection= vectorStorage.getCollectionName(); 38 | vectorStorage.store(collection,embeddingResults); 39 | log.info("finished"); 40 | return "finished docId:{}"+doc; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/command/ChatCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.command; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.github.xiaoymin.llm.compoents.VectorStorage; 5 | import com.github.xiaoymin.llm.llm.ZhipuAI; 6 | import com.github.xiaoymin.llm.utils.LLMUtils; 7 | import lombok.AllArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.shell.standard.ShellComponent; 10 | import org.springframework.shell.standard.ShellMethod; 11 | 12 | /** 13 | * @author xiaoymin@foxmail.com 14 | * 2023/10/06 13:04 15 | * @since llm_chat_java_hello 16 | */ 17 | @AllArgsConstructor 18 | @Slf4j 19 | @ShellComponent 20 | public class ChatCommand { 21 | 22 | final VectorStorage vectorStorage; 23 | final ZhipuAI zhipuAI; 24 | 25 | @ShellMethod(value = "chat with files") 26 | public String chat(String question){ 27 | if (StrUtil.isBlank(question)){ 28 | return "You must send a question"; 29 | } 30 | //句子转向量 31 | double[] vector=zhipuAI.sentence(question); 32 | // 向量召回 33 | String collection= vectorStorage.getCollectionName(); 34 | String vectorData=vectorStorage.retrieval(collection,vector); 35 | if (StrUtil.isBlank(vectorData)){ 36 | return "No Answer!"; 37 | } 38 | // 构建Prompt 39 | String prompt= LLMUtils.buildPrompt(question,vectorData); 40 | zhipuAI.chat(prompt); 41 | // 大模型对话 42 | //return "you question:{}"+question+"finished."; 43 | return StrUtil.EMPTY; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/compoents/LoadStartup.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.compoents; 2 | 3 | import cn.hutool.core.date.DateUtil; 4 | import lombok.AllArgsConstructor; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.InitializingBean; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.time.Instant; 10 | import java.util.Date; 11 | 12 | /** 13 | * @author xiaoymin@foxmail.com 14 | * 2023/10/06 13:26 15 | * @since llm_chat_java_hello 16 | */ 17 | @AllArgsConstructor 18 | @Component 19 | @Slf4j 20 | public class LoadStartup implements InitializingBean { 21 | 22 | final VectorStorage vectorStorage; 23 | 24 | 25 | public void startup(){ 26 | log.info("init vector collection"); 27 | String collectionName= vectorStorage.getCollectionName(); 28 | log.info("init collection:{}",collectionName); 29 | //向量维度固定1024,根据选择的向量Embedding模型的维度确定最终维度 30 | // 这里因为选择智谱的Embedding模型,维度是1024,所以固定为该值 31 | vectorStorage.initCollection(collectionName,1024); 32 | log.info("init collection success."); 33 | } 34 | 35 | @Override 36 | public void afterPropertiesSet() throws Exception { 37 | log.info("start load....."); 38 | this.startup(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/compoents/TxtChunk.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.compoents; 2 | 3 | import cn.hutool.core.io.IoUtil; 4 | import cn.hutool.core.util.ArrayUtil; 5 | import cn.hutool.core.util.StrUtil; 6 | import com.github.xiaoymin.llm.domain.llm.ChunkResult; 7 | import lombok.AllArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.core.io.ClassPathResource; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.io.IOException; 13 | import java.nio.charset.StandardCharsets; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.concurrent.atomic.AtomicInteger; 17 | 18 | /** 19 | * @author xiaoymin@foxmail.com 20 | * 2023/10/06 12:48 21 | * @since llm_chat_java_hello 22 | */ 23 | @Slf4j 24 | @Component 25 | @AllArgsConstructor 26 | public class TxtChunk { 27 | 28 | public List chunk(String docId){ 29 | String path="data/"+docId+".txt"; 30 | log.info("start chunk---> docId:{},path:{}",docId,path); 31 | ClassPathResource classPathResource=new ClassPathResource(path); 32 | try { 33 | String txt=IoUtil.read(classPathResource.getInputStream(), StandardCharsets.UTF_8); 34 | //按固定字数分割,256 35 | String[] lines=StrUtil.split(txt,256); 36 | log.info("chunk size:{}", ArrayUtil.length(lines)); 37 | List results=new ArrayList<>(); 38 | AtomicInteger atomicInteger=new AtomicInteger(0); 39 | for (String line:lines){ 40 | ChunkResult chunkResult=new ChunkResult(); 41 | chunkResult.setDocId(docId); 42 | chunkResult.setContent(line); 43 | chunkResult.setChunkId(atomicInteger.incrementAndGet()); 44 | results.add(chunkResult); 45 | } 46 | return results; 47 | } catch (IOException e) { 48 | log.error(e.getMessage()); 49 | } 50 | return new ArrayList<>(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/compoents/VectorStorage.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.compoents; 2 | 3 | import cn.hutool.core.collection.CollectionUtil; 4 | import cn.hutool.core.date.DateUtil; 5 | import cn.hutool.core.map.MapUtil; 6 | import com.github.xiaoymin.llm.domain.llm.EmbeddingResult; 7 | import com.github.xiaoymin.llm.domain.store.ElasticVectorData; 8 | import lombok.AllArgsConstructor; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.elasticsearch.index.query.QueryBuilders; 11 | import org.elasticsearch.index.query.functionscore.ScriptScoreQueryBuilder; 12 | import org.elasticsearch.script.Script; 13 | import org.elasticsearch.script.ScriptType; 14 | import org.springframework.data.domain.Pageable; 15 | import org.springframework.data.elasticsearch.core.*; 16 | import org.springframework.data.elasticsearch.core.document.Document; 17 | import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; 18 | import org.springframework.data.elasticsearch.core.query.IndexQuery; 19 | import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder; 20 | import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; 21 | import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; 22 | import org.springframework.stereotype.Component; 23 | 24 | import java.time.Instant; 25 | import java.util.*; 26 | 27 | /** 28 | * @author xiaoymin@foxmail.com 29 | * 2023/10/06 12:39 30 | * @since llm_chat_java_hello 31 | */ 32 | @Slf4j 33 | @Component 34 | @AllArgsConstructor 35 | public class VectorStorage { 36 | 37 | final ElasticsearchRestTemplate elasticsearchRestTemplate; 38 | 39 | public String getCollectionName(){ 40 | //演示效果使用,固定前缀+日期 41 | return "llm_action_rag_"+ DateUtil.format(Date.from(Instant.now()),"yyyyMMdd"); 42 | } 43 | 44 | /** 45 | * 初始化向量数据库index 46 | * @param collectionName 名称 47 | * @param dim 维度 48 | */ 49 | public boolean initCollection(String collectionName,int dim){ 50 | log.info("collection:{}", collectionName); 51 | // 查看向量索引是否存在,此方法为固定默认索引字段 52 | IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(IndexCoordinates.of(collectionName)); 53 | if (!indexOperations.exists()) { 54 | // 索引不存在,直接创建 55 | log.info("index not exists,create"); 56 | //创建es的结构,简化处理 57 | Document document = Document.from(this.elasticMapping(dim)); 58 | // 创建 59 | indexOperations.create(new HashMap<>(), document); 60 | return true; 61 | } 62 | return true; 63 | } 64 | 65 | public void store(String collectionName,List embeddingResults){ 66 | //保存向量 67 | log.info("save vector,collection:{},size:{}",collectionName, CollectionUtil.size(embeddingResults)); 68 | 69 | List results = new ArrayList<>(); 70 | for (EmbeddingResult embeddingResult : embeddingResults) { 71 | ElasticVectorData ele = new ElasticVectorData(); 72 | ele.setVector(embeddingResult.getEmbedding()); 73 | ele.setChunkId(embeddingResult.getRequestId()); 74 | ele.setContent(embeddingResult.getPrompt()); 75 | results.add(new IndexQueryBuilder().withObject(ele).build()); 76 | } 77 | // 构建数据包 78 | List bulkedResult = elasticsearchRestTemplate.bulkIndex(results, IndexCoordinates.of(collectionName)); 79 | int size = CollectionUtil.size(bulkedResult); 80 | log.info("保存向量成功-size:{}", size); 81 | } 82 | 83 | public String retrieval(String collectionName,double[] vector){ 84 | // Build the script,查询向量 85 | Map params = new HashMap<>(); 86 | params.put("query_vector", vector); 87 | // 计算cos值+1,避免出现负数的情况,得到结果后,实际score值在减1再计算 88 | Script script = new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, "cosineSimilarity(params.query_vector, 'vector')+1", params); 89 | ScriptScoreQueryBuilder scriptScoreQueryBuilder = new ScriptScoreQueryBuilder(QueryBuilders.boolQuery(), script); 90 | // 构建请求 91 | NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder() 92 | .withQuery(scriptScoreQueryBuilder) 93 | .withPageable(Pageable.ofSize(3)).build(); 94 | SearchHits dataSearchHits = this.elasticsearchRestTemplate.search(nativeSearchQuery, ElasticVectorData.class, IndexCoordinates.of(collectionName)); 95 | //log.info("检索成功,size:{}", dataSearchHits.getTotalHits()); 96 | List> data = dataSearchHits.getSearchHits(); 97 | List results = new LinkedList<>(); 98 | for (SearchHit ele : data) { 99 | results.add(ele.getContent().getContent()); 100 | } 101 | return CollectionUtil.join(results,""); 102 | } 103 | 104 | private Map elasticMapping(int dims) { 105 | Map properties = new HashMap<>(); 106 | properties.put("_class", MapUtil.builder("type", "keyword").put("doc_values", "false").put("index", "false").build()); 107 | properties.put("chunkId", MapUtil.builder("type", "keyword").build()); 108 | properties.put("content", MapUtil.builder("type", "keyword").build()); 109 | properties.put("docId", MapUtil.builder("type", "keyword").build()); 110 | // 向量 111 | properties.put("vector", MapUtil.builder("type", "dense_vector").put("dims", Objects.toString(dims)).build()); 112 | Map root = new HashMap<>(); 113 | root.put("properties", properties); 114 | return root; 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/config/LLmProperties.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | * @author xiaoymin@foxmail.com 9 | * 2023/10/06 13:38 10 | * @since llm_chat_java_hello 11 | */ 12 | @Data 13 | @Component 14 | @ConfigurationProperties(prefix = "llm") 15 | public class LLmProperties { 16 | /** 17 | * 智谱AI的开发密钥,https://open.bigmodel.cn/dev/api#text_embedding 18 | * 注册智谱AI开放平台获取 19 | */ 20 | private String zpKey; 21 | } 22 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/domain/llm/ChunkResult.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.domain.llm; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author xiaoymin@foxmail.com 7 | * 2023/10/06 14:33 8 | * @since llm_chat_java_hello 9 | */ 10 | @Data 11 | public class ChunkResult { 12 | private String docId; 13 | private int chunkId; 14 | private String content; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/domain/llm/EmbeddingResult.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.domain.llm; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | 7 | /** 8 | * @author xiaoymin@foxmail.com 9 | * 2023/10/06 13:36 10 | * @since llm_chat_java_hello 11 | */ 12 | @Getter 13 | @Setter 14 | public class EmbeddingResult { 15 | 16 | /** 17 | * 原始文本内容 18 | */ 19 | private String prompt; 20 | /** 21 | * embedding的处理结果,返回向量化表征的数组,数组长度为1024 22 | */ 23 | private double[] embedding; 24 | /** 25 | * 用户在客户端请求时提交的任务编号或者平台生成的任务编号 26 | */ 27 | private String requestId; 28 | /** 29 | * 智谱AI开放平台生成的任务订单号,调用请求结果接口时请使用此订单号 30 | */ 31 | private String taskId; 32 | /** 33 | * 处理状态,PROCESSING(处理中),SUCCESS(成功),FAIL(失败) 34 | * 注:处理中状态需通过查询获取结果 35 | */ 36 | private String taskStatus; 37 | } 38 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/domain/llm/ZhipuChatCompletion.java: -------------------------------------------------------------------------------- 1 | /* 2 | * THIS FILE IS PART OF Zhejiang LiShi Technology CO.,LTD. 3 | * Copyright (c) 2019-2023 Zhejiang LiShi Technology CO.,LTD. 4 | * It is forbidden to distribute or copy the code under this software without the consent of the Zhejiang LiShi Technology 5 | * 6 | * https://www.lishiots.com/ 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | 16 | package com.github.xiaoymin.llm.domain.llm; 17 | 18 | import lombok.Data; 19 | 20 | import java.util.LinkedList; 21 | import java.util.List; 22 | 23 | /** 24 | * @Classname ZpChatglmReq 25 | * @Description TODO 26 | * @Date 2023/7/13 15:21 27 | * @Author jerrylin 28 | */ 29 | @Data 30 | public class ZhipuChatCompletion { 31 | 32 | private List prompt=new LinkedList<>(); 33 | private float temperature; 34 | private float top_p; 35 | 36 | private String request_id; 37 | /** 38 | * SSE接口调用时,用于控制每次返回内容方式是增量还是全量,不提供此参数时默认为增量返回 39 | * - true 为增量返回 40 | * - false 为全量返回 41 | */ 42 | private boolean incremental = true; 43 | 44 | public void addPrompt(String content){ 45 | this.prompt.add(Prompt.buildOne(content)); 46 | } 47 | 48 | @Data 49 | public static class Prompt { 50 | 51 | private String role = "user"; 52 | private String content; 53 | 54 | public static Prompt buildOne(String content){ 55 | Prompt prompt1=new Prompt(); 56 | prompt1.setContent(content); 57 | return prompt1; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/domain/llm/ZhipuResult.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.domain.llm; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author xiaoymin@foxmail.com 7 | * 2023/10/06 14:11 8 | * @since llm_chat_java_hello 9 | */ 10 | @Data 11 | public class ZhipuResult { 12 | private int code; 13 | private String msg; 14 | private boolean success; 15 | private EmbeddingResult data; 16 | } 17 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/domain/store/ElasticVectorData.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.domain.store; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author xiaoymin@foxmail.com 7 | * 2023/10/06 14:40 8 | * @since llm_chat_java_hello 9 | */ 10 | @Data 11 | public class ElasticVectorData { 12 | 13 | private String chunkId; 14 | private String content; 15 | private String docId; 16 | private double[] vector; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/listener/ConsoleEventSourceListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * THIS FILE IS PART OF Zhejiang LiShi Technology CO.,LTD. 3 | * Copyright (c) 2019-2023 Zhejiang LiShi Technology CO.,LTD. 4 | * It is forbidden to distribute or copy the code under this software without the consent of the Zhejiang LiShi Technology 5 | * 6 | * https://www.lishiots.com/ 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | 16 | package com.github.xiaoymin.llm.listener; 17 | 18 | import cn.hutool.core.util.StrUtil; 19 | import lombok.AllArgsConstructor; 20 | import lombok.SneakyThrows; 21 | import lombok.extern.slf4j.Slf4j; 22 | import okhttp3.Response; 23 | import okhttp3.ResponseBody; 24 | import okhttp3.sse.EventSource; 25 | import okhttp3.sse.EventSourceListener; 26 | 27 | import java.util.Objects; 28 | import java.util.concurrent.CountDownLatch; 29 | 30 | /** 31 | * 描述: sse event listener 32 | */ 33 | @AllArgsConstructor 34 | @Slf4j 35 | public class ConsoleEventSourceListener extends EventSourceListener { 36 | final CountDownLatch countDownLatch; 37 | 38 | @Override 39 | public void onOpen(EventSource eventSource, Response response) { 40 | //log.info("LLM建立sse连接..."); 41 | } 42 | 43 | @Override 44 | public void onEvent(EventSource eventSource, String id, String type, String data) { 45 | // log.info("LLM返回,id:{},type:{},数据:{}", id, type, data); 46 | System.out.print(data); 47 | if (data.contains("\n")){ 48 | System.out.println("换行了"); 49 | } 50 | if (StrUtil.equalsIgnoreCase(type,"finish")){ 51 | //end 52 | System.out.println(StrUtil.EMPTY); 53 | } 54 | } 55 | 56 | @Override 57 | public void onClosed(EventSource eventSource) { 58 | // log.info("LLM关闭sse连接..."); 59 | countDownLatch.countDown(); 60 | } 61 | 62 | @SneakyThrows 63 | @Override 64 | public void onFailure( EventSource eventSource, Throwable t, Response response) { 65 | countDownLatch.countDown(); 66 | if (Objects.isNull(response)) { 67 | log.error("LLM sse连接异常", t); 68 | eventSource.cancel(); 69 | return; 70 | } 71 | ResponseBody body = response.body(); 72 | if (Objects.nonNull(body)) { 73 | log.error("error1-----------------"); 74 | log.error("LLM sse连接异常data:{}", body.string(), t); 75 | } else { 76 | log.error("error2-----------------"); 77 | log.error("LLM sse连接异常data:{}", response, t); 78 | } 79 | eventSource.cancel(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/llm/ZhipuAI.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.llm; 2 | 3 | import cn.hutool.core.collection.CollectionUtil; 4 | import cn.hutool.core.util.RandomUtil; 5 | import cn.hutool.core.util.StrUtil; 6 | import cn.hutool.http.ContentType; 7 | import cn.hutool.http.Header; 8 | import com.fasterxml.jackson.core.JsonProcessingException; 9 | import com.fasterxml.jackson.databind.ObjectMapper; 10 | import com.github.xiaoymin.llm.config.LLmProperties; 11 | import com.github.xiaoymin.llm.domain.llm.ChunkResult; 12 | import com.github.xiaoymin.llm.domain.llm.EmbeddingResult; 13 | import com.github.xiaoymin.llm.domain.llm.ZhipuChatCompletion; 14 | import com.github.xiaoymin.llm.domain.llm.ZhipuResult; 15 | import com.github.xiaoymin.llm.listener.ConsoleEventSourceListener; 16 | import com.github.xiaoymin.llm.utils.LLMUtils; 17 | import com.google.gson.Gson; 18 | import lombok.AllArgsConstructor; 19 | import lombok.extern.slf4j.Slf4j; 20 | import okhttp3.*; 21 | import okhttp3.sse.EventSource; 22 | import okhttp3.sse.EventSources; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.springframework.stereotype.Component; 25 | 26 | import java.io.IOException; 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | import java.util.Objects; 30 | import java.util.concurrent.CountDownLatch; 31 | import java.util.concurrent.TimeUnit; 32 | 33 | /** 34 | * @author xiaoymin@foxmail.com 35 | * 2023/10/06 13:35 36 | * @since llm_chat_java_hello 37 | */ 38 | @Component 39 | @AllArgsConstructor 40 | @Slf4j 41 | public class ZhipuAI { 42 | 43 | final LLmProperties lLmProperties; 44 | 45 | final Gson GSON=new Gson(); 46 | 47 | public String getApiKey(){ 48 | String apiKey= lLmProperties.getZpKey(); 49 | if (StrUtil.isBlank(apiKey)){ 50 | apiKey=System.getenv("CHAT2CMD_KEY_ZP"); 51 | } 52 | return apiKey; 53 | } 54 | 55 | public void chat(String prompt){ 56 | try { 57 | OkHttpClient.Builder builder = new OkHttpClient.Builder() 58 | .connectTimeout(20000, TimeUnit.MILLISECONDS) 59 | .readTimeout(20000, TimeUnit.MILLISECONDS) 60 | .writeTimeout(20000, TimeUnit.MILLISECONDS) 61 | .addInterceptor(new ZhipuHeaderInterceptor(this.getApiKey())); 62 | OkHttpClient okHttpClient = builder.build(); 63 | 64 | ZhipuChatCompletion zhipuChatCompletion=new ZhipuChatCompletion(); 65 | zhipuChatCompletion.addPrompt(prompt); 66 | // 采样温度,控制输出的随机性,必须为正数 67 | // 值越大,会使输出更随机,更具创造性;值越小,输出会更加稳定或确定 68 | zhipuChatCompletion.setTemperature(0.7f); 69 | zhipuChatCompletion.setTop_p(0.7f); 70 | 71 | EventSource.Factory factory = EventSources.createFactory(okHttpClient); 72 | ObjectMapper mapper = new ObjectMapper(); 73 | String requestBody = mapper.writeValueAsString(zhipuChatCompletion); 74 | Request request = new Request.Builder() 75 | .url("https://open.bigmodel.cn/api/paas/v3/model-api/chatglm_std/sse-invoke") 76 | .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody)) 77 | .build(); 78 | CountDownLatch countDownLatch=new CountDownLatch(1); 79 | // 创建事件,控制台输出 80 | EventSource eventSource = factory.newEventSource(request, new ConsoleEventSourceListener(countDownLatch)); 81 | countDownLatch.await(); 82 | 83 | } catch (Exception e) { 84 | log.error("llm-chat异常:{}", e.getMessage()); 85 | } 86 | } 87 | 88 | /** 89 | * 获取句子的向量 90 | * @param sentence 句子 91 | * @return 向量 92 | */ 93 | public double[] sentence(String sentence){ 94 | ChunkResult chunkResult=new ChunkResult(); 95 | chunkResult.setContent(sentence); 96 | chunkResult.setChunkId(RandomUtil.randomInt()); 97 | EmbeddingResult embeddingResult=this.embedding(chunkResult); 98 | return embeddingResult.getEmbedding(); 99 | } 100 | 101 | /** 102 | * 批量 103 | * @param chunkResults 批量文本 104 | * @return 向量 105 | */ 106 | public List embedding(List chunkResults){ 107 | log.info("start embedding,size:{}",CollectionUtil.size(chunkResults)); 108 | if (CollectionUtil.isEmpty(chunkResults)){ 109 | return new ArrayList<>(); 110 | } 111 | List embeddingResults=new ArrayList<>(); 112 | for (ChunkResult chunkResult:chunkResults){ 113 | embeddingResults.add(this.embedding(chunkResult)); 114 | } 115 | return embeddingResults; 116 | } 117 | 118 | public EmbeddingResult embedding(ChunkResult chunkResult){ 119 | String apiKey= this.getApiKey(); 120 | //log.info("zp-key:{}",apiKey); 121 | OkHttpClient.Builder builder = new OkHttpClient.Builder() 122 | .connectTimeout(20000, TimeUnit.MILLISECONDS) 123 | .readTimeout(20000, TimeUnit.MILLISECONDS) 124 | .writeTimeout(20000, TimeUnit.MILLISECONDS) 125 | .addInterceptor(new ZhipuHeaderInterceptor(apiKey)); 126 | OkHttpClient okHttpClient = builder.build(); 127 | EmbeddingResult embedRequest=new EmbeddingResult(); 128 | embedRequest.setPrompt(chunkResult.getContent()); 129 | embedRequest.setRequestId(Objects.toString(chunkResult.getChunkId())); 130 | // 智谱embedding 131 | Request request = new Request.Builder() 132 | .url("https://open.bigmodel.cn/api/paas/v3/model-api/text_embedding/invoke") 133 | .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), GSON.toJson(embedRequest))) 134 | .build(); 135 | try { 136 | Response response= okHttpClient.newCall(request).execute(); 137 | String result=response.body().string(); 138 | ZhipuResult zhipuResult= GSON.fromJson(result, ZhipuResult.class); 139 | EmbeddingResult ret= zhipuResult.getData(); 140 | ret.setPrompt(embedRequest.getPrompt()); 141 | ret.setRequestId(embedRequest.getRequestId()); 142 | return ret; 143 | } catch (IOException e) { 144 | throw new RuntimeException(e); 145 | } 146 | 147 | } 148 | 149 | @AllArgsConstructor 150 | private static class ZhipuHeaderInterceptor implements Interceptor { 151 | 152 | final String apiKey; 153 | 154 | @NotNull 155 | @Override 156 | public Response intercept(@NotNull Chain chain) throws IOException { 157 | Request original = chain.request(); 158 | String authorization=LLMUtils.gen(apiKey,60); 159 | //log.info("authorization:{}",authorization); 160 | Request request = original.newBuilder() 161 | .header(Header.AUTHORIZATION.getValue(), authorization) 162 | .header(Header.CONTENT_TYPE.getValue(), ContentType.JSON.getValue()) 163 | .method(original.method(), original.body()) 164 | .build(); 165 | return chain.proceed(request); 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/java/com/github/xiaoymin/llm/utils/LLMUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm.utils; 2 | 3 | import cn.hutool.jwt.JWTUtil; 4 | 5 | import java.nio.charset.StandardCharsets; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * @author xiaoymin@foxmail.com 11 | * 2023/10/06 13:42 12 | * @since llm_chat_java_hello 13 | */ 14 | public class LLMUtils { 15 | 16 | 17 | public static String buildPrompt(String question,String context){ 18 | return "请利用如下上下文的信息回答问题:" + "\n" + 19 | question + "\n" + 20 | "上下文信息如下:" + "\n" + 21 | context + "\n" + 22 | "如果上下文信息中没有帮助,则不允许胡乱回答!"; 23 | } 24 | 25 | public static String gen(String apiKey, int expSeconds) { 26 | String[] parts = apiKey.split("\\."); 27 | if (parts.length != 2) { 28 | throw new RuntimeException("智谱invalid key"); 29 | } 30 | 31 | String id = parts[0]; 32 | String secret = parts[1]; 33 | // 4143f0fa36f0aaf39a63be11a3623c63.eMhlXYJLdUGQO0xH 34 | Map payload = new HashMap<>(); 35 | long currentTimeMillis = System.currentTimeMillis(); 36 | long expirationTimeMillis = currentTimeMillis + (60 * 1000); 37 | payload.put("api_key", id); 38 | payload.put("exp", expirationTimeMillis); 39 | payload.put("timestamp", currentTimeMillis); 40 | Map headerMap = new HashMap<>(); 41 | headerMap.put("alg", "HS256"); 42 | headerMap.put("sign_type", "SIGN"); 43 | return JWTUtil.createToken(headerMap,payload,secret.getBytes(StandardCharsets.UTF_8)); 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: llm-rag-001 4 | elasticsearch: 5 | uris: http://k8s.local.cn:30134 6 | shell: 7 | history: 8 | name: test 9 | theme: 10 | name: aaa 11 | logging: 12 | config: classpath:logback-local.xml 13 | # 自定义配置 14 | llm: 15 | # 智谱AI开放密钥,开发者替换为自己的 16 | zp-key: 17 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/resources/data/001.txt: -------------------------------------------------------------------------------- 1 | 直播吧10月12日讯 NBA季前赛,76人主场迎战凯尔特人,两队首场季前赛交锋在波士顿进行,76人登帝组合缺阵,凯尔特人新援波津、霍勒迪等齐亮相,最终凯尔特人8分优势战胜76人,本场比赛登帝继续缺阵,绿军双探花也不打。 2 | 3 | 波尔津吉斯上来就里突外投连续取分,凯尔特人打出不错开局,但马克西能给出回应,随后凯尔特人接连外线发炮再次建立领先,铁林上来里突外投连砍8分一度率队反超比分,但绿军又接连三分稳住局势,次节乌布雷手感火热外线连续命中,双方展开三分对飚,比分交替领先,波津接连造杀伤,淮塔里突外投连砍6分,绿军一波11-2小高潮半场领先8分。下半场,凯尔特人撤下先发,马克西带领76人连续打成转换一度追平比分,好在绿军一波8-0紧急止血,普理查德和豪泽外线威胁大,绿军三节领先到15分,末节76人接连三分追分,但绿军靠科塔内线扣篮给出回应,随后绿军越打越好一度拉开20分以上领先,最终绿军112-101再胜76人。 4 | 5 | 6 | 7 | 双方数据 8 | 9 | 凯尔特人:普理查德17分3助、豪泽15分4板3助、波尔津吉斯11分5板、霍勒迪11分2板2助、怀特11分3板4助3帽、霍福德9分4板、科塔10分3板2助、米哈伊柳克15分6板2助 10 | 11 | 76人:马克西17分3板3助2断、乌布雷18分3板2帽、里德10分7板5助2断、梅尔顿10分2助2帽、斯普林格10分3板 -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/resources/data/002.txt: -------------------------------------------------------------------------------- 1 | 新赛季NBA全面拉开帷幕,在湖人此前进行的两场季前赛中,一胜一负,和篮网一战,全主力打了半场,詹姆斯和拉塞尔两个持球点,带动全队8人得分上双,经过今夏的补强,湖人整个轮转框架深度明显提升,哈姆完全可以摆出两套竞争力阵容。第三场对决对手是国王,国王今年夏天5年2.17亿美元续约萨博尼斯,此外交易得到杜阿尔特,在上赛季常规赛西部第三的阵容基础上,继续升级,新赛季也有望成为太阳、勇士、湖人、掘金冲冠的搅局者。湖人今夏引援收获颇丰,普林斯的投射能力,海斯的机动性和篮下终结效率,伍德也在慢慢改掉重攻轻守的坏习惯。 2 | 3 | 4 | 5 | 6 | 本场比赛前,哈姆透露詹姆斯+里夫斯+浓眉三人组均休战,此外范德比尔特和雷迪什两人,因为脚踝伤势和跟腱伤势也无法出场,湖人几乎相当于让出一整套首发阵容。但哈姆赛前信心十足,表示如今球队可用球员很多,每个人都充满竞争力。湖人摆出的首发为:拉塞尔+文森特+普林斯+八村塁+海斯,算上替补席的伍德,以及缺阵的几人,这基本上是湖人新赛季的主要轮转框架。而国王这边除了穆雷因伤休战外,也拿出最强阵容对垒湖人:福克斯+许尔特+巴恩斯+韦津科夫+萨博尼斯。尴尬的是,国王几乎全主力,却打不过湖人的替补!浓眉在场边非常开心。 7 | 8 | 9 | 10 | 11 | 开局文森特空切篮下吃饼,巴恩斯和文森特对飙三分球,八村塁内外开花,拉塞尔飘逸跳投,湖人形成多点开花之势。湖人在防守端的压迫性十足,海斯一直在对抗萨博尼斯,而且相比于上赛季,湖人退防速度有明显提升,八村塁也敢打敢拼,顶着萨博尼斯强起造犯规。中段当国王迫近分差时,拉塞尔连续持球攻框得手,拉塞尔打得非常聪明,几次突分喂饼普林斯和伍德,审时度势挡拆后突破,国王确实拦不住。而节末湖人陷入得分荒,国王二阵打湖人三阵时,蒙克和莱尔斯的三分球带队缩小分差,第一节湖人30-28领先国王。 12 | 13 | 14 | 15 | 16 | 第二节开打,文森特连珠炮弹轰进三分,普林斯高难度强投打成2+1,萨博尼斯一直在点名海斯造杀伤,从力量对抗来说,海斯有些吃力。许尔特的三分+福克斯的上篮,国王中段终于抹平分差。但节末拉塞尔轻松上篮得手,助攻普林斯再中三分球,湖人进攻延续性很好。国王则凭借萨博尼斯和福克斯连续罚球上分,半场51-50领先湖人。看得出国王主帅迈克布朗确实想赢球,增加首发上场时间,基本按照常规赛节奏打,哈姆在锻炼第二阵容的同时,也给了小将克里斯蒂更多时间,确实湖人仅靠里弗斯+拉塞尔+文森特三后卫,延续一整年有些吃力。 17 | 18 | 19 | 20 | 21 | 下半场回来,文森特和巴恩斯对飙三分,国王在外线打开手感后,一直压制住湖人,但中段湖人突然爆发:拉塞尔造三分犯规+反击轻松上篮+突分助攻普林斯轰进三分球+控球过半场后连续两次突施冷箭三分打停国王!湖人打出一波15-3的高潮瞬间反超并拉开分差。福克斯的三分球帮助国王止血,伍德上空篮得手,克里斯蒂反击单臂扣杀,而到节末,克里斯蒂和伍德两人一举将分差拉开到两位数,三节打完湖人90-79领先国王。打到第四节,当湖人已经拿出第三阵容时,国王还是蒙克带队的第二阵容,可即便如此,国王还是无法缩小分差。 22 | 23 | 24 | 25 | 26 | 反而是湖人在卡尔斯顿+席菲诺的带领下,继续扩大领先优势,麦基面对年轻的克里斯蒂和席菲诺,速度跟不上,还屡屡吃到犯规。最终湖人109-101完胜国王,迎来季前赛两连胜!数据,国王这边,萨博尼斯10分16篮板5助攻,福克斯18分5助攻,杜阿尔特10分2篮板,巴恩斯15分。湖人这边,拉塞尔21分3篮板8助攻,八村塁13分6篮板,普林斯13分7篮板2抢断,文森特18分2助攻,伍德13分4篮板。湖人替补逆袭国王首发,而湖人第三阵容又能压制国王替补,这让人始料未及。 27 | 28 | 29 | 30 | 31 | 纵观全场比赛,湖人今非昔比。首先能得分的点太多了,拉塞尔和湖人续约1+1合同,他确实是置死地而后生,他也需要更好的表现为自己下份大合同蓄力。普林斯+文森特包括八村塁,湖人如今也不缺外线投手,更有海斯和伍德这种机动性很强的内线参与护框,整个湖人几乎没有短板。只要哈姆不执着于摆上三个小个后卫,詹眉身边保留一个做脏活的蓝领锋线,保持健康状态,新赛季湖人的上限不可限量。 -------------------------------------------------------------------------------- /llm_chat_java_hello/src/main/resources/logback-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ${HOSTNAME} 6 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | %d %p (%file:%line\)- %m%n 18 | utf-8 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | 29 | ${LOG_HOME}/app/biz.%d{yyyy-MM-dd}.%i.log 30 | 31 | 10 32 | 50MB 33 | 100MB 34 | 35 | 36 | %d %p (%file:%line\)- %m%n 37 | UTF-8 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /llm_chat_java_hello/src/test/java/com/github/xiaoymin/llm/LlmChatJavaHelloApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaoymin.llm; 2 | 3 | import com.github.xiaoymin.llm.domain.llm.EmbeddingResult; 4 | import com.github.xiaoymin.llm.llm.ZhipuAI; 5 | import com.google.gson.Gson; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.junit.jupiter.api.Test; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | 11 | @Slf4j 12 | @SpringBootTest 13 | class LlmChatJavaHelloApplicationTests { 14 | 15 | 16 | 17 | @Test 18 | void contextLoads() { 19 | } 20 | 21 | } 22 | --------------------------------------------------------------------------------