commit 3c69d9362697be716452223bc60e6068cc149b87 Author: michael Date: Fri Jan 12 16:24:14 2024 +0800 init diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5eff13a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +root = true + +# 匹配全部文件 +[*] +# 结尾换行符,可选"lf"、"cr"、"crlf" +end_of_line = lf +# 在文件结尾插入新行 +insert_final_newline = true +# 删除一行中的前后空格 +trim_trailing_whitespace = true +# 设置字符集 +charset = utf-8 +# 缩进风格,可选"space"、"tab" +indent_style = space +# 缩进的空格数 +indent_size = 4 + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..15d0d18 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +**/target/ +**/node_modules/ +.idea +*.iml +.project +.settings +starter/**/jboot.properties +*.jar +*.log +.logs +logs +*.iws +*.classpath +.DS_Store +*.patch +~$* +*/*.jar +docker_volumes/ +package-lock.json +yarn.lock diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + 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 (i) 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. diff --git a/agents-flex-core/pom.xml b/agents-flex-core/pom.xml new file mode 100644 index 0000000..036f199 --- /dev/null +++ b/agents-flex-core/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + com.agentsflex + parent + 1.0-SNAPSHOT + + + agents-flex-core + + + 8 + 8 + UTF-8 + 4.9.3 + 2.0.45 + + + + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + + com.squareup.okhttp3 + okhttp-sse + ${okhttp.version} + + + com.alibaba + fastjson + ${fastjson.version} + + + + diff --git a/agents-flex-core/src/main/java/com/agentsflex/Main.java b/agents-flex-core/src/main/java/com/agentsflex/Main.java new file mode 100644 index 0000000..d9109c5 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/Main.java @@ -0,0 +1,7 @@ +package com.agentsflex; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/agents-flex-core/src/main/java/com/agentsflex/agent/Agent.java b/agents-flex-core/src/main/java/com/agentsflex/agent/Agent.java new file mode 100644 index 0000000..b77d674 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/agent/Agent.java @@ -0,0 +1,4 @@ +package com.agentsflex.agent; + +public class Agent { +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/annotation/FunctionDef.java b/agents-flex-core/src/main/java/com/agentsflex/annotation/FunctionDef.java new file mode 100644 index 0000000..90abfa9 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/annotation/FunctionDef.java @@ -0,0 +1,10 @@ +package com.agentsflex.annotation; + +import java.lang.annotation.*; + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface FunctionDef { + +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/chain/Chain.java b/agents-flex-core/src/main/java/com/agentsflex/chain/Chain.java new file mode 100644 index 0000000..e8cbc33 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/chain/Chain.java @@ -0,0 +1,4 @@ +package com.agentsflex.chain; + +public class Chain { +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/chain/Interceptor.java b/agents-flex-core/src/main/java/com/agentsflex/chain/Interceptor.java new file mode 100644 index 0000000..8aaa39e --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/chain/Interceptor.java @@ -0,0 +1,4 @@ +package com.agentsflex.chain; + +public class Interceptor { +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/chain/Invocation.java b/agents-flex-core/src/main/java/com/agentsflex/chain/Invocation.java new file mode 100644 index 0000000..46adbfb --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/chain/Invocation.java @@ -0,0 +1,4 @@ +package com.agentsflex.chain; + +public class Invocation { +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/chain/Invoker.java b/agents-flex-core/src/main/java/com/agentsflex/chain/Invoker.java new file mode 100644 index 0000000..6cc4929 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/chain/Invoker.java @@ -0,0 +1,7 @@ +package com.agentsflex.chain; + +public class Invoker { + + + +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/client/BaseLlmClientListener.java b/agents-flex-core/src/main/java/com/agentsflex/client/BaseLlmClientListener.java new file mode 100644 index 0000000..6817de5 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/client/BaseLlmClientListener.java @@ -0,0 +1,30 @@ +package com.agentsflex.client; + +import com.agentsflex.llm.ChatListener; +import com.agentsflex.llm.Llm; + +public abstract class BaseLlmClientListener implements LlmClientListener{ + + private final Llm llm; + private final ChatListener chatListener; + + public BaseLlmClientListener(Llm llm,ChatListener chatListener) { + this.llm = llm; + this.chatListener = chatListener; + } + + @Override + public void onStart(LlmClient client) { + chatListener.onStart(llm); + } + + @Override + public void onStop(LlmClient client) { + chatListener.onStop(llm); + } + + @Override + public void onFailure(LlmClient client, Throwable throwable) { + chatListener.onFailure(llm,throwable); + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/client/LlmClient.java b/agents-flex-core/src/main/java/com/agentsflex/client/LlmClient.java new file mode 100644 index 0000000..6cde073 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/client/LlmClient.java @@ -0,0 +1,10 @@ +package com.agentsflex.client; + +import java.util.Map; + +public interface LlmClient { + + void start(String url, Map headers, String payload, LlmClientListener listener); + + void stop(); +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/client/LlmClientListener.java b/agents-flex-core/src/main/java/com/agentsflex/client/LlmClientListener.java new file mode 100644 index 0000000..74503f1 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/client/LlmClientListener.java @@ -0,0 +1,13 @@ +package com.agentsflex.client; + +public interface LlmClientListener { + + void onStart(LlmClient client); + + void onMessage(LlmClient client,String response); + + void onStop(LlmClient client); + + void onFailure(LlmClient client, Throwable throwable); + +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/client/impl/HttpClient.java b/agents-flex-core/src/main/java/com/agentsflex/client/impl/HttpClient.java new file mode 100644 index 0000000..b0f9a8a --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/client/impl/HttpClient.java @@ -0,0 +1,19 @@ +package com.agentsflex.client.impl; + +import com.agentsflex.client.LlmClient; +import com.agentsflex.client.LlmClientListener; + +import java.util.Map; + +public class HttpClient implements LlmClient { + + @Override + public void start(String url, Map headers, String payload, LlmClientListener listener) { + + } + + @Override + public void stop() { + + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/client/impl/SseClient.java b/agents-flex-core/src/main/java/com/agentsflex/client/impl/SseClient.java new file mode 100644 index 0000000..61980bd --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/client/impl/SseClient.java @@ -0,0 +1,110 @@ +package com.agentsflex.client.impl; + +import com.agentsflex.client.LlmClient; +import com.agentsflex.client.LlmClientListener; +import okhttp3.*; +import okhttp3.internal.sse.RealEventSource; +import okhttp3.sse.EventSource; +import okhttp3.sse.EventSourceListener; +import okhttp3.sse.EventSources; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class SseClient extends EventSourceListener implements LlmClient { + + private OkHttpClient client; + private RealEventSource eventSource; + + private LlmClientListener listener; + private boolean isStop = false; + + @Override + public void start(String url, Map headers, String payload, LlmClientListener listener) { + this.listener = listener; + this.isStop = false; + + Request.Builder rBuilder = new Request.Builder() + .url(url); + + if (headers != null && !headers.isEmpty()) { + headers.forEach(rBuilder::addHeader); + } + + MediaType mediaType = MediaType.parse("application/json; charset=utf-8"); + RequestBody body = RequestBody.create(payload,mediaType); + rBuilder.post(body); + + + this.client = new OkHttpClient.Builder() + .connectTimeout(3, TimeUnit.MINUTES) + .readTimeout(3, TimeUnit.MINUTES) + .build(); + +// this.eventSource = new RealEventSource(rBuilder.build(), this); +// this.eventSource.connect(this.client); + + + this.listener.onStart(this); + + EventSource.Factory factory = EventSources.createFactory(this.client); + factory.newEventSource(rBuilder.build(),this); + + + } + + @Override + public void stop() { + if (!isStop) { + this.isStop = true; + eventSource.cancel(); + client.dispatcher().executorService().shutdown(); + this.listener.onStop(this); + } + } + + + @Override + public void onClosed(@NotNull EventSource eventSource) { + System.out.println("onClosed-->>" + eventSource); + if (!isStop) { + this.isStop = true; + this.listener.onStop(this); + } + } + + @Override + public void onEvent(@NotNull EventSource eventSource, @Nullable String id, @Nullable String type, @NotNull String data) { + System.out.println("onEvent-->>" + eventSource); + System.out.println("onEvent-->>" + id); + System.out.println("onEvent-->>" + type); + System.out.println("onEvent-->>" + data); + this.listener.onMessage(this, data); + } + + @Override + public void onFailure(@NotNull EventSource eventSource, @Nullable Throwable t, @Nullable Response response) { + System.out.println("onFailure-->>" + eventSource); + System.out.println("onFailure-->>" + t); + System.out.println("onFailure-->>" + response); + String string = null; + try { + string = response.body().string(); + System.out.println("onFailure-->>" + string); + } catch (IOException e) { + throw new RuntimeException(e); + } + + this.listener.onFailure(this, t); + } + + @Override + public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) { + //super.onOpen(eventSource, response); + System.out.println("onOpen-->>" + eventSource); + System.out.println("onOpen-->>" + response); + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/client/impl/WebSocketClient.java b/agents-flex-core/src/main/java/com/agentsflex/client/impl/WebSocketClient.java new file mode 100644 index 0000000..2a7dcf7 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/client/impl/WebSocketClient.java @@ -0,0 +1,92 @@ +package com.agentsflex.client.impl; + +import com.agentsflex.client.LlmClient; +import com.agentsflex.client.LlmClientListener; +import okhttp3.*; +import okio.ByteString; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class WebSocketClient extends WebSocketListener implements LlmClient { + + + private WebSocket webSocket; + private LlmClientListener listener; + private boolean isStop = false; + + private String payload; + + @Override + public void start(String url, Map headers, String payload, LlmClientListener listener) { + this.listener = listener; + this.payload = payload; + + OkHttpClient client = new OkHttpClient.Builder() + .readTimeout(0, TimeUnit.MILLISECONDS) + .build(); + + Request request = new Request.Builder() + .url(url) + .build(); + + this.webSocket = client.newWebSocket(request, this); + this.isStop = false; + + + // Trigger shutdown of the dispatcher's executor so this process can exit cleanly. +// client.dispatcher().executorService().shutdown(); + } + + @Override + public void stop() { + if (webSocket != null) { + webSocket.close(0, ""); + } + if (!isStop) { + this.isStop = true; + listener.onStop(this); + } + } + + + //webSocket events + @Override + public void onOpen(WebSocket webSocket, Response response) { + webSocket.send(payload); + this.listener.onStart(this); + } + + @Override + public void onMessage(WebSocket webSocket, String text) { + this.listener.onMessage(this, text); + } + + @Override + public void onMessage(WebSocket webSocket, ByteString bytes) { + this.listener.onMessage(this, bytes.utf8()); + } + + @Override + public void onClosing(WebSocket webSocket, int code, String reason) { + } + + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + if (!isStop) { + this.isStop = true; + this.listener.onStop(this); + + this.listener.onFailure(this, t); + } + } + + @Override + public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) { + if (!isStop) { + this.isStop = true; + this.listener.onStop(this); + } + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/llm/BaseLlm.java b/agents-flex-core/src/main/java/com/agentsflex/llm/BaseLlm.java new file mode 100644 index 0000000..0450f7e --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/llm/BaseLlm.java @@ -0,0 +1,14 @@ +package com.agentsflex.llm; + +public abstract class BaseLlm extends Llm{ + + protected T config; + + public BaseLlm(T config) { + this.config = config; + } + + public T getConfig() { + return config; + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/llm/ChatListener.java b/agents-flex-core/src/main/java/com/agentsflex/llm/ChatListener.java new file mode 100644 index 0000000..b95bdaa --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/llm/ChatListener.java @@ -0,0 +1,14 @@ +package com.agentsflex.llm; + +import com.agentsflex.message.AiMessage; + +public interface ChatListener { + + default void onStart(Llm llm){} + + void onMessage(Llm llm, AiMessage aiMessage); + + default void onStop(Llm llm){} + + default void onFailure(Llm llm, Throwable throwable){} +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/llm/Embeddings.java b/agents-flex-core/src/main/java/com/agentsflex/llm/Embeddings.java new file mode 100644 index 0000000..3a3b804 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/llm/Embeddings.java @@ -0,0 +1,10 @@ +package com.agentsflex.llm; + +import com.agentsflex.client.LlmClient; +import com.agentsflex.prompt.Prompt; + +public interface Embeddings { + + LlmClient embeddings(Prompt prompt, EmbeddingsListener listener); + +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/llm/EmbeddingsListener.java b/agents-flex-core/src/main/java/com/agentsflex/llm/EmbeddingsListener.java new file mode 100644 index 0000000..df2dd6f --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/llm/EmbeddingsListener.java @@ -0,0 +1,4 @@ +package com.agentsflex.llm; + +public interface EmbeddingsListener { +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/llm/Llm.java b/agents-flex-core/src/main/java/com/agentsflex/llm/Llm.java new file mode 100644 index 0000000..81ef0a4 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/llm/Llm.java @@ -0,0 +1,11 @@ +package com.agentsflex.llm; + +import com.agentsflex.client.LlmClient; +import com.agentsflex.prompt.Prompt; + +public abstract class Llm implements Embeddings{ + + + public abstract LlmClient chat(Prompt prompt, ChatListener listener); + +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/llm/LlmConfig.java b/agents-flex-core/src/main/java/com/agentsflex/llm/LlmConfig.java new file mode 100644 index 0000000..9585714 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/llm/LlmConfig.java @@ -0,0 +1,6 @@ +package com.agentsflex.llm; + +import java.io.Serializable; + +public class LlmConfig implements Serializable { +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/message/AiMessage.java b/agents-flex-core/src/main/java/com/agentsflex/message/AiMessage.java new file mode 100644 index 0000000..4ac0be0 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/message/AiMessage.java @@ -0,0 +1,44 @@ +package com.agentsflex.message; + + +public class AiMessage extends Message { + + private Integer index; + private MessageStatus status; + private int totalTokens; + + private String fullContent; + + + public Integer getIndex() { + return index; + } + + public void setIndex(Integer index) { + this.index = index; + } + + public MessageStatus getStatus() { + return status; + } + + public void setStatus(MessageStatus status) { + this.status = status; + } + + public int getTotalTokens() { + return totalTokens; + } + + public void setTotalTokens(int totalTokens) { + this.totalTokens = totalTokens; + } + + public String getFullContent() { + return fullContent; + } + + public void setFullContent(String fullContent) { + this.fullContent = fullContent; + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/message/FunctionMessage.java b/agents-flex-core/src/main/java/com/agentsflex/message/FunctionMessage.java new file mode 100644 index 0000000..2b017bb --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/message/FunctionMessage.java @@ -0,0 +1,4 @@ +package com.agentsflex.message; + +public class FunctionMessage extends Message{ +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/message/HumanMessage.java b/agents-flex-core/src/main/java/com/agentsflex/message/HumanMessage.java new file mode 100644 index 0000000..8b02df6 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/message/HumanMessage.java @@ -0,0 +1,9 @@ +package com.agentsflex.message; + +public class HumanMessage extends Message{ + + public HumanMessage(String content) { + super(); + setContent(content); + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/message/Message.java b/agents-flex-core/src/main/java/com/agentsflex/message/Message.java new file mode 100644 index 0000000..f45f4d4 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/message/Message.java @@ -0,0 +1,16 @@ +package com.agentsflex.message; + +import com.agentsflex.util.Metadata; + +public class Message extends Metadata { + + protected String content; + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/message/MessageStatus.java b/agents-flex-core/src/main/java/com/agentsflex/message/MessageStatus.java new file mode 100644 index 0000000..264db4e --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/message/MessageStatus.java @@ -0,0 +1,24 @@ +package com.agentsflex.message; + +import java.io.Serializable; + +public enum MessageStatus implements Serializable { + START(1), + MIDDLE(2), + END(3), + UNKNOW(9), + ; + private int value; + + MessageStatus(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/message/SystemMessage.java b/agents-flex-core/src/main/java/com/agentsflex/message/SystemMessage.java new file mode 100644 index 0000000..0c70e89 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/message/SystemMessage.java @@ -0,0 +1,11 @@ +package com.agentsflex.message; + +public class SystemMessage extends Message { + + + public SystemMessage(String content) { + this.content = content; + } + + +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/prompt/HistoriesPrompt.java b/agents-flex-core/src/main/java/com/agentsflex/prompt/HistoriesPrompt.java new file mode 100644 index 0000000..7c1ab15 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/prompt/HistoriesPrompt.java @@ -0,0 +1,23 @@ +package com.agentsflex.prompt; + +import com.agentsflex.message.Message; + +import java.util.ArrayList; +import java.util.List; + +public class HistoriesPrompt extends Prompt{ + + private final List messages = new ArrayList<>(); + + + + public void addMessage(Message message) { + messages.add(message); + } + + + @Override + public List toMessages() { + return messages; + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/prompt/Prompt.java b/agents-flex-core/src/main/java/com/agentsflex/prompt/Prompt.java new file mode 100644 index 0000000..4a54997 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/prompt/Prompt.java @@ -0,0 +1,13 @@ +package com.agentsflex.prompt; + +import com.agentsflex.message.Message; +import com.agentsflex.util.Metadata; + +import java.util.List; + + +public abstract class Prompt extends Metadata { + + public abstract List toMessages(); + +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/prompt/PromptTemplate.java b/agents-flex-core/src/main/java/com/agentsflex/prompt/PromptTemplate.java new file mode 100644 index 0000000..8267b2b --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/prompt/PromptTemplate.java @@ -0,0 +1,5 @@ +package com.agentsflex.prompt; + +public class PromptTemplate { + +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/prompt/SimplePrompt.java b/agents-flex-core/src/main/java/com/agentsflex/prompt/SimplePrompt.java new file mode 100644 index 0000000..e0b4f4f --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/prompt/SimplePrompt.java @@ -0,0 +1,21 @@ +package com.agentsflex.prompt; + +import com.agentsflex.message.HumanMessage; +import com.agentsflex.message.Message; + +import java.util.Arrays; +import java.util.List; + +public class SimplePrompt extends Prompt{ + + private final String content; + + public SimplePrompt(String content) { + this.content = content; + } + + @Override + public List toMessages() { + return Arrays.asList(new HumanMessage(content)); + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/text/Loader.java b/agents-flex-core/src/main/java/com/agentsflex/text/Loader.java new file mode 100644 index 0000000..1c9a248 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/text/Loader.java @@ -0,0 +1,5 @@ +package com.agentsflex.text; + +public interface Loader { + Text load(); +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/text/Splitter.java b/agents-flex-core/src/main/java/com/agentsflex/text/Splitter.java new file mode 100644 index 0000000..66001d8 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/text/Splitter.java @@ -0,0 +1,8 @@ +package com.agentsflex.text; + +import java.util.List; + +public interface Splitter { + + List split(Text text); +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/text/Text.java b/agents-flex-core/src/main/java/com/agentsflex/text/Text.java new file mode 100644 index 0000000..e05f86c --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/text/Text.java @@ -0,0 +1,15 @@ +package com.agentsflex.text; + +import com.agentsflex.util.Metadata; + +public class Text extends Metadata { + private String content; + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/text/splitter/SimpleSplitter.java b/agents-flex-core/src/main/java/com/agentsflex/text/splitter/SimpleSplitter.java new file mode 100644 index 0000000..dcd458a --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/text/splitter/SimpleSplitter.java @@ -0,0 +1,14 @@ +package com.agentsflex.text.splitter; + +import com.agentsflex.text.Splitter; +import com.agentsflex.text.Text; + +import java.util.List; + +public class SimpleSplitter implements Splitter { + + @Override + public List split(Text text) { + return null; + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/util/HashUtil.java b/agents-flex-core/src/main/java/com/agentsflex/util/HashUtil.java new file mode 100644 index 0000000..16dbe3d --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/util/HashUtil.java @@ -0,0 +1,56 @@ +package com.agentsflex.util; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.util.Base64; +import java.util.concurrent.ThreadLocalRandom; + +public class HashUtil { + private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray(); + private static final char[] CHAR_ARRAY = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); + + public static String md5(String srcStr) { + return hash("MD5", srcStr); + } + + + public static String sha256(String srcStr) { + return hash("SHA-256", srcStr); + } + + public static String hmacSHA256ToBase64(String content, String secret) { + try { + Mac hmacSHA256 = Mac.getInstance("HmacSHA256"); + SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); + hmacSHA256.init(secretKey); + byte[] bytes = hmacSHA256.doFinal(content.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(bytes); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String hash(String algorithm, String srcStr) { + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + byte[] bytes = md.digest(srcStr.getBytes(StandardCharsets.UTF_8)); + return bytesToHex(bytes); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String bytesToHex(byte[] bytes) { + StringBuilder ret = new StringBuilder(bytes.length * 2); + for (int i = 0; i < bytes.length; i++) { + ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]); + ret.append(HEX_DIGITS[bytes[i] & 0x0f]); + } + return ret.toString(); + } + + + +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/util/Metadata.java b/agents-flex-core/src/main/java/com/agentsflex/util/Metadata.java new file mode 100644 index 0000000..782088a --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/util/Metadata.java @@ -0,0 +1,29 @@ +package com.agentsflex.util; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +public class Metadata implements Serializable { + + protected Map metadataMap; + + public Object getMetadata(String key) { + return metadataMap != null ? metadataMap.get(key) : null; + } + + public void addMetadata(String key, Object value) { + if (metadataMap == null) { + metadataMap = new HashMap<>(); + } + metadataMap.put(key, value); + } + + public Map getMetadataMap() { + return metadataMap; + } + + public void setMetadataMap(Map metadataMap) { + this.metadataMap = metadataMap; + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/util/OKHttpUtil.java b/agents-flex-core/src/main/java/com/agentsflex/util/OKHttpUtil.java new file mode 100644 index 0000000..c55888e --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/util/OKHttpUtil.java @@ -0,0 +1,4 @@ +package com.agentsflex.util; + +public class OKHttpUtil { +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/util/StringUtil.java b/agents-flex-core/src/main/java/com/agentsflex/util/StringUtil.java new file mode 100644 index 0000000..04f3795 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/util/StringUtil.java @@ -0,0 +1,4 @@ +package com.agentsflex.util; + +public class StringUtil { +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/vector/Retriever.java b/agents-flex-core/src/main/java/com/agentsflex/vector/Retriever.java new file mode 100644 index 0000000..c4d890b --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/vector/Retriever.java @@ -0,0 +1,6 @@ +package com.agentsflex.vector; + + +public interface Retriever { + VectorData retrieve(String prompt); +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/vector/RetrieverOptions.java b/agents-flex-core/src/main/java/com/agentsflex/vector/RetrieverOptions.java new file mode 100644 index 0000000..cf27545 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/vector/RetrieverOptions.java @@ -0,0 +1,4 @@ +package com.agentsflex.vector; + +public class RetrieverOptions { +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/vector/VectorData.java b/agents-flex-core/src/main/java/com/agentsflex/vector/VectorData.java new file mode 100644 index 0000000..df3277d --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/vector/VectorData.java @@ -0,0 +1,18 @@ +package com.agentsflex.vector; + +import com.agentsflex.util.Metadata; + + +public class VectorData extends Metadata { + + // the embedding data + private double[] data; + + public double[] getData() { + return data; + } + + public void setData(double[] data) { + this.data = data; + } +} diff --git a/agents-flex-core/src/main/java/com/agentsflex/vector/VectorStorage.java b/agents-flex-core/src/main/java/com/agentsflex/vector/VectorStorage.java new file mode 100644 index 0000000..d9a2c29 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/vector/VectorStorage.java @@ -0,0 +1,5 @@ +package com.agentsflex.vector; + +public interface VectorStorage { + Retriever getRetrieve(RetrieverOptions options); +} diff --git a/agents-flex-llm/agents-flex-llm-openai/pom.xml b/agents-flex-llm/agents-flex-llm-openai/pom.xml new file mode 100644 index 0000000..7f05398 --- /dev/null +++ b/agents-flex-llm/agents-flex-llm-openai/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + com.agentsflex + agents-flex-llm + 1.0-SNAPSHOT + + + agents-flex-llm-openai + + + 8 + 8 + UTF-8 + + + + com.agentsflex + agents-flex-core + 1.0-SNAPSHOT + compile + + + + diff --git a/agents-flex-llm/agents-flex-llm-openai/src/main/java/com/agentsflex/llm/openai/OpenAiConfig.java b/agents-flex-llm/agents-flex-llm-openai/src/main/java/com/agentsflex/llm/openai/OpenAiConfig.java new file mode 100644 index 0000000..bebe89e --- /dev/null +++ b/agents-flex-llm/agents-flex-llm-openai/src/main/java/com/agentsflex/llm/openai/OpenAiConfig.java @@ -0,0 +1,25 @@ +package com.agentsflex.llm.openai; + +import com.agentsflex.llm.LlmConfig; + +public class OpenAiConfig extends LlmConfig { + + private String apiKey; + private String model = "gpt-3.5-turbo"; + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } +} diff --git a/agents-flex-llm/agents-flex-llm-openai/src/main/java/com/agentsflex/llm/openai/OpenAiLLmUtil.java b/agents-flex-llm/agents-flex-llm-openai/src/main/java/com/agentsflex/llm/openai/OpenAiLLmUtil.java new file mode 100644 index 0000000..be54651 --- /dev/null +++ b/agents-flex-llm/agents-flex-llm-openai/src/main/java/com/agentsflex/llm/openai/OpenAiLLmUtil.java @@ -0,0 +1,46 @@ +package com.agentsflex.llm.openai; + +import com.agentsflex.message.AiMessage; +import com.agentsflex.message.HumanMessage; +import com.agentsflex.message.Message; +import com.agentsflex.prompt.Prompt; +import com.alibaba.fastjson.JSON; + +import java.util.*; + +public class OpenAiLLmUtil { + + + public static String promptToPayload(Prompt prompt,OpenAiConfig config) { + + List messages = prompt.toMessages(); + + // https://platform.openai.com/docs/api-reference/making-requests + String payload = "{\n" + +// " \"model\": \"gpt-3.5-turbo\",\n" + + " \"model\": \""+config.getModel()+"\",\n" + + " \"messages\": messageJsonString,\n" + + " \"temperature\": 0.7\n" + + "}"; + + + List> messageArray = new ArrayList<>(); + messages.forEach(message -> { + Map map = new HashMap<>(2); + if (message instanceof HumanMessage) { + map.put("role", "user"); + map.put("content", message.getContent()); + } else if (message instanceof AiMessage) { + map.put("role", "assistant"); + map.put("content", ((AiMessage) message).getFullContent()); + } + + messageArray.add(map); + }); + + String messageText = JSON.toJSONString(messageArray); + return payload.replace("messageJsonString", messageText); + } + + +} diff --git a/agents-flex-llm/agents-flex-llm-openai/src/main/java/com/agentsflex/llm/openai/OpenAiLlm.java b/agents-flex-llm/agents-flex-llm-openai/src/main/java/com/agentsflex/llm/openai/OpenAiLlm.java new file mode 100644 index 0000000..15e5806 --- /dev/null +++ b/agents-flex-llm/agents-flex-llm-openai/src/main/java/com/agentsflex/llm/openai/OpenAiLlm.java @@ -0,0 +1,47 @@ +package com.agentsflex.llm.openai; + +import com.agentsflex.client.BaseLlmClientListener; +import com.agentsflex.client.LlmClient; +import com.agentsflex.client.impl.SseClient; +import com.agentsflex.llm.ChatListener; +import com.agentsflex.llm.BaseLlm; +import com.agentsflex.llm.EmbeddingsListener; +import com.agentsflex.message.AiMessage; +import com.agentsflex.prompt.Prompt; + +import java.util.HashMap; +import java.util.Map; + +public class OpenAiLlm extends BaseLlm { + + public OpenAiLlm(OpenAiConfig config) { + super(config); + } + + + @Override + public LlmClient chat(Prompt prompt, ChatListener listener) { + LlmClient llmClient = new SseClient(); + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + headers.put("Authorization", "Bearer " + getConfig().getApiKey()); + + String payload = OpenAiLLmUtil.promptToPayload(prompt, config); + + + llmClient.start("https://api.openai.com/v1/chat/completions", headers, payload, new BaseLlmClientListener(this, listener) { + @Override + public void onMessage(LlmClient client, String response) { + listener.onMessage(OpenAiLlm.this, new AiMessage()); + } + }); + + return llmClient; + } + + + @Override + public LlmClient embeddings(Prompt prompt, EmbeddingsListener listener) { + return null; + } +} diff --git a/agents-flex-llm/agents-flex-llm-openai/src/test/java/com/agentsflex/llm/openai/OpenAiLlmTest.java b/agents-flex-llm/agents-flex-llm-openai/src/test/java/com/agentsflex/llm/openai/OpenAiLlmTest.java new file mode 100644 index 0000000..b493cc5 --- /dev/null +++ b/agents-flex-llm/agents-flex-llm-openai/src/test/java/com/agentsflex/llm/openai/OpenAiLlmTest.java @@ -0,0 +1,41 @@ +package com.agentsflex.llm.openai; + +import com.agentsflex.llm.Llm; +import com.agentsflex.prompt.SimplePrompt; + +public class OpenAiLlmTest { + + public static void main(String[] args) throws InterruptedException { + + + OpenAiConfig config = new OpenAiConfig(); + config.setApiKey("sk-rts5NF6n*******"); + + Llm llm = new OpenAiLlm(config); + +// HistoriesPrompt prompt = new HistoriesPrompt(); +// +// System.out.println("您想问什么?"); +// Scanner scanner = new Scanner(System.in); +// String userInput = scanner.nextLine(); +// +// while (userInput != null){ +// +// prompt.addMessage(new HumanMessage(userInput)); +// +// llm.chat(prompt, (instance, message) -> { +// System.out.println(">>>> " + message.getContent()); +// }); +// +// userInput = scanner.nextLine(); +// } + + + llm.chat(new SimplePrompt("请写一个小兔子战胜大灰狼的故事"), (instance, message) -> { + System.out.println("--->" + message.getContent()); + }); + + Thread.sleep(10000); + + } +} diff --git a/agents-flex-llm/agents-flex-llm-spark/pom.xml b/agents-flex-llm/agents-flex-llm-spark/pom.xml new file mode 100644 index 0000000..c033562 --- /dev/null +++ b/agents-flex-llm/agents-flex-llm-spark/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + com.agentsflex + agents-flex-llm + 1.0-SNAPSHOT + + + agents-flex-llm-spark + + + 8 + 8 + UTF-8 + + + + com.agentsflex + agents-flex-core + 1.0-SNAPSHOT + compile + + + + + junit + junit + test + + + + diff --git a/agents-flex-llm/agents-flex-llm-spark/src/main/java/com/agentsflex/llm/spark/SparkLlm.java b/agents-flex-llm/agents-flex-llm-spark/src/main/java/com/agentsflex/llm/spark/SparkLlm.java new file mode 100644 index 0000000..82268c5 --- /dev/null +++ b/agents-flex-llm/agents-flex-llm-spark/src/main/java/com/agentsflex/llm/spark/SparkLlm.java @@ -0,0 +1,54 @@ +package com.agentsflex.llm.spark; + +import com.agentsflex.client.BaseLlmClientListener; +import com.agentsflex.client.LlmClient; +import com.agentsflex.client.impl.WebSocketClient; +import com.agentsflex.llm.ChatListener; +import com.agentsflex.llm.BaseLlm; +import com.agentsflex.llm.EmbeddingsListener; +import com.agentsflex.message.AiMessage; +import com.agentsflex.message.MessageStatus; +import com.agentsflex.prompt.HistoriesPrompt; +import com.agentsflex.prompt.Prompt; + +public class SparkLlm extends BaseLlm { + + public SparkLlm(SparkLlmConfig config) { + super(config); + } + + @Override + public LlmClient chat(Prompt prompt, ChatListener listener) { + LlmClient llmClient = new WebSocketClient(); + String url = SparkLlmUtil.createURL(config); + + String payload = SparkLlmUtil.promptToPayload(prompt, config); + + StringBuilder fullMessage = new StringBuilder(); + + llmClient.start(url, null, payload, new BaseLlmClientListener(this, listener) { + @Override + public void onMessage(LlmClient client, String response) { + AiMessage aiMessage = SparkLlmUtil.parseAiMessage(response); + + fullMessage.append(aiMessage.getContent()); + aiMessage.setFullContent(fullMessage.toString()); + + listener.onMessage(SparkLlm.this, aiMessage); + + if (aiMessage.getStatus() == MessageStatus.END + && prompt instanceof HistoriesPrompt) { + ((HistoriesPrompt) prompt).addMessage(aiMessage); + } + } + }); + + return llmClient; + } + + + @Override + public LlmClient embeddings(Prompt prompt, EmbeddingsListener listener) { + return null; + } +} diff --git a/agents-flex-llm/agents-flex-llm-spark/src/main/java/com/agentsflex/llm/spark/SparkLlmConfig.java b/agents-flex-llm/agents-flex-llm-spark/src/main/java/com/agentsflex/llm/spark/SparkLlmConfig.java new file mode 100644 index 0000000..03b7c7a --- /dev/null +++ b/agents-flex-llm/agents-flex-llm-spark/src/main/java/com/agentsflex/llm/spark/SparkLlmConfig.java @@ -0,0 +1,44 @@ +package com.agentsflex.llm.spark; + +import com.agentsflex.llm.LlmConfig; + +public class SparkLlmConfig extends LlmConfig { + + private String appId; + private String apiSecret; + private String apiKey ; + private String version = "v3.1"; + + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getApiSecret() { + return apiSecret; + } + + public void setApiSecret(String apiSecret) { + this.apiSecret = apiSecret; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } +} diff --git a/agents-flex-llm/agents-flex-llm-spark/src/main/java/com/agentsflex/llm/spark/SparkLlmUtil.java b/agents-flex-llm/agents-flex-llm-spark/src/main/java/com/agentsflex/llm/spark/SparkLlmUtil.java new file mode 100644 index 0000000..37d9107 --- /dev/null +++ b/agents-flex-llm/agents-flex-llm-spark/src/main/java/com/agentsflex/llm/spark/SparkLlmUtil.java @@ -0,0 +1,113 @@ +package com.agentsflex.llm.spark; + +import com.agentsflex.message.AiMessage; +import com.agentsflex.message.HumanMessage; +import com.agentsflex.message.Message; +import com.agentsflex.message.MessageStatus; +import com.agentsflex.prompt.Prompt; +import com.agentsflex.util.HashUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.JSONPath; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.*; + +public class SparkLlmUtil { + + public static AiMessage parseAiMessage(String json){ + AiMessage aiMessage = new AiMessage(); + JSONObject jsonObject = JSON.parseObject(json); + Object status = JSONPath.eval(jsonObject, "$.payload.choices.status"); + MessageStatus messageStatus = SparkLlmUtil.parseMessageStatus((Integer) status); + aiMessage.setStatus(messageStatus); + aiMessage.setIndex((Integer) JSONPath.eval(jsonObject,"$.payload.choices.text[0].index")); + aiMessage.setContent((String) JSONPath.eval(jsonObject,"$.payload.choices.text[0].content")); + return aiMessage; + } + + + public static String promptToPayload(Prompt prompt, SparkLlmConfig config) { + + List messages = prompt.toMessages(); + + // https://www.xfyun.cn/doc/spark/Web.html#_1-%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E + String payload = "{\n" + + " \"header\": {\n" + + " \"app_id\": \"" + config.getAppId() + "\",\n" + + " \"uid\": \"" + UUID.randomUUID() + "\"\n" + + " },\n" + + " \"parameter\": {\n" + + " \"chat\": {\n" + + " \"domain\": \"generalv3\",\n" + + " \"temperature\": 0.5,\n" + + " \"max_tokens\": 1024 \n" + + " }\n" + + " },\n" + + " \"payload\": {\n" + + " \"message\": {\n" + + " \"text\": messageJsonString" + + " }\n" + + " }\n" + + "}"; + + + List> messageArray = new ArrayList<>(); + messages.forEach(message -> { + Map map = new HashMap<>(2); + if (message instanceof HumanMessage) { + map.put("role", "user"); + map.put("content", message.getContent()); + } else if (message instanceof AiMessage) { + map.put("role", "assistant"); + map.put("content", ((AiMessage) message).getFullContent()); + } + + messageArray.add(map); + }); + + String messageText = JSON.toJSONString(messageArray); + return payload.replace("messageJsonString", messageText); + } + + public static MessageStatus parseMessageStatus(Integer status) { + switch (status) { + case 0: + return MessageStatus.START; + case 1: + return MessageStatus.MIDDLE; + case 2: + return MessageStatus.END; + } + + return MessageStatus.UNKNOW; + } + + public static String createURL(SparkLlmConfig config) { + SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss '+0000'", Locale.US); + sdf.setTimeZone(java.util.TimeZone.getTimeZone("UTC")); + String date = sdf.format(new Date()); + + String header = "host: spark-api.xf-yun.com\n"; + header += "date: " + date + "\n"; + header += "GET /" + config.getVersion() + "/chat HTTP/1.1"; + + String base64 = HashUtil.hmacSHA256ToBase64(header, config.getApiSecret()); + String authorization_origin = "api_key=\"" + config.getApiKey() + + "\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"" + base64 + "\""; + + String authorization = Base64.getEncoder().encodeToString(authorization_origin.getBytes()); + return "ws://spark-api.xf-yun.com/" + config.getVersion() + "/chat?authorization=" + authorization + + "&date=" + urlEncode(date) + "&host=spark-api.xf-yun.com"; + } + + private static String urlEncode(String content) { + try { + return URLEncoder.encode(content, "utf-8").replace("+", "%20"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } +} diff --git a/agents-flex-llm/agents-flex-llm-spark/src/test/java/com/agentsflex/llm/spark/test/SparkLlmTest.java b/agents-flex-llm/agents-flex-llm-spark/src/test/java/com/agentsflex/llm/spark/test/SparkLlmTest.java new file mode 100644 index 0000000..77959e3 --- /dev/null +++ b/agents-flex-llm/agents-flex-llm-spark/src/test/java/com/agentsflex/llm/spark/test/SparkLlmTest.java @@ -0,0 +1,43 @@ +package com.agentsflex.llm.spark.test; + +import com.agentsflex.llm.Llm; +import com.agentsflex.llm.spark.SparkLlm; +import com.agentsflex.llm.spark.SparkLlmConfig; +import com.agentsflex.message.HumanMessage; +import com.agentsflex.prompt.HistoriesPrompt; + +import java.util.Scanner; + +public class SparkLlmTest { + + public static void main(String[] args) throws InterruptedException { + + + SparkLlmConfig config = new SparkLlmConfig(); + config.setAppId("****"); + config.setApiKey("****"); + config.setApiSecret("****"); + + Llm llm = new SparkLlm(config); + + HistoriesPrompt prompt = new HistoriesPrompt(); + + System.out.println("您想问什么?"); + Scanner scanner = new Scanner(System.in); + String userInput = scanner.nextLine(); + + while (userInput != null){ + + prompt.addMessage(new HumanMessage(userInput)); + + llm.chat(prompt, (instance, message) -> { + System.out.println(">>>> " + message.getContent()); + }); + + userInput = scanner.nextLine(); + } + + + + } +} diff --git a/agents-flex-llm/pom.xml b/agents-flex-llm/pom.xml new file mode 100644 index 0000000..0001f5f --- /dev/null +++ b/agents-flex-llm/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + + com.agentsflex + parent + 1.0-SNAPSHOT + + + agents-flex-llm + pom + + agents-flex-llm-openai + agents-flex-llm-spark + + + + 8 + 8 + UTF-8 + + + diff --git a/agents-flex-samples/pom.xml b/agents-flex-samples/pom.xml new file mode 100644 index 0000000..f548df9 --- /dev/null +++ b/agents-flex-samples/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + com.agentsflex + parent + 1.0-SNAPSHOT + + + agents-flex-samples + + + 8 + 8 + UTF-8 + + + diff --git a/agents-flex-samples/src/main/java/com/agentsflex/Main.java b/agents-flex-samples/src/main/java/com/agentsflex/Main.java new file mode 100644 index 0000000..d9109c5 --- /dev/null +++ b/agents-flex-samples/src/main/java/com/agentsflex/Main.java @@ -0,0 +1,7 @@ +package com.agentsflex; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/agents-flex-test/pom.xml b/agents-flex-test/pom.xml new file mode 100644 index 0000000..50afe04 --- /dev/null +++ b/agents-flex-test/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + com.agentsflex + parent + 1.0-SNAPSHOT + + + agents-flex-test + + + 8 + 8 + UTF-8 + + + \ No newline at end of file diff --git a/agents-flex-test/src/main/java/com/agentsflex/Main.java b/agents-flex-test/src/main/java/com/agentsflex/Main.java new file mode 100644 index 0000000..d9109c5 --- /dev/null +++ b/agents-flex-test/src/main/java/com/agentsflex/Main.java @@ -0,0 +1,7 @@ +package com.agentsflex; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/agents-flex-vector/pom.xml b/agents-flex-vector/pom.xml new file mode 100644 index 0000000..f7d8bb0 --- /dev/null +++ b/agents-flex-vector/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + com.agentsflex + parent + 1.0-SNAPSHOT + + + agents-flex-vector + + + 8 + 8 + UTF-8 + + + diff --git a/agents-flex-vector/src/main/java/com/agentsflex/Main.java b/agents-flex-vector/src/main/java/com/agentsflex/Main.java new file mode 100644 index 0000000..d9109c5 --- /dev/null +++ b/agents-flex-vector/src/main/java/com/agentsflex/Main.java @@ -0,0 +1,7 @@ +package com.agentsflex; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/changes.md b/changes.md new file mode 100644 index 0000000..ee48376 --- /dev/null +++ b/changes.md @@ -0,0 +1 @@ +# Agents-Flex ChangeLog diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..030f1de --- /dev/null +++ b/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + com.agentsflex + parent + 1.0-SNAPSHOT + pom + + agents-flex-core + agents-flex-test + agents-flex-samples + agents-flex-llm + agents-flex-vector + + + + 8 + 8 + UTF-8 + 4.13.2 + + + + + + + junit + junit + ${junit.version} + + + + + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ed9e17d --- /dev/null +++ b/readme.md @@ -0,0 +1,49 @@ +

