Skip to content

Agent AI Module

Transforms unstructured inputs (voice audio and receipt images) into normalized transaction data that reuses core transaction creation flows.

  • POST /api/v1/agent/voice (multipart with audio)
  • POST /api/v1/agent/ocr (multipart with receipt, walletId, categoryId)
  • Voice: file buffer and supported audio MIME type are required.
  • OCR: file buffer and supported image MIME type are required.
  • Multipart parsing for audio and receipt is handled by Multer middleware in the presentation layer.
  • OCR request must include walletId and categoryId.
  • Parsing and normalization happen in service + use-case chain.
RouteControllerUse caseService/repository chainRoute file trace
POST /agent/voiceAgentController.processVoiceCommandTransactionVoiceCommandImplVoiceServiceImpl, WalletRepositoryImpl, CategoryRepositoryImpl, AddTransactionImplbackend/src/Presentation/Routes/AgentRoutes.ts
POST /agent/ocrAgentController.processReceiptTransactionOcrImplOcrServiceImpl, AddTransactionImplbackend/src/Presentation/Routes/AgentRoutes.ts

Controller: backend/src/Presentation/Controllers/AgentController.ts.

  • VOICE_MIME_NOT_SUPPORTED (415).
  • VOICE_PROCESSING_FAILED (502).
  • OCR_PROVIDER_MISCONFIGURED / OCR_RESPONSE_FAILED (500).
  • INVALID_PAYLOAD (400) when required multipart fields are missing.
  • Real-call integration tests:
    • backend/src/tests/integration/voice.real.test.ts
    • backend/src/tests/integration/ocr.real.test.ts
Terminal window
curl -X POST "https://budgeti-backend.johandercampos.com/api/v1/agent/ocr" \
-H "Authorization: Bearer <jwt>" \
-F "receipt=@./receipt.jpg" \
-F "walletId=wlt_123" \
-F "categoryId=cat_123"
{
"code": "TRANSACTION_CREATED",
"message": "2 transaction(s) created from receipt",
"transactions": [
{ "id": "txn_1", "amount": -12.5, "description": "Coffee", "walletId": "wlt_123" },
{ "id": "txn_2", "amount": -24.9, "description": "Snacks", "walletId": "wlt_123" }
],
"count": 2
}
{
"code": "VOICE_MIME_NOT_SUPPORTED",
"message": "Audio format is not supported",
"error": "Audio format is not supported"
}
// AgentController.processReceipt
const { walletId, categoryId } = req.body;
const transactions = await transactionOcr.execute({
file: req.file!.buffer,
mimeType: req.file!.mimetype,
walletId,
categoryId,
userId: req.userId!,
});
return res.status(201).json({
...buildSuccessResponse(SuccessCodes.TRANSACTION_CREATED),
transactions,
count: transactions.length,
});