mirror of
https://gitee.com/agents-flex/agents-flex.git
synced 2024-11-29 18:38:17 +08:00
init
This commit is contained in:
commit
3c69d93626
17
.editorconfig
Normal file
17
.editorconfig
Normal file
@ -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
|
||||
|
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
@ -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
|
201
LICENSE
Normal file
201
LICENSE
Normal file
@ -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.
|
40
agents-flex-core/pom.xml
Normal file
40
agents-flex-core/pom.xml
Normal file
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.agentsflex</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>agents-flex-core</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<okhttp.version>4.9.3</okhttp.version>
|
||||
<fastjson.version>2.0.45</fastjson.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp-sse</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
7
agents-flex-core/src/main/java/com/agentsflex/Main.java
Normal file
7
agents-flex-core/src/main/java/com/agentsflex/Main.java
Normal file
@ -0,0 +1,7 @@
|
||||
package com.agentsflex;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello world!");
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.agentsflex.agent;
|
||||
|
||||
public class Agent {
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.agentsflex.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD})
|
||||
public @interface FunctionDef {
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.agentsflex.chain;
|
||||
|
||||
public class Chain {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.agentsflex.chain;
|
||||
|
||||
public class Interceptor {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.agentsflex.chain;
|
||||
|
||||
public class Invocation {
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.agentsflex.chain;
|
||||
|
||||
public class Invoker {
|
||||
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.agentsflex.client;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface LlmClient {
|
||||
|
||||
void start(String url, Map<String, String> headers, String payload, LlmClientListener listener);
|
||||
|
||||
void stop();
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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<String, String> headers, String payload, LlmClientListener listener) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
|
||||
}
|
||||
}
|
@ -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<String, String> 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);
|
||||
}
|
||||
}
|
@ -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<String, String> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.agentsflex.llm;
|
||||
|
||||
public abstract class BaseLlm<T extends LlmConfig> extends Llm{
|
||||
|
||||
protected T config;
|
||||
|
||||
public BaseLlm(T config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public T getConfig() {
|
||||
return config;
|
||||
}
|
||||
}
|
@ -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){}
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.agentsflex.llm;
|
||||
|
||||
public interface EmbeddingsListener {
|
||||
}
|
11
agents-flex-core/src/main/java/com/agentsflex/llm/Llm.java
Normal file
11
agents-flex-core/src/main/java/com/agentsflex/llm/Llm.java
Normal file
@ -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);
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.agentsflex.llm;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class LlmConfig implements Serializable {
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.agentsflex.message;
|
||||
|
||||
public class FunctionMessage extends Message{
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.agentsflex.message;
|
||||
|
||||
public class HumanMessage extends Message{
|
||||
|
||||
public HumanMessage(String content) {
|
||||
super();
|
||||
setContent(content);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.agentsflex.message;
|
||||
|
||||
public class SystemMessage extends Message {
|
||||
|
||||
|
||||
public SystemMessage(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<Message> messages = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
public void addMessage(Message message) {
|
||||
messages.add(message);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Message> toMessages() {
|
||||
return messages;
|
||||
}
|
||||
}
|
@ -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<Message> toMessages();
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.agentsflex.prompt;
|
||||
|
||||
public class PromptTemplate {
|
||||
|
||||
}
|
@ -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<Message> toMessages() {
|
||||
return Arrays.asList(new HumanMessage(content));
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.agentsflex.text;
|
||||
|
||||
public interface Loader {
|
||||
Text load();
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.agentsflex.text;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Splitter {
|
||||
|
||||
List<Text> split(Text text);
|
||||
}
|
15
agents-flex-core/src/main/java/com/agentsflex/text/Text.java
Normal file
15
agents-flex-core/src/main/java/com/agentsflex/text/Text.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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<Text> split(Text text) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -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<String, Object> 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<String, Object> getMetadataMap() {
|
||||
return metadataMap;
|
||||
}
|
||||
|
||||
public void setMetadataMap(Map<String, Object> metadataMap) {
|
||||
this.metadataMap = metadataMap;
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.agentsflex.util;
|
||||
|
||||
public class OKHttpUtil {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.agentsflex.util;
|
||||
|
||||
public class StringUtil {
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.agentsflex.vector;
|
||||
|
||||
|
||||
public interface Retriever {
|
||||
VectorData retrieve(String prompt);
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.agentsflex.vector;
|
||||
|
||||
public class RetrieverOptions {
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.agentsflex.vector;
|
||||
|
||||
public interface VectorStorage {
|
||||
Retriever getRetrieve(RetrieverOptions options);
|
||||
}
|
28
agents-flex-llm/agents-flex-llm-openai/pom.xml
Normal file
28
agents-flex-llm/agents-flex-llm-openai/pom.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.agentsflex</groupId>
|
||||
<artifactId>agents-flex-llm</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>agents-flex-llm-openai</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.agentsflex</groupId>
|
||||
<artifactId>agents-flex-core</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<Message> 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<Map<String, String>> messageArray = new ArrayList<>();
|
||||
messages.forEach(message -> {
|
||||
Map<String, String> 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<OpenAiConfig> {
|
||||
|
||||
public OpenAiLlm(OpenAiConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public LlmClient chat(Prompt prompt, ChatListener listener) {
|
||||
LlmClient llmClient = new SseClient();
|
||||
Map<String, String> 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
35
agents-flex-llm/agents-flex-llm-spark/pom.xml
Normal file
35
agents-flex-llm/agents-flex-llm-spark/pom.xml
Normal file
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.agentsflex</groupId>
|
||||
<artifactId>agents-flex-llm</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>agents-flex-llm-spark</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.agentsflex</groupId>
|
||||
<artifactId>agents-flex-core</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -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<SparkLlmConfig> {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<Message> 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<Map<String, String>> messageArray = new ArrayList<>();
|
||||
messages.forEach(message -> {
|
||||
Map<String, String> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
25
agents-flex-llm/pom.xml
Normal file
25
agents-flex-llm/pom.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.agentsflex</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>agents-flex-llm</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>agents-flex-llm-openai</module>
|
||||
<module>agents-flex-llm-spark</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
20
agents-flex-samples/pom.xml
Normal file
20
agents-flex-samples/pom.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.agentsflex</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>agents-flex-samples</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -0,0 +1,7 @@
|
||||
package com.agentsflex;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello world!");
|
||||
}
|
||||
}
|
20
agents-flex-test/pom.xml
Normal file
20
agents-flex-test/pom.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.agentsflex</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>agents-flex-test</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
7
agents-flex-test/src/main/java/com/agentsflex/Main.java
Normal file
7
agents-flex-test/src/main/java/com/agentsflex/Main.java
Normal file
@ -0,0 +1,7 @@
|
||||
package com.agentsflex;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello world!");
|
||||
}
|
||||
}
|
20
agents-flex-vector/pom.xml
Normal file
20
agents-flex-vector/pom.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.agentsflex</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>agents-flex-vector</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -0,0 +1,7 @@
|
||||
package com.agentsflex;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello world!");
|
||||
}
|
||||
}
|
1
changes.md
Normal file
1
changes.md
Normal file
@ -0,0 +1 @@
|
||||
# Agents-Flex ChangeLog
|
37
pom.xml
Normal file
37
pom.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.agentsflex</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>agents-flex-core</module>
|
||||
<module>agents-flex-test</module>
|
||||
<module>agents-flex-samples</module>
|
||||
<module>agents-flex-llm</module>
|
||||
<module>agents-flex-vector</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<junit.version>4.13.2</junit.version>
|
||||
</properties>
|
||||
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
</project>
|
49
readme.md
Normal file
49
readme.md
Normal file
@ -0,0 +1,49 @@
|
||||
<h4 align="right"><strong>English</strong> | <a href="./readme_zh.md">简体中文</a></h4>
|
||||
|
||||
|
||||
|
||||
# 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);
|
||||
}
|
||||
```
|
||||
|
49
readme_zh.md
Normal file
49
readme_zh.md
Normal file
@ -0,0 +1,49 @@
|
||||
<h4 align="right"><a href="./readme.md">English</a> | <strong>简体中文</strong></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
# 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);
|
||||
}
|
||||
```
|
Loading…
Reference in New Issue
Block a user