English | 简体中文

+ + + +# Agents-Flex is an elegant LLM Application Framework like LangChain with Java. + + +## Hello Word + +use OpenAi LLM: + +```java + public static void main(String[] args) throws InterruptedException { + + OpenAiConfig config = new OpenAiConfig(); + config.setApiKey("sk-rts5NF6n*******"); + + Llm llm = new OpenAiLlm(config); + + Prompt prompt = new SimplePrompt("Please write a story about a little rabbit defeating a big bad wolf"); + llm.chat(prompt, (llmInstance, message) -> { + System.out.println("--->" + message.getContent()); + }); + + Thread.sleep(10000); +} +``` + +use SparkAi LLM: + +```java + public static void main(String[] args) throws InterruptedException { + + SparkLlmConfig config = new SparkLlmConfig(); + config.setAppId("****"); + config.setApiKey("****"); + config.setApiSecret("****"); + + Llm llm = new SparkLlm(config); + + Prompt prompt = new SimplePrompt("Please write a story about a little rabbit defeating a big bad wolf"); + llm.chat(prompt, (llmInstance, message) -> { + System.out.println("--->" + message.getContent()); + }); + + Thread.sleep(10000); +} +``` + diff --git a/readme_zh.md b/readme_zh.md new file mode 100644 index 0000000..0734d18 --- /dev/null +++ b/readme_zh.md @@ -0,0 +1,49 @@ +

English | 简体中文

+ + + + +# Agents-Flex: 一个优雅的 LLM(大语言模型) 应用开发 + + +## Hello Word + +使用 OpenAi 大语言模型: + +```java + public static void main(String[] args) throws InterruptedException { + + OpenAiConfig config = new OpenAiConfig(); + config.setApiKey("sk-rts5NF6n*******"); + + Llm llm = new OpenAiLlm(config); + + Prompt prompt = new SimplePrompt("请写一个关于小兔子战胜大灰狼的故事。"); + llm.chat(prompt, (llmInstance, message) -> { + System.out.println("--->" + message.getContent()); + }); + + Thread.sleep(10000); +} +``` + +使用 “讯飞星火” 大语言模型: + +```java + public static void main(String[] args) throws InterruptedException { + + SparkLlmConfig config = new SparkLlmConfig(); + config.setAppId("****"); + config.setApiKey("****"); + config.setApiSecret("****"); + + Llm llm = new SparkLlm(config); + + Prompt prompt = new SimplePrompt("请写一个关于小兔子战胜大灰狼的故事。"); + llm.chat(prompt, (llmInstance, message) -> { + System.out.println("--->" + message.getContent()); + }); + + Thread.sleep(10000); +} +```