This is an automated email from the ASF dual-hosted git repository. jamesnetherton pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-quarkus-examples.git
commit f6c0c84c430bd02b7af1ee4341db40dad5d8067c Author: Alexandre Gallice <[email protected]> AuthorDate: Wed Jan 21 15:40:38 2026 +0100 data-extract: improve date and name handling --- .../extraction/CustomPojoExtractionService.java | 29 ++++++++++++++-------- .../java/org/acme/extraction/DataExtractAgent.java | 5 ++-- .../test/java/org/acme/extraction/RouteTest.java | 6 ++--- ..._chat-18cda03a-bbe5-48d0-a35b-262b36c541a7.json | 24 ++++++++++++++++++ ..._chat-4b63856f-cac5-4bc1-b66a-d01255ac40e0.json | 24 ------------------ ..._chat-ae3edfa4-a510-4121-9eb2-6051c3072e69.json | 24 ++++++++++++++++++ ...chat-d0af43a7-81b5-49cd-8624-a4c222c5eb4b.json} | 10 ++++---- ..._chat-e8f3defd-bdcb-47f4-8782-687fd3cae6d1.json | 24 ------------------ 8 files changed, 77 insertions(+), 69 deletions(-) diff --git a/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoExtractionService.java b/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoExtractionService.java index 5a8a7994..c153d19b 100644 --- a/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoExtractionService.java +++ b/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoExtractionService.java @@ -16,7 +16,7 @@ */ package org.acme.extraction; -import java.time.LocalDate; +import java.time.Month; import java.util.Locale; import com.fasterxml.jackson.annotation.JsonProperty; @@ -24,42 +24,51 @@ import dev.langchain4j.service.UserMessage; import dev.langchain4j.service.V; import io.quarkus.runtime.annotations.RegisterForReflection; -@RegisterForReflection(targets = LocalDate.class) +@RegisterForReflection public interface CustomPojoExtractionService { + @RegisterForReflection(registerFullHierarchy = true) class CustomPojo { @JsonProperty(required = true) public boolean customerSatisfied; @JsonProperty(required = true) public String customerName; @JsonProperty(required = true) - public LocalDate customerBirthday; + public Birthday customerBirthday; @JsonProperty(required = true) public String summary; private final static String FORMAT = "\n{\n" + "\t\"customerSatisfied\": \"%s\",\n" + "\t\"customerName\": \"%s\",\n" - + "\t\"customerBirthday\": \"%td %tB %tY\",\n" + + "\t\"customerBirthday\": \"%02d %s %04d\",\n" + "\t\"summary\": \"%s\"\n" + "}\n"; public String toString() { - return String.format(Locale.US, FORMAT, this.customerSatisfied, this.customerName, this.customerBirthday, - this.customerBirthday, this.customerBirthday, this.summary); + return String.format(Locale.US, FORMAT, this.customerSatisfied, this.customerName, this.customerBirthday.day, + Month.of(this.customerBirthday.month), this.customerBirthday.year, this.summary); } } + class Birthday { + @JsonProperty(required = true) + public int year; + @JsonProperty(required = true) + public short month; + @JsonProperty(required = true) + public short day; + } + String CUSTOM_POJO_EXTRACT_PROMPT = "Extract information about a customer from the transcript delimited by triple backticks: ```{{text}}```." - + "The customerBirthday field should be formatted as {{dateFormat}}." + + "The customerName field should be formatted as FIRSTNAME LASTNAME, for instance Isaac Newton." + "The summary field should concisely relate the customer main ask." + "Source any extracted field values from what is explicitly mentioned in the transcript." + "Extracted field values should be as accurate as possible."; /** - * The text and dateFormat parameters of this method are automatically injected as {{text}} & {{dateFormat}} in the - * CUSTOM_POJO_EXTRACT_PROMPT. + * The text parameter of this method is automatically injected as {{text}} in the CUSTOM_POJO_EXTRACT_PROMPT. */ @UserMessage(CUSTOM_POJO_EXTRACT_PROMPT) - CustomPojo extractFromText(@V("text") String text, @V("dateFormat") String dateFormat); + CustomPojo extractFromText(@V("text") String text); } diff --git a/data-extract-langchain4j/src/main/java/org/acme/extraction/DataExtractAgent.java b/data-extract-langchain4j/src/main/java/org/acme/extraction/DataExtractAgent.java index c084dd6a..b4de066f 100644 --- a/data-extract-langchain4j/src/main/java/org/acme/extraction/DataExtractAgent.java +++ b/data-extract-langchain4j/src/main/java/org/acme/extraction/DataExtractAgent.java @@ -27,7 +27,6 @@ import org.apache.camel.component.langchain4j.agent.api.AiAgentBody; * Custom agent to extract data from text. */ public class DataExtractAgent implements Agent { - public static final String DATE_FORMAT = "YYYY-MM-DD"; private final AgentConfiguration configuration; private final CustomPojoStore pojoStore; @@ -42,8 +41,8 @@ public class DataExtractAgent implements Agent { * Returns a JSON representation of a {@link CustomPojo}. */ @Override - public String chat(AiAgentBody aiAgentBody, ToolProvider toolProvider) { - CustomPojo response = createService(toolProvider).extractFromText(aiAgentBody.getUserMessage(), DATE_FORMAT); + public String chat(AiAgentBody<?> aiAgentBody, ToolProvider toolProvider) { + CustomPojo response = createService(toolProvider).extractFromText(aiAgentBody.getUserMessage()); // Store extracted CustomPojoExtractionService.CustomPojos objects into the CustomPojoStore for later inspection pojoStore.addPojo(response); diff --git a/data-extract-langchain4j/src/test/java/org/acme/extraction/RouteTest.java b/data-extract-langchain4j/src/test/java/org/acme/extraction/RouteTest.java index fe466c44..913a34fe 100644 --- a/data-extract-langchain4j/src/test/java/org/acme/extraction/RouteTest.java +++ b/data-extract-langchain4j/src/test/java/org/acme/extraction/RouteTest.java @@ -67,17 +67,17 @@ public class RouteTest { // Assert values of the first extracted POJO .body("pojos[0].customerSatisfied", is("true")) .body("pojos[0].customerName", is("Sarah London")) - .body("pojos[0].customerBirthday", is("10 July 1986")) + .body("pojos[0].customerBirthday", is("10 JULY 1986")) .body("pojos[0].summary", not(empty())) // Assert values of the second extracted POJO .body("pojos[1].customerSatisfied", is("false")) .body("pojos[1].customerName", is("John Doe")) - .body("pojos[1].customerBirthday", is("01 November 2001")) + .body("pojos[1].customerBirthday", is("01 NOVEMBER 2001")) .body("pojos[1].summary", not(empty())) // Assert values of the third extracted POJO .body("pojos[2].customerSatisfied", is("true")) .body("pojos[2].customerName", is("Kate Boss")) - .body("pojos[2].customerBirthday", is("13 August 1999")) + .body("pojos[2].customerBirthday", is("13 AUGUST 1999")) .body("pojos[2].summary", not(empty())); } diff --git a/data-extract-langchain4j/src/test/resources/mappings/api_chat-18cda03a-bbe5-48d0-a35b-262b36c541a7.json b/data-extract-langchain4j/src/test/resources/mappings/api_chat-18cda03a-bbe5-48d0-a35b-262b36c541a7.json new file mode 100644 index 00000000..2e325121 --- /dev/null +++ b/data-extract-langchain4j/src/test/resources/mappings/api_chat-18cda03a-bbe5-48d0-a35b-262b36c541a7.json @@ -0,0 +1,24 @@ +{ + "id" : "18cda03a-bbe5-48d0-a35b-262b36c541a7", + "name" : "api_chat", + "request" : { + "url" : "/api/chat", + "method" : "POST", + "bodyPatterns" : [ { + "equalToJson" : "{\n \"model\" : \"granite4:3b-h\",\n \"messages\" : [ {\n \"role\" : \"user\",\n \"content\" : \"Extract information about a customer from the transcript delimited by triple backticks: ```Operator: Hello, how may I help you ?\\nCustomer: Hello, I'm calling because I need to declare an accident on my main vehicle.\\nOperator: Ok, can you please give me your name ?\\nCustomer: My name is Sarah London.\\nOperator: Could you please give me your birth date ?\\nC [...] + "ignoreArrayOrder" : true, + "ignoreExtraElements" : true + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"model\":\"granite4:3b-h\",\"created_at\":\"2026-01-20T14:46:58.833215508Z\",\"message\":{\"role\":\"assistant\",\"content\":\"{\\n \\\"customerSatisfied\\\": true,\\n \\\"customerName\\\": \\\"Sarah London\\\",\\n \\\"customerBirthday\\\": {\\n \\\"year\\\": 1986,\\n \\\"month\\\": 7,\\n \\\"day\\\": 10\\n },\\n \\\"summary\\\": \\\"The customer, Sarah London, needed to declare an accident on her main vehicle and was informed that all expenses linked to the [...] + "headers" : { + "Date" : "Tue, 20 Jan 2026 14:46:58 GMT", + "Content-Type" : "application/json; charset=utf-8" + } + }, + "uuid" : "18cda03a-bbe5-48d0-a35b-262b36c541a7", + "persistent" : true, + "insertionIndex" : 6 +} \ No newline at end of file diff --git a/data-extract-langchain4j/src/test/resources/mappings/api_chat-4b63856f-cac5-4bc1-b66a-d01255ac40e0.json b/data-extract-langchain4j/src/test/resources/mappings/api_chat-4b63856f-cac5-4bc1-b66a-d01255ac40e0.json deleted file mode 100644 index 12285be4..00000000 --- a/data-extract-langchain4j/src/test/resources/mappings/api_chat-4b63856f-cac5-4bc1-b66a-d01255ac40e0.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "id" : "4b63856f-cac5-4bc1-b66a-d01255ac40e0", - "name" : "api_chat", - "request" : { - "url" : "/api/chat", - "method" : "POST", - "bodyPatterns" : [ { - "equalToJson" : "{\n \"model\" : \"granite4:3b-h\",\n \"messages\" : [ {\n \"role\" : \"user\",\n \"content\" : \"Extract information about a customer from the transcript delimited by triple backticks: ```Operator: Hello, how may I help you ?\\nCustomer: Hello, I'm calling because I need to declare an accident on my main vehicle.\\nOperator: Ok, can you please give me your name ?\\nCustomer: My name is Sarah London.\\nOperator: Could you please give me your birth date ?\\nC [...] - "ignoreArrayOrder" : true, - "ignoreExtraElements" : true - } ] - }, - "response" : { - "status" : 200, - "body" : "{\"model\":\"granite4:3b-h\",\"created_at\":\"2026-01-15T15:03:26.59496985Z\",\"message\":{\"role\":\"assistant\",\"content\":\"{\\n \\\"customerSatisfied\\\": true,\\n \\\"customerName\\\": \\\"Sarah London\\\",\\n \\\"customerBirthday\\\": {\\\"year\\\": 1986, \\\"month\\\": 7, \\\"day\\\": 10},\\n \\\"summary\\\": \\\"The customer, Sarah London, called to declare an accident on her main vehicle. The operator confirmed that all expenses linked to the accident would be [...] - "headers" : { - "Date" : "Thu, 15 Jan 2026 15:03:26 GMT", - "Content-Type" : "application/json; charset=utf-8" - } - }, - "uuid" : "4b63856f-cac5-4bc1-b66a-d01255ac40e0", - "persistent" : true, - "insertionIndex" : 6 -} \ No newline at end of file diff --git a/data-extract-langchain4j/src/test/resources/mappings/api_chat-ae3edfa4-a510-4121-9eb2-6051c3072e69.json b/data-extract-langchain4j/src/test/resources/mappings/api_chat-ae3edfa4-a510-4121-9eb2-6051c3072e69.json new file mode 100644 index 00000000..4a9422da --- /dev/null +++ b/data-extract-langchain4j/src/test/resources/mappings/api_chat-ae3edfa4-a510-4121-9eb2-6051c3072e69.json @@ -0,0 +1,24 @@ +{ + "id" : "ae3edfa4-a510-4121-9eb2-6051c3072e69", + "name" : "api_chat", + "request" : { + "url" : "/api/chat", + "method" : "POST", + "bodyPatterns" : [ { + "equalToJson" : "{\n \"model\" : \"granite4:3b-h\",\n \"messages\" : [ {\n \"role\" : \"user\",\n \"content\" : \"Extract information about a customer from the transcript delimited by triple backticks: ```Operator: Hello, how may I help you?\\nCustomer: Hello, I am currently at the police station because I've got an accident. The police would need a proof that I have an insurance. Could you please help me?\\nOperator: Sure, could you please remind me your name and birth dat [...] + "ignoreArrayOrder" : true, + "ignoreExtraElements" : true + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"model\":\"granite4:3b-h\",\"created_at\":\"2026-01-20T14:47:27.992920518Z\",\"message\":{\"role\":\"assistant\",\"content\":\"{\\n \\\"customerSatisfied\\\": true,\\n \\\"customerName\\\": \\\"Kate Boss\\\",\\n \\\"customerBirthday\\\": {\\n \\\"year\\\": 1999,\\n \\\"month\\\": 8,\\n \\\"day\\\": 13\\n },\\n \\\"summary\\\": \\\"The customer, Kate Boss, had an accident and needed proof of insurance from the police station. The operator helped by verifying [...] + "headers" : { + "Date" : "Tue, 20 Jan 2026 14:47:27 GMT", + "Content-Type" : "application/json; charset=utf-8" + } + }, + "uuid" : "ae3edfa4-a510-4121-9eb2-6051c3072e69", + "persistent" : true, + "insertionIndex" : 4 +} \ No newline at end of file diff --git a/data-extract-langchain4j/src/test/resources/mappings/api_chat-be38bae8-7817-4141-8b20-2cff30446e53.json b/data-extract-langchain4j/src/test/resources/mappings/api_chat-d0af43a7-81b5-49cd-8624-a4c222c5eb4b.json similarity index 50% rename from data-extract-langchain4j/src/test/resources/mappings/api_chat-be38bae8-7817-4141-8b20-2cff30446e53.json rename to data-extract-langchain4j/src/test/resources/mappings/api_chat-d0af43a7-81b5-49cd-8624-a4c222c5eb4b.json index f72b3e9e..fdb405c8 100644 --- a/data-extract-langchain4j/src/test/resources/mappings/api_chat-be38bae8-7817-4141-8b20-2cff30446e53.json +++ b/data-extract-langchain4j/src/test/resources/mappings/api_chat-d0af43a7-81b5-49cd-8624-a4c222c5eb4b.json @@ -1,24 +1,24 @@ { - "id" : "be38bae8-7817-4141-8b20-2cff30446e53", + "id" : "d0af43a7-81b5-49cd-8624-a4c222c5eb4b", "name" : "api_chat", "request" : { "url" : "/api/chat", "method" : "POST", "bodyPatterns" : [ { - "equalToJson" : "{\n \"model\" : \"granite4:3b-h\",\n \"messages\" : [ {\n \"role\" : \"user\",\n \"content\" : \"Extract information about a customer from the transcript delimited by triple backticks: ```Operator: Hello, how may I help you ?\\nCustomer: Hello, I'm John. I need to share a problem with you. Actually, the insurance has reimbursed only half the money I have spent due to the accident.\\nOperator: Hello John, could you please give me your last name so that I can [...] + "equalToJson" : "{\n \"model\" : \"granite4:3b-h\",\n \"messages\" : [ {\n \"role\" : \"user\",\n \"content\" : \"Extract information about a customer from the transcript delimited by triple backticks: ```Operator: Hello, how may I help you ?\\nCustomer: Hello, I'm John. I need to share a problem with you. Actually, the insurance has reimbursed only half the money I have spent due to the accident.\\nOperator: Hello John, could you please give me your last name so that I can [...] "ignoreArrayOrder" : true, "ignoreExtraElements" : true } ] }, "response" : { "status" : 200, - "body" : "{\"model\":\"granite4:3b-h\",\"created_at\":\"2026-01-15T15:03:40.273238709Z\",\"message\":{\"role\":\"assistant\",\"content\":\"{\\n \\\"customerSatisfied\\\": false,\\n \\\"customerName\\\": \\\"John Doe\\\",\\n \\\"customerBirthday\\\": {\\n \\\"year\\\": 2001,\\n \\\"month\\\": 11,\\n \\\"day\\\": 1\\n },\\n \\\"summary\\\": \\\"Customer John Doe is dissatisfied with the insurance company's decision to cancel the full reimbursement option automatically. He [...] + "body" : "{\"model\":\"granite4:3b-h\",\"created_at\":\"2026-01-20T14:47:13.730091697Z\",\"message\":{\"role\":\"assistant\",\"content\":\"{\\n \\\"customerSatisfied\\\": false,\\n \\\"customerName\\\": \\\"John Doe\\\",\\n \\\"customerBirthday\\\": {\\n \\\"year\\\": 2001,\\n \\\"month\\\": 11,\\n \\\"day\\\": 1\\n },\\n \\\"summary\\\": \\\"The customer, John Doe, is dissatisfied as his insurance company did not notify him about the cancellation of full reimbursement [...] "headers" : { - "Date" : "Thu, 15 Jan 2026 15:03:40 GMT", + "Date" : "Tue, 20 Jan 2026 14:47:13 GMT", "Content-Type" : "application/json; charset=utf-8" } }, - "uuid" : "be38bae8-7817-4141-8b20-2cff30446e53", + "uuid" : "d0af43a7-81b5-49cd-8624-a4c222c5eb4b", "persistent" : true, "insertionIndex" : 5 } \ No newline at end of file diff --git a/data-extract-langchain4j/src/test/resources/mappings/api_chat-e8f3defd-bdcb-47f4-8782-687fd3cae6d1.json b/data-extract-langchain4j/src/test/resources/mappings/api_chat-e8f3defd-bdcb-47f4-8782-687fd3cae6d1.json deleted file mode 100644 index 3c634a2b..00000000 --- a/data-extract-langchain4j/src/test/resources/mappings/api_chat-e8f3defd-bdcb-47f4-8782-687fd3cae6d1.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "id" : "e8f3defd-bdcb-47f4-8782-687fd3cae6d1", - "name" : "api_chat", - "request" : { - "url" : "/api/chat", - "method" : "POST", - "bodyPatterns" : [ { - "equalToJson" : "{\n \"model\" : \"granite4:3b-h\",\n \"messages\" : [ {\n \"role\" : \"user\",\n \"content\" : \"Extract information about a customer from the transcript delimited by triple backticks: ```Operator: Hello, how may I help you?\\nCustomer: Hello, I am currently at the police station because I've got an accident. The police would need a proof that I have an insurance. Could you please help me?\\nOperator: Sure, could you please remind me your name and birth dat [...] - "ignoreArrayOrder" : true, - "ignoreExtraElements" : true - } ] - }, - "response" : { - "status" : 200, - "body" : "{\"model\":\"granite4:3b-h\",\"created_at\":\"2026-01-15T15:03:54.19103477Z\",\"message\":{\"role\":\"assistant\",\"content\":\"{\\n \\\"customerSatisfied\\\": true,\\n \\\"customerName\\\": \\\"Kate Boss\\\",\\n \\\"customerBirthday\\\": {\\\"year\\\": 1999, \\\"month\\\": 8, \\\"day\\\": 13},\\n \\\"summary\\\": \\\"The customer Kate Boss requested assistance in providing proof of insurance for an accident she was involved in at a police station. The operator helped v [...] - "headers" : { - "Date" : "Thu, 15 Jan 2026 15:03:54 GMT", - "Content-Type" : "application/json; charset=utf-8" - } - }, - "uuid" : "e8f3defd-bdcb-47f4-8782-687fd3cae6d1", - "persistent" : true, - "insertionIndex" : 4 -} \ No newline at end of file
