Preview: uploadController.js
Size: 3.54 KB
/var/www/receipt-app-backend-bitkit.dk/httpdocs/dist/controllers/uploadController.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.uploadAndParseBill = void 0;
const receiptAiService_1 = require("../services/receiptAiService");
const creditorMatchService_1 = require("../services/creditorMatchService");
const logger_1 = __importDefault(require("../utils/logger"));
const uploadService_1 = require("../services/uploadService");
const receiptVisionPrepareService_1 = require("../services/receiptVisionPrepareService");
const receiptVisionImageClamp_1 = require("../services/receiptVisionImageClamp");
const file_type_1 = __importDefault(require("file-type"));
const uploadAndParseBill = async (req, res) => {
// @ts-ignore
const user = req.user;
if (!req.file) {
logger_1.default.warn("Upload: No file uploaded", { body: req.body });
return res.status(400).json({ error: "No file uploaded" });
}
try {
// Use the upload service
const receipt = await (0, uploadService_1.saveReceiptFile)(user.id, req.file);
// Detect real MIME type if needed
let mimeType = req.file.mimetype;
if (mimeType === "application/octet-stream") {
const detected = await file_type_1.default.fromBuffer(req.file.buffer);
if (detected) {
mimeType = detected.mime;
}
}
const { buffer: visionBuffer, mimeType: visionMime } = await (0, receiptVisionPrepareService_1.prepareBufferForAiReceiptVision)(req.file.buffer, mimeType, req.file.originalname);
const { buffer: clampedBuffer, mimeType: clampedMime } = await (0, receiptVisionImageClamp_1.clampImageForVisionApi)(visionBuffer, visionMime);
const aiParsed = await (0, receiptAiService_1.parseReceiptImageWithAi)(clampedBuffer, clampedMime);
if (!aiParsed || typeof aiParsed !== "object") {
logger_1.default.error("Failed to parse receipt with AI", { aiParsed });
return res.status(500).json({ error: "Failed to parse receipt with AI" });
}
logger_1.default.info("File parsed with AI", { aiParsed });
const parsed = aiParsed;
const currency = "currency" in parsed ? parsed.currency : null;
let creditorMatch = null;
const merchantRaw = parsed.merchant;
if (typeof merchantRaw === "string" && merchantRaw.trim()) {
try {
creditorMatch = await (0, creditorMatchService_1.matchCreditorsForMerchant)(merchantRaw.trim());
}
catch (matchErr) {
logger_1.default.warn("Creditor match skipped after parse error", {
error: matchErr,
});
}
}
/** Same value to send as `merchant` on POST /bills when auto-match is confident. */
let merchant = null;
if (creditorMatch &&
creditorMatch.autoResolved &&
creditorMatch.autoResolved.podioItemId != null) {
merchant = Number(creditorMatch.autoResolved.podioItemId);
}
res.json({
receiptId: receipt.id,
merchant,
aiParsed,
extractedText: parsed.extractedText ?? null,
currency,
creditorMatch,
});
}
catch (err) {
logger_1.default.error("Failed to process uploaded file", {
error: err,
});
res.status(500).json({ error: "Failed to process file" });
}
};
exports.uploadAndParseBill = uploadAndParseBill;
Directory Contents
Dirs: 0 × Files: 9