Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM, PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source files covering clients, berths, interests/pipeline, documents/EOI, expenses/invoices, email, notifications, dashboard, admin, and client portal. CI/CD via Gitea Actions with Docker builds. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
55
src/lib/services/receipt-scanner.ts
Normal file
55
src/lib/services/receipt-scanner.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import OpenAI from 'openai';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
const openai = new OpenAI(); // uses OPENAI_API_KEY from env
|
||||
|
||||
interface ScanResult {
|
||||
establishment: string | null;
|
||||
date: string | null;
|
||||
amount: number | null;
|
||||
currency: string | null;
|
||||
lineItems: Array<{ description: string; amount: number }>;
|
||||
confidence: number;
|
||||
}
|
||||
|
||||
export async function scanReceipt(
|
||||
imageBuffer: Buffer,
|
||||
mimeType: string,
|
||||
): Promise<ScanResult> {
|
||||
try {
|
||||
const base64 = imageBuffer.toString('base64');
|
||||
const response = await openai.chat.completions.create({
|
||||
model: 'gpt-4o',
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Extract receipt data as JSON: { establishment, date (ISO), amount (number), currency (3-letter code), lineItems: [{ description, amount }], confidence (0-1) }. Return ONLY valid JSON.',
|
||||
},
|
||||
{
|
||||
type: 'image_url',
|
||||
image_url: { url: `data:${mimeType};base64,${base64}` },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
max_tokens: 1000,
|
||||
});
|
||||
|
||||
const content = response.choices[0]?.message?.content ?? '{}';
|
||||
const cleaned = content.replace(/```json\n?|\n?```/g, '').trim();
|
||||
return JSON.parse(cleaned) as ScanResult;
|
||||
} catch (err) {
|
||||
logger.error({ err }, 'Receipt scan failed');
|
||||
return {
|
||||
establishment: null,
|
||||
date: null,
|
||||
amount: null,
|
||||
currency: null,
|
||||
lineItems: [],
|
||||
confidence: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user