diff --git a/jcommon/ai/gpt/pom.xml b/jcommon/ai/gpt/pom.xml
new file mode 100644
index 000000000..1e751705d
--- /dev/null
+++ b/jcommon/ai/gpt/pom.xml
@@ -0,0 +1,54 @@
+
+
+ 4.0.0
+
+ run.mone
+ ai
+ 1.4-jdk20-SNAPSHOT
+
+
+ gpt
+ 1.5-jdk8-SNAPSHOT
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.10.0
+
+
+
+
+
+
+
+
+
+ maven-compiler-plugin
+ 3.11.0
+
+
+ 8
+ true
+ UTF-8
+
+ ${project.basedir}/src/main/java
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/GptClient.java b/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/GptClient.java
new file mode 100644
index 000000000..49eb76c8a
--- /dev/null
+++ b/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/GptClient.java
@@ -0,0 +1,54 @@
+package run.mone.ai.gpt;
+
+import com.google.gson.Gson;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import run.mone.ai.gpt.bo.ResponsePayload;
+import run.mone.ai.gpt.bo.multiModal.GptVisionRequest;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+@Data
+@Slf4j
+public class GptClient {
+
+ private static Gson gson = new Gson();
+
+ public ResponsePayload visionCall(String url, String token, GptVisionRequest gptVisionRequest) {
+ return baseCall(url, token, gson.toJson(gptVisionRequest));
+ }
+
+ private ResponsePayload baseCall(String url, String token, String bodyStr) {
+ OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.MINUTES).build();
+ MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
+ RequestBody body = RequestBody.create(mediaType, bodyStr);
+ Request request = new Request.Builder()
+ .url(url)
+ .post(body)
+ .addHeader("api-key", token)
+ .addHeader("Content-Type", "application/json; charset=utf-8")
+ .build();
+
+ try (Response response = client.newCall(request).execute()) {
+ if (response.code() == 429) {
+ ResponsePayload res = new ResponsePayload();
+ ResponsePayload.Error error = new ResponsePayload.Error();
+ error.setCode("429");
+ error.setMessage("被gpt限流了");
+ res.setError(error);
+ return res;
+ }
+ if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
+ // Handle the response
+ String res = response.body().string();
+ log.info("claude3 res:{}", res);
+ return new Gson().fromJson(res, ResponsePayload.class);
+ } catch (Throwable e) {
+ log.error(e.getMessage(), e);
+ }
+ return null;
+ }
+
+}
diff --git a/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/ResponsePayload.java b/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/ResponsePayload.java
new file mode 100644
index 000000000..1aabe2c5d
--- /dev/null
+++ b/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/ResponsePayload.java
@@ -0,0 +1,87 @@
+package run.mone.ai.gpt.bo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ResponsePayload {
+ private List choices;
+ private long created;
+ private String id;
+ private String model;
+ private String object;
+ private List prompt_filter_results;
+ private String system_fingerprint;
+ private Usage usage;
+ private Error error;
+
+ @Data
+ public static class Error {
+ private String code;
+ private String message;
+ }
+
+ @Data
+ public static class Choice {
+ private ContentFilterResults content_filter_results;
+ private String finish_reason;
+ private int index;
+ private Message message;
+
+
+ @Data
+ public static class ContentFilterResults {
+ private FilterResult hate;
+ private FilterResult self_harm;
+ private FilterResult sexual;
+ private FilterResult violence;
+
+ }
+
+ @Data
+ public static class FilterResult {
+ private boolean filtered;
+ private String severity;
+
+ }
+
+ @Data
+ public static class Message {
+ private String content;
+ private String role;
+
+ }
+ }
+
+ @Data
+ public static class PromptFilterResult {
+ private int prompt_index;
+ private ContentFilterResult content_filter_result;
+
+
+ @Data
+ public static class ContentFilterResult {
+ private JailbreakResult jailbreak;
+ private Choice.FilterResult sexual;
+ private Choice.FilterResult violence;
+ private Choice.FilterResult hate;
+ private Choice.FilterResult self_harm;
+
+
+ @Data
+ public static class JailbreakResult {
+ private boolean filtered;
+ private boolean detected;
+
+ }
+ }
+ }
+
+ @Data
+ public static class Usage {
+ private int completion_tokens;
+ private int prompt_tokens;
+ private int total_tokens;
+ }
+}
diff --git a/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/multiModal/GptVisionContent.java b/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/multiModal/GptVisionContent.java
new file mode 100644
index 000000000..36343a787
--- /dev/null
+++ b/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/multiModal/GptVisionContent.java
@@ -0,0 +1,22 @@
+package run.mone.ai.gpt.bo.multiModal;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+@Builder
+public class GptVisionContent {
+
+ @SerializedName("type")
+ private String type;
+
+ @SerializedName("text")
+ private String text;
+
+ @SerializedName("image_url")
+ private Map imageUrl;
+
+}
diff --git a/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/multiModal/GptVisionMsg.java b/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/multiModal/GptVisionMsg.java
new file mode 100644
index 000000000..6787b3146
--- /dev/null
+++ b/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/multiModal/GptVisionMsg.java
@@ -0,0 +1,23 @@
+package run.mone.ai.gpt.bo.multiModal;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author goodjava@qq.com
+ * @date 2023/5/25 14:16
+ */
+@Data
+@Builder
+public class GptVisionMsg implements Serializable {
+
+ @SerializedName("role")
+ private String role;
+
+ @SerializedName("content")
+ private List content;
+}
diff --git a/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/multiModal/GptVisionRequest.java b/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/multiModal/GptVisionRequest.java
new file mode 100644
index 000000000..fab363962
--- /dev/null
+++ b/jcommon/ai/gpt/src/main/java/run/mone/ai/gpt/bo/multiModal/GptVisionRequest.java
@@ -0,0 +1,46 @@
+package run.mone.ai.gpt.bo.multiModal;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author goodjava@qq.com
+ * @date 2024/4/9 16:36
+ */
+@Data
+@Builder
+public class GptVisionRequest {
+
+ @SerializedName("model")
+ private String model;
+
+ @SerializedName("temperature")
+ private double temperature;
+
+ @SerializedName("n")
+ @Builder.Default
+ private int n = 1;
+
+ @SerializedName("stream")
+ private boolean stream;
+
+ @SerializedName("top_p")
+ private double topP;
+
+ @SerializedName("max_tokens")
+ private int maxTokens;
+
+ @SerializedName("presence_penalty")
+ private double presencePenalty;
+
+ @SerializedName("frequency_penalty")
+ private double frequencyPenalty;
+
+ @SerializedName("messages")
+ private List messages;
+
+
+}
diff --git a/jcommon/ai/pom.xml b/jcommon/ai/pom.xml
index 41a73b29f..748017515 100644
--- a/jcommon/ai/pom.xml
+++ b/jcommon/ai/pom.xml
@@ -18,6 +18,7 @@
aws
minimax
bytedance
+ gpt