io.github.imfangs
diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/java/com/xxl/job/executor/jobhandler/AIXxlJob.java b/xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/java/com/xxl/job/executor/jobhandler/AIXxlJob.java
index 1485b30b..06c39f66 100644
--- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/java/com/xxl/job/executor/jobhandler/AIXxlJob.java
+++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/java/com/xxl/job/executor/jobhandler/AIXxlJob.java
@@ -15,6 +15,7 @@ import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.api.OllamaChatOptions;
+import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.stereotype.Component;
import java.util.HashMap;
@@ -32,6 +33,8 @@ public class AIXxlJob {
@Resource
private OllamaChatModel ollamaChatModel;
+ @Resource
+ private OpenAiChatModel openAiChatModel;
/**
* 1、ollama Chat任务
@@ -252,4 +255,91 @@ public class AIXxlJob {
}
+ // --------------------------------- openclaw ---------------------------------
+
+ /**
+ * 3、openclaw 任务
+ *
+ * 参数示例:格式见 OpenclawParam
+ *
+ * {
+ * "input": "{输入信息,必填信息}",
+ * "prompt": "{模型prompt,可选信息}"
+ * }
+ *
+ */
+ @XxlJob("openClawJobHandler")
+ public void openClawJobHandler() {
+
+ // param
+ String param = XxlJobHelper.getJobParam();
+ if (param == null || param.trim().isEmpty()) {
+ XxlJobHelper.log("param is empty.");
+
+ XxlJobHelper.handleFail();
+ return;
+ }
+
+ // openclaw param
+ OpenClawParam openClawParam = null;
+ try {
+ openClawParam = GsonTool.fromJson(param, OpenClawParam.class);
+ if (openClawParam.getPrompt()==null || openClawParam.getPrompt().isBlank()) {
+ openClawParam.setPrompt("你是一个出游助手,擅长做旅游规划");
+ }
+ if (openClawParam.getInput() == null || openClawParam.getInput().isBlank()) {
+ XxlJobHelper.log("input is empty.");
+
+ XxlJobHelper.handleFail();
+ return;
+ }
+ } catch (Exception e) {
+ XxlJobHelper.log(new RuntimeException("OpenclawParam parse error", e));
+ XxlJobHelper.handleFail();
+ return;
+ }
+
+ // input
+ XxlJobHelper.log("
【Input】: " + openClawParam.getInput()+ "
");
+
+ // build chat-client
+ ChatClient openclawChatClient = ChatClient
+ .builder(openAiChatModel)
+ .defaultAdvisors(MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build())
+ .defaultAdvisors(SimpleLoggerAdvisor.builder().build())
+ .build();
+
+ // call opencalw
+ String response = openclawChatClient
+ .prompt(openClawParam.getPrompt())
+ .user(openClawParam.getInput())
+ .call()
+ .content();
+
+ XxlJobHelper.log("
【Output】: " + response + "
");
+
+ }
+
+ private static class OpenClawParam {
+ private String input;
+ private String prompt;
+
+ public String getInput() {
+ return input;
+ }
+
+ public void setInput(String input) {
+ this.input = input;
+ }
+
+ public String getPrompt() {
+ return prompt;
+ }
+
+ public void setPrompt(String prompt) {
+ this.prompt = prompt;
+ }
+ }
+
+
}
diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/resources/application.properties b/xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/resources/application.properties
index 2a95e692..361d7c27 100644
--- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/resources/application.properties
+++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/resources/application.properties
@@ -35,6 +35,9 @@ xxl.job.executor.excludedpackage=
### ollama
-spring.ai.model.chat=ollama
-### ollama url
spring.ai.ollama.base-url=http://localhost:11434
+
+### openai (for openclaw)
+spring.ai.openai.base-url=http://127.0.0.1:18789
+spring.ai.openai.api-key=xxxxxx
+
diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/test/java/com/xxl/job/executor/test/openclaw/OpenClawTest.java b/xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/test/java/com/xxl/job/executor/test/openclaw/OpenClawTest.java
new file mode 100644
index 00000000..e031ba82
--- /dev/null
+++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/test/java/com/xxl/job/executor/test/openclaw/OpenClawTest.java
@@ -0,0 +1,95 @@
+package com.xxl.job.executor.test.openclaw;
+
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
+import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
+import org.springframework.ai.chat.memory.MessageWindowChatMemory;
+import org.springframework.ai.openai.OpenAiChatModel;
+import org.springframework.boot.test.context.SpringBootTest;
+import reactor.core.publisher.Flux;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@SpringBootTest
+public class OpenClawTest {
+ private static final Logger logger = LoggerFactory.getLogger(OpenClawTest.class);
+
+ @Resource
+ private OpenAiChatModel openAiChatModel;
+
+ /*ChatModel chatModel = OpenAiChatModel
+ .builder()
+ .openAiApi(OpenAiApi
+ .builder()
+ .baseUrl(baseUrl)
+ .apiKey( token)
+ .webClientBuilder(WebClient.builder().clientConnector(
+ new ReactorClientHttpConnector(
+ HttpClient.create()
+ .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30 * 1000)
+ .responseTimeout(Duration.ofMillis(30 * 1000))
+ )
+ ))
+ .build())
+ .build();*/
+
+ @Test
+ public void test() throws Exception {
+
+ String prompt = "你是一个出游助手,擅长做旅游规划";
+ String input = "查看下上海今天得天气,给出出游建议";
+
+ // ChatClient
+ ChatClient chatClient = ChatClient
+ .builder(openAiChatModel)
+ .defaultAdvisors(MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build())
+ .defaultAdvisors(SimpleLoggerAdvisor.builder().build())
+ .build();
+
+ // Call LLM: 同步输出
+ String response = chatClient
+ .prompt(prompt)
+ .user(input)
+ .call()
+ .content();
+
+ logger.info("Input: {}", input);
+ logger.info("Output: {}", response);
+ }
+
+ @Test
+ public void test2() throws Exception {
+
+ String prompt = "你是一个出游助手,擅长做旅游规划";
+ String input = "查看下上海今天得天气,给出出游建议";
+
+ // ChatClient
+ ChatClient chatClient = ChatClient
+ .builder(openAiChatModel)
+ .defaultAdvisors(MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build())
+ .defaultAdvisors(SimpleLoggerAdvisor.builder().build())
+ .build();
+
+ // Call LLM: 流式输出
+ Flux flux = chatClient
+ .prompt(prompt)
+ .user(input)
+ .user(user -> user.text(input).params(Map.of("stream", true)))
+ .stream()
+ .content();
+
+ flux.subscribe(
+ data -> System.out.println("Received: " + data), // onNext 处理
+ error -> System.err.println("Error: " + error), // onError 处理
+ () -> System.out.println("Completed") // onComplete 处理
+ );
+
+ TimeUnit.SECONDS.sleep(30);
+ }
+
+}