Skip to content

Commit

Permalink
Ability to add or propose transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
mput committed Jun 26, 2024
1 parent d0964f4 commit 4e36ee9
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 32 deletions.
2 changes: 1 addition & 1 deletion app/bot/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,5 +197,5 @@ func (bot *Bot) proposeTransaction(ctx *ext.Context) (string, *gotgbot.SendMessa
return fmt.Sprintf("Error: %v", err), nil, nil
}

return fmt.Sprintf("```\n%s\n```", transaction), &gotgbot.SendMessageOpts{ParseMode: "MarkdownV2"}, nil
return transaction, &gotgbot.SendMessageOpts{ParseMode: "MarkdownV2"}, nil
}
68 changes: 45 additions & 23 deletions app/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,37 +166,46 @@ func (l *Ledger) Execute(args ...string) (string, error) {
return l.execute(args...)
}

func (l *Ledger) AddTransaction(transaction string) error {
err := l.repo.Init()
defer l.repo.Free()
func (l *Ledger) addTransaction(transaction string) error {
balBefore, err := l.execute("balance")
if err != nil {
return fmt.Errorf("unable to init repo: %v", err)
return fmt.Errorf("invalid transaction: %v", err)
}

balAfter, err := l.executeWith(transaction, "balance")

balBefore, err := l.execute("balance")
if err != nil {
return err
return fmt.Errorf("invalid transaction: %v", err)
}

if balBefore == balAfter {
return fmt.Errorf("invalid transaction: transaction doesn't change balance")
}

r, err := l.repo.OpenForAppend(l.mainFile)
if err != nil {
return fmt.Errorf("unable to open main ledger file: %v", err)
}
_, err = fmt.Fprintf(r, "\n%s\n", transaction)
r.Close()
defer r.Close()
if err != nil {
return fmt.Errorf("unable to write main ledger file: %v", err)
}
balAfter, err :=l.execute("balance")
if err != nil {
return err
}
if balBefore == balAfter {
return fmt.Errorf("transaction doesn't change balance")
}
return nil
}

func (l *Ledger) AddTransaction(transaction string) error {
err := l.repo.Init()
defer l.repo.Free()
if err != nil {
return fmt.Errorf("unable to init repo: %v", err)
}
return l.addTransaction(transaction)
}

func (l *Ledger) validate() error {
_, err := l.execute("balance")
return err
Expand Down Expand Up @@ -343,8 +352,6 @@ func (b OpenAITransactionGenerator) GenerateTransaction(promptCtx PromptCtx) (Tr
return Transaction{}, fmt.Errorf("chatCompletion error: %v", err)
}

fmt.Println(resp.Choices[0].Message.Content)

res := Transaction{}
err = json.Unmarshal([]byte(resp.Choices[0].Message.Content), &res)
if err != nil {
Expand Down Expand Up @@ -466,8 +473,6 @@ func (l *Ledger) proposeTransaction(userInput string) (Transaction, error) {
return trx, fmt.Errorf("unable to generate transaction: %v", err)
}

fmt.Println(trx.Format(true))

err = l.validateWith(trx.Format(true))
if err != nil {
return trx, fmt.Errorf("unable to validate transaction: %v", err)
Expand All @@ -477,15 +482,32 @@ func (l *Ledger) proposeTransaction(userInput string) (Transaction, error) {

}

func (l *Ledger) ProposeTransaction(userInput string, attempts int) (tr Transaction,err error) {
if attempts <= 0 {
panic("times should be greater than 0")
}
func (l *Ledger) AddOrProposeTransaction(userInput string, attempts int) (wasGenerated bool, tr Transaction,err error) {
wasGenerated = false
err = l.repo.Init()
defer l.repo.Free()

if err != nil {
return tr, err
return wasGenerated, tr, err
}

// first try to add userInput as transaction
err = l.addTransaction(userInput)
if err == nil {
err = l.repo.CommitPush("New comment", "teledger", "teledger@example.com")
if err != nil {
return wasGenerated, tr, err
}
return wasGenerated, tr, nil
}

if !strings.HasPrefix(err.Error(), "invalid transaction:") {
return wasGenerated, tr, err
}

// after this generate a transaction using LLM
wasGenerated = true
if attempts <= 0 {
panic("times should be greater than 0")
}

for i := 0; i < attempts; i++ {
Expand All @@ -494,11 +516,11 @@ func (l *Ledger) ProposeTransaction(userInput string, attempts int) (tr Transact
}
tr, err = l.proposeTransaction(userInput)
if err == nil {
return tr, nil
return wasGenerated, tr, nil
}
}

return tr, err
return wasGenerated, tr, err
}


Expand Down
21 changes: 19 additions & 2 deletions app/ledger/ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,9 @@ account Equity
t.Run("happy path", func(t *testing.T) {


tr, err := ledger.ProposeTransaction("20 Taco Bell", 5)
wasGenerated, tr, err := ledger.AddOrProposeTransaction("20 Taco Bell", 5)

assert.True(t, wasGenerated)

assert.NoError(t, err)

Expand Down Expand Up @@ -282,10 +284,25 @@ account Equity
)
})

t.Run("add an already valid transaction", func(t *testing.T) {
mockedTransactionGenerator.ResetCalls()

wasGenerated, _, err := ledger.AddOrProposeTransaction(`
2014-11-12 * Tacos
Assets:Cash -2,43 EUR
Food 2,43 EUR
`, 1)

assert.False(t, wasGenerated)
assert.NoError(t, err)
assert.Equal(t, 0, len(mockedTransactionGenerator.calls.GenerateTransaction))

})

t.Run("validation error path", func(t *testing.T) {
mockedTransactionGenerator.ResetCalls()

_, err := ledger.ProposeTransaction("20 Taco Bell", 1)
_, _, err := ledger.AddOrProposeTransaction("20 Taco Bell", 1)

assert.ErrorContains(t, err, "Unknown account 'cash'")

Expand Down
35 changes: 30 additions & 5 deletions app/teledger/teledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,42 @@ func (tel *Teledger) Balance() (string, error) {
}


func inBacktick(s string) string {
return fmt.Sprintf("```\n%s\n```", s)
}

// Receive a short free-text description of a transaction
// and propose a formatted transaction validated with the
// ledger file.
// Store the transaction in a state, so the user can confirm
// or reject it.
func (tel *Teledger) ProposeTransaction(desc string) (string, error) {
wasGenerated, tr, err := tel.ledger.AddOrProposeTransaction(desc, 2)
if wasGenerated {
if err == nil {
return fmt.Sprintf(`Proposed valid transaction:
%s
`,
inBacktick(tr.Format(false)),
), nil
} else {
if len(tr.Postings) > 0 {
return fmt.Sprintf(`Proposed but invalid transaction:
%s`,
inBacktick(tr.Format(false)),
), nil
} else {
return "", err
}

tr, err := tel.ledger.ProposeTransaction(desc, 2)
if err != nil {
return "", err
}
}

} else {
if err == nil {
return "Transaction Added", nil
} else {
return "", err
}

return tr.Format(true), nil
}
}
2 changes: 1 addition & 1 deletion todo.org
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

* Main
** [ ] Add Transaction To a ledger repository
- [ ] Basic (transaction LLM completion and valid transaction addition)
- [X] Basic (transaction LLM completion and valid transaction addition)
- [ ] Add to log with chat button
- [ ] Delete with button
** [ ] Configuration from a repository with Ledger
Expand Down

0 comments on commit 4e36ee9

Please sign in to comment.