AI 기반 청구서 분할기 만들기: OCR, LLMs, 실시간 상태

발행: (2026년 1월 18일 오후 08:35 GMT+9)
9 min read
원문: Dev.to

Source: Dev.to

Doru Prodan

1. OCR 파이프라인: 픽셀에서 원시 텍스트까지

Hackbill과 같은 도구를 만들 때 첫 번째 과제는 흐릿하거나 저조도 스마트폰 사진을 기계가 읽을 수 있는 텍스트로 변환하는 것입니다. 기존 광학 문자 인식(OCR) 기술은 크게 발전했지만, 영수증은 고유한 어려움을 가지고 있습니다: 다양한 글꼴, 구겨진 종이, 그리고 복잡한 레이아웃(수량, 품명, 가격을 위한 열 등).

전처리 단계

OCR 엔진에 입력하기 전에 일반적으로 정확도를 높이기 위한 파이프라인이 필요합니다:

  • 그레이스케일 변환: 색상 노이즈 제거.
  • 원근 보정: 에지 검출(예: Canny)을 사용해 영수증 모서리를 찾고 4점 원근 변환을 수행.
  • 적응형 이진화: 종이 전체에 걸친 불균일한 조명을 처리.

엔진 선택

  • Tesseract: 오픈소스 표준.
  • 클라우드 기반 솔루션(AWS Textract, Google Cloud Vision): “블록” 및 “폼” 형태로 결과를 반환하므로 다중 열 레이아웃에서 더 나은 결과를 제공.

2. 구조화된 데이터 추출을 위한 LLM 활용

Raw OCR 출력은 종종 구조화되지 않은 문자열의 엉망입니다. 예를 들어, 한 줄에 1 BU RGER $15 .00와 같이 표시될 수 있습니다. 영수증을 포맷하는 방식이 POS 시스템마다 다르기 때문에 전통적인 정규식 기반 파싱은 매우 깨지기 쉽습니다.

이때 GPT‑4oClaude 3.5 Sonnet과 같은 대형 언어 모델(LLM)이 빛을 발합니다. 수백 줄의 정규식을 작성하는 대신, 시스템 프롬프트를 사용해 원시 OCR 텍스트를 LLM에 전달하고 JSON 스키마를 반환하도록 할 수 있습니다.

구현 예시 (Node.js)

const extractReceiptItems = async (rawText) => {
  const prompt = `
    Extract the items, quantities, and prices from this receipt text.
    Return ONLY a JSON array of objects with keys: name, quantity, price.
    Text: "${rawText}"
  `;

  const response = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [{ role: "user", content: prompt }],
    response_format: { type: "json_object" },
  });

  return JSON.parse(response.choices[0].message.content);
};

AI 기반 스캔을 활용함으로써 Hackbill 은 어떤 줄이 품목인지, 날짜나 서버 이름과 같은 메타데이터인지를 지능적으로 식별할 수 있어 사용자의 “검토” 단계가 크게 감소합니다.

3. 실시간 협업 및 상태 관리

영수증을 스캔하고 항목을 추출한 뒤 다음 기술적 과제는 “공유 및 청구(Share and Claim)” 단계입니다. 개발자 관점에서 보면 이는 분산 상태 문제입니다. 세 사람이 같은 영수증을 보고 있다면, 두 사람이 동시에 같은 맥주를 청구하지 않도록 해야 합니다.

실시간 동기화를 위한 기술 스택

“Hackbill 워크플로우”에서 언급된 “누가 무엇을 청구하고 있는지 실시간으로 보기” 기능을 구현하려면 일반적으로 세 가지 옵션이 있습니다:

  • WebSockets (Socket.io): 저지연, 양방향 통신에 최적.
  • Server‑Sent Events (SSE): 일방향 업데이트(서버 → 클라이언트)에 적합.
  • 실시간 데이터베이스 (Supabase/Firebase): Pub/Sub 로직을 기본 제공하므로 빠른 개발에 가장 효율적.

충돌 처리

