Skip to content

Commit 8a4faf1

Browse files
committed
Refactor transaction extraction and account lookup logic
Revised transaction extraction to include account IDs and enhanced fallback mechanisms for missing data. Improved account lookup logic using filters and enriched the handling of account details. Updated tests, DTOs, and configurations to align with these changes, ensuring better robustness and traceability.
1 parent 29494e6 commit 8a4faf1

File tree

19 files changed

+204
-77
lines changed

19 files changed

+204
-77
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.jongsoft.finance.rest.transaction;
2+
3+
import com.jongsoft.finance.core.TransactionType;
4+
import com.jongsoft.finance.learning.TransactionResult;
5+
import io.micronaut.serde.annotation.Serdeable;
6+
7+
import java.time.LocalDate;
8+
9+
@Serdeable
10+
public record TransactionExtractResponse(
11+
TransactionType type,
12+
LocalDate date,
13+
AccountRef from,
14+
AccountRef to,
15+
String description,
16+
double amount) {
17+
18+
@Serdeable
19+
public record AccountRef(long id, String name){}
20+
21+
public static TransactionExtractResponse from(TransactionResult transactionResult) {
22+
return new TransactionExtractResponse(
23+
transactionResult.type(),
24+
transactionResult.date(),
25+
new AccountRef(transactionResult.from().id(), transactionResult.from().name()),
26+
new AccountRef(transactionResult.to().id(), transactionResult.to().name()),
27+
transactionResult.description(),
28+
transactionResult.amount());
29+
}
30+
}

fintrack-api/src/main/java/com/jongsoft/finance/rest/transaction/TransactionSuggestionResource.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
import com.jongsoft.finance.core.exception.StatusException;
55
import com.jongsoft.finance.learning.SuggestionEngine;
66
import com.jongsoft.finance.learning.SuggestionInput;
7-
import com.jongsoft.finance.learning.TransactionResult;
87
import com.jongsoft.finance.rest.model.TagResponse;
98
import com.jongsoft.finance.security.AuthenticationRoles;
10-
import io.micronaut.http.annotation.*;
9+
import io.micronaut.http.annotation.Body;
10+
import io.micronaut.http.annotation.Controller;
11+
import io.micronaut.http.annotation.Post;
1112
import io.micronaut.security.annotation.Secured;
1213
import io.swagger.v3.oas.annotations.Operation;
1314
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -65,8 +66,9 @@ class TransactionSuggestionResource {
6566
operationId = "extractTransaction",
6667
summary = "Extract transaction info",
6768
description = "Extract transaction information from the presented text.")
68-
public TransactionResult extractTransaction(TransactionExtractRequest request) {
69+
public TransactionExtractResponse extractTransaction(@Body TransactionExtractRequest request) {
6970
return suggestionEngine.extractTransaction(request.fromText())
71+
.map(TransactionExtractResponse::from)
7072
.orElseThrow(() -> StatusException.badRequest("No extractor configured.", "llm.not.configured"));
7173
}
7274
}

fintrack-api/src/main/resources/docs/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</head>
1111
<body>
1212
<rapi-doc id="thedoc"
13-
spec-url="/spec/fintrack-2.0.0.yml"
13+
spec-url="/spec/pledger-2.0.0.yml"
1414
heading-text="FinTrack API"
1515
show-header="false"
1616
schema-style="table"

fintrack-api/src/main/resources/i18n/messages.properties

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,10 +589,15 @@ validation.transaction.schedule.end.before.start=Start of the scheduled transact
589589
page.user.profile.import.account.lookup.info=During the import an account was found that is not mapped to an account in Pledger.io. Please either add it manually or correct the mapping below.
590590
page.settings.import.details.transactions.rules.run=Run transaction rules
591591
page.settings.currencies.edit=Edit currency
592-
page.setting.overview.setting.ImportOutdated=Import outdated entries
593592
page.accounts.liability.created.failed=Failed to create the liability account.
594593
page.login.welcome=Welcome back
595594
page.login.subtitle=Sign in to continue
596595
page.login.success=Login successful
597596
common.lang.or=or
598597
page.user.profile.two-factor=2-factor authentication
598+
page.transactions.process=Process transaction
599+
page.transactions.generate=Extract from text
600+
page.transactions.generate.info=Paste a transaction description from your bank statement to extract the relevant information.
601+
page.transactions.generated=Extracted transaction
602+
page.transactions.generate.confirm=Create transaction
603+
common.action.back=Back

learning/learning-module-llm/src/main/java/com/jongsoft/finance/llm/AiSuggestionEngine.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,16 @@ public SuggestionResult makeSuggestions(SuggestionInput transactionInput) {
5656

5757
@Override
5858
public Optional<TransactionResult> extractTransaction(String transactionInput) {
59-
var extracted = transactionExtractorAgent.extractTransaction(transactionInput);
59+
var extracted = transactionExtractorAgent.extractTransaction(UUID.randomUUID(), transactionInput);
6060
return Optional.of(new TransactionResult(
6161
extracted.type(),
6262
extracted.date(),
63-
extracted.fromAccount().name().isBlank() ? null : extracted.fromAccount().name(),
64-
extracted.toAccount().name().isBlank() ? null : extracted.toAccount().name(),
63+
Optional.ofNullable(extracted.fromAccount())
64+
.map(e -> new TransactionResult.AccountResult(Optional.ofNullable(e.id()).orElse(-1L), e.name()))
65+
.orElse(null),
66+
Optional.ofNullable(extracted.toAccount())
67+
.map(e -> new TransactionResult.AccountResult(Optional.ofNullable(e.id()).orElse(-1L), e.name()))
68+
.orElse(null),
6569
extracted.description(),
6670
extracted.amount()
6771
));

learning/learning-module-llm/src/main/java/com/jongsoft/finance/llm/LanguageModelStarter.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ public ClassificationAgent transactionSupportAgent(
3434
log.info("Setting up transaction support chat agent.");
3535
var aiBuilder = AiServices.builder(ClassificationAgent.class)
3636
.chatLanguageModel(model)
37-
.chatMemoryProvider(chatMemoryProvider())
38-
.tools(aiTools.getTools());
37+
.chatMemoryProvider(chatMemoryProvider());
3938

39+
if (aiTools.getTools().length > 0) {
40+
aiBuilder.tools(aiTools.getTools());
41+
}
4042
Optional.ofNullable(retrievalAugmentor).ifPresent(aiBuilder::retrievalAugmentor);
4143

4244
return aiBuilder.build();
@@ -45,11 +47,15 @@ public ClassificationAgent transactionSupportAgent(
4547
@Bean
4648
public TransactionExtractorAgent transactionExtractorAgent(ChatLanguageModel model, ToolSupplier aiTools) {
4749
log.info("Setting up transaction extractor chat agent.");
48-
return AiServices.builder(TransactionExtractorAgent.class)
50+
var aiBuilder = AiServices.builder(TransactionExtractorAgent.class)
4951
.chatLanguageModel(model)
50-
.chatMemoryProvider(chatMemoryProvider())
51-
.tools(aiTools.getTools())
52-
.build();
52+
.chatMemoryProvider(chatMemoryProvider());
53+
54+
if (aiTools.getTools().length > 0) {
55+
aiBuilder.tools(aiTools.getTools());
56+
}
57+
58+
return aiBuilder.build();
5359
}
5460

5561
@Bean

learning/learning-module-llm/src/main/java/com/jongsoft/finance/llm/agent/TransactionExtractorAgent.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package com.jongsoft.finance.llm.agent;
22

33
import com.jongsoft.finance.llm.dto.TransactionDTO;
4+
import dev.langchain4j.service.MemoryId;
45
import dev.langchain4j.service.SystemMessage;
56
import dev.langchain4j.service.UserMessage;
7+
import dev.langchain4j.service.V;
8+
9+
import java.util.UUID;
610

711
@SystemMessage({
812
"""
@@ -15,7 +19,9 @@
1519
Parse and extract transaction data from user-provided text.
1620
Construct and return a JSON object (or array of objects, if multiple transactions) that exactly matches the TransactionDTO and AccountDTO schema.
1721
Field requirements:
22+
- fromAccount.id: The unique identifier of the sender account.
1823
- fromAccount.name: The name of the sender account (e.g., “My Savings”, “Bank of America”).
24+
- toAccount.id: The unique identifier of the receiver account.
1925
- toAccount.name: The name of the receiver account (e.g., “John Doe”, “Amazon”, “Chase Checking”).
2026
- type: One of debit, credit, or transfer, based on the context:
2127
- debit = money received
@@ -25,8 +31,11 @@ Construct and return a JSON object (or array of objects, if multiple transaction
2531
- amount: A non-negative number, parsed from the text (currency symbols are ignored).
2632
- date: The date of the transaction, in YYYY-MM-DD format. Parse approximate or relative dates (e.g., “yesterday”).
2733
34+
The description field must be in the same language as the input text.
35+
You must lookup the accounts using the tools provided to you.
2836
If any field is missing or cannot be confidently inferred, leave it out of the output.
29-
Return only the structured JSON data—do not include any commentary or explanations."""
37+
Only return the JSON of the extracted transaction, do not include any other fields or reasoning.
38+
```"""
3039
})
3140
public interface TransactionExtractorAgent {
3241

@@ -36,6 +45,8 @@ public interface TransactionExtractorAgent {
3645
Only include fields that can be confidently identified.
3746
Here's the text: {{input}}"""
3847
})
39-
TransactionDTO extractTransaction(String input);
48+
TransactionDTO extractTransaction(
49+
@MemoryId UUID chat,
50+
@V("input") String input);
4051

4152
}

learning/learning-module-llm/src/main/java/com/jongsoft/finance/llm/augmenters/ClassificationAugmenter.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ public AugmentationResult augment(AugmentationRequest augmentationRequest) {
4646
throw new IllegalStateException("Could not augment a message of type " + augmentationRequest.chatMessage().getClass().getName());
4747
}
4848

49-
@Override
50-
public UserMessage augment(UserMessage userMessage, Metadata metadata) {
49+
private UserMessage augment(UserMessage userMessage, Metadata metadata) {
5150
var currentMessage = userMessage.singleText();
5251

5352
String allowedList = "";

learning/learning-module-llm/src/main/java/com/jongsoft/finance/llm/dto/AccountDTO.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
@Description("A financial account that can be used in transactions.")
66
public record AccountDTO(
7+
@Description("The unique identifier of the account.")
8+
Long id,
79
@Description("The name of the account.")
810
String name,
911
@Description("The type of the account, leave blank at all times.")

learning/learning-module-llm/src/main/java/com/jongsoft/finance/llm/dto/TransactionDTO.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public record TransactionDTO(
1313
AccountDTO toAccount,
1414
@Description("Write a short description for the transaction, excludes dates and amounts. Be creative.")
1515
String description,
16-
@Description("The date of the transaction.")
16+
@Description("The date of the transaction, in YYYY-MM-DD format.")
1717
LocalDate date,
1818
@Description("The amount of the transaction, cannot be a negative number.")
1919
double amount,

0 commit comments

Comments
 (0)