AI Model Wiki

    Skip to main content
    20 min
    Lesson 5 of 5

    Hands-On Practice

    From the course Computer Vision APIs & Applications

    Put what you have learned in this course into practice with the structured exercise below. Working through it end-to-end is the single best way to consolidate the concepts.

    Concrete Starter Project: Build an AI Receipt Scanner

    This project covers the full pipeline from image upload to structured data — combining the OCR, validation, and storage patterns from all four lessons.

    What You'll Build

    A web form where users upload receipt images. The app extracts structured purchase data (store, date, items, totals) using GPT-4o vision and stores the results in a database.

    Step 1 — Accept the Upload and Pre-Process

    import sharp from "sharp";
    import { createHash } from "crypto";
    
    export async function POST(req: Request) {
      const formData = await req.formData();
      const file = formData.get("receipt") as File;
    
      // Validate type and size
      if (!["image/jpeg", "image/png", "image/webp"].includes(file.type)) {
        return Response.json({ error: "Unsupported format" }, { status: 400 });
      }
      if (file.size > 10 * 1024 * 1024) {
        return Response.json({ error: "File too large (max 10MB)" }, { status: 400 });
      }
    
      // Resize to reduce tokens
      const buffer = Buffer.from(await file.arrayBuffer());
      const resized = await sharp(buffer)
        .resize({ width: 1536, height: 1536, fit: "inside", withoutEnlargement: true })
        .jpeg({ quality: 85 })
        .toBuffer();
    
      const imageHash = createHash("sha256").update(resized).digest("hex");
      const base64 = resized.toString("base64");
      return extractReceipt(base64, imageHash);
    }
    

    Step 2 — Extract with GPT-4o Vision

    async function extractReceipt(base64Image: string, imageHash: string) {
      // Check cache first
      const cached = await db.query("SELECT data FROM receipt_cache WHERE image_hash = $1", [imageHash]);
      if (cached.rows.length) return Response.json(cached.rows[0].data);
    
      const response = await openai.chat.completions.create({
        model: "gpt-4o",
        messages: [{
          role: "user",
          content: [
            { type: "image_url", image_url: { url: `data:image/jpeg;base64,${base64Image}`, detail: "high" } },
            { type: "text", text: 'Extract receipt data. Return JSON: { "store_name": string, "date": "YYYY-MM-DD", "items": [{ "name": string, "qty": number, "price": number }], "subtotal": number, "tax": number, "total": number, "currency": string }' },
          ],
        }],
        response_format: { type: "json_object" },
      });
    
      const data = JSON.parse(response.choices[0].message.content!);
      await db.query("INSERT INTO receipt_cache (image_hash, data) VALUES ($1, $2)", [imageHash, JSON.stringify(data)]);
      return Response.json(data);
    }
    

    Step 3 — Validate the Schema

    import { z } from "zod";
    
    const ReceiptSchema = z.object({
      store_name: z.string().min(1),
      date: z.string().regex(/^d{4}-d{2}-d{2}$/),
      items: z.array(z.object({ name: z.string(), qty: z.number(), price: z.number().positive() })).min(1),
      subtotal: z.number().positive(),
      tax: z.number().min(0),
      total: z.number().positive(),
      currency: z.string().length(3),
    });
    
    const validated = ReceiptSchema.safeParse(data);
    if (!validated.success) {
      return Response.json({ error: "Extraction failed validation", issues: validated.error.issues }, { status: 422 });
    }
    

    Self-Check Questions

    • What happens with handwritten receipts where OCR accuracy drops significantly?
    • How would you handle receipts in languages other than English?
    • What's your fallback when GPT-4o returns valid JSON but with obviously wrong numbers?

    Stretch Goal

    Add a spending summary dashboard: group extracted receipts by store and month, and display total spend per category using item names and an AI classifier.

    Key Takeaways

    • •Hands-on application converts course concepts into real skill
    • •Start small with an MVP before optimising
    • •Self-check questions catch gaps in understanding before they ship to production
    0 of 5 lessons marked complete

    Progress is kept in this browser only.