사용자가 “Claim” 버튼을 클릭하면, 클라이언트는 UI에 낙관적 업데이트를 적용하고 백엔드가 요청을 검증합니다. 데이터베이스에서 해당 항목이 이미 다른 user_id에 의해 청구된 경우, 백엔드는 트랜잭션을 거부하고 UI는 롤백됩니다.

4. 공정한 팁 분배의 수학

Hackbill 철학의 가장 혁신적인 기능 중 하나는 공정한 팁 분배입니다. 대부분의 사람들은 팁을 균등하게 나누지만, 이는 기술적으로 불공평합니다. 제가 $5 샐러드를 주문하고 당신이 $50 스테이크를 주문했을 때, $10 팁을 균등하게 나누면 제 소비에 비해 과다 지불하게 됩니다.

알고리즘

Hackbill은 청구한 항목이 있는 사람만이 팁을 자신의 비율에 맞게 지불하도록 보장합니다. 수학적으로 이는 가중 비율로 계산됩니다:

  1. Calculate Subtotal: Sum of all claimed items.

  2. Calculate User Subtotal: Sum of items claimed by User A.

  3. Calculate Proportion:

    User A Proportion = User A Subtotal / Total Subtotal
  4. Apply Tip/Tax:

    User A Total = User A Subtotal
                 + (Total Tip * User A Proportion)
                 + (Total Tax * User A Proportion)

백엔드에 이 로직을 구현하면 최종 “Claim” 금액이 수학적으로 정확하고 사회적으로 마찰이 없게 됩니다.

5. 보안 및 개인정보 고려사항

개발자로서 영수증 데이터의 민감성을 고려해야 합니다. 영수증에는 종종 신용카드 마지막 네 자리, 상점 주소, 식사 습관 등이 포함됩니다.

  • 데이터 최소화: 항목 이름과 가격만 저장합니다. 파싱이 성공하면 원본 이미지는 삭제합니다.
  • 단기 세션: 고유한 UUID 기반 URL을 사용하여 청구서를 공유하고, 일정 기간 후에 만료되도록 합니다.
  • 암호화: 전송 중인 모든 데이터는 HTTPS를 통해 처리하고, 개인 식별 정보(PII)는 저장 시 암호화합니다.

결론: 코드로 사회적 마찰 해결

Hackbill(https://hackbill.com/) 같은 도구를 만드는 것은 컴퓨터 비전, 자연어 처리, 실시간 웹 시스템 등 다양한 최신 기술을 결합해 일상적인 인간 문제를 해결하는 마스터클래스입니다.

유사한 애플리케이션을 만들고자 하는 개발자들에게 핵심 포인트는 명확합니다:

  • 현실 세계의 비구조적 특성을 경직된 정규식으로 싸우지 마세요. 데이터 추출에는 LLM을 활용하고, 협업을 위해 실시간 동기화를 사용하며, 가중 팁 분배와 같은 가장자리 경우를 항상 수학적으로 처리하도록 하세요.

수동 계산을 그만하고 싶으신가요? Hackbill을 확인하여 이러한 기술 원리를 실제로 보고 다음 단체 식사를 효율화하세요.

개발자를 위한 핵심 요점

  • OCR은 시작일 뿐, 끝이 아니다: OCR이 생성하는 지저분한 데이터를 구조화하려면 LLM을 사용하세요.
  • 실시간은 협상 불가: 원활한 “청구” 경험을 위해 WebSockets 또는 Supabase를 사용하세요.
  • 가중 수학 > 단순 수학: 공정성을 보장하려면 항상 비례 소계에 기반해 지분을 계산하세요.

코딩 즐겁게 하시고, 다음 점심 계산서도 이 마크다운만큼 깔끔하길 바랍니다!

Back to Blog

관련 글

더 보기 »

기술은 구원자가 아니라 촉진자다

왜 사고의 명확성이 사용하는 도구보다 더 중요한가? Technology는 종종 마법 스위치처럼 취급된다—켜기만 하면 모든 것이 개선된다. 새로운 software, ...

에이전틱 코딩에 입문하기

Copilot Agent와의 경험 나는 주로 GitHub Copilot을 사용해 인라인 편집과 PR 리뷰를 수행했으며, 대부분의 사고는 내 머리로 했습니다. 최근 나는 t...