<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Doru Prodan</title>
    <description>The latest articles on DEV Community by Doru Prodan (@hackbill).</description>
    <link>https://dev.to/hackbill</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3717747%2Fd0eeef47-050d-4a9d-bf3c-7df1a459eff6.png</url>
      <title>DEV Community: Doru Prodan</title>
      <link>https://dev.to/hackbill</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hackbill"/>
    <language>en</language>
    <item>
      <title>Building an AI-Powered Bill Splitter: OCR, LLMs, and Real-time State</title>
      <dc:creator>Doru Prodan</dc:creator>
      <pubDate>Sun, 18 Jan 2026 11:35:59 +0000</pubDate>
      <link>https://dev.to/hackbill/building-an-ai-powered-bill-splitter-ocr-llms-and-real-time-state-5d2</link>
      <guid>https://dev.to/hackbill/building-an-ai-powered-bill-splitter-ocr-llms-and-real-time-state-5d2</guid>
      <description>&lt;h2&gt;
  
  
  The Developer’s Dilemma: The Post-Lunch Math Problem
&lt;/h2&gt;

&lt;p&gt;We’ve all been there. A team lunch ends, a long receipt arrives, and suddenly everyone is squinting at tiny font sizes, trying to calculate tax and tip for their specific order of truffle fries and a club sandwich. For developers, this isn't just a social annoyance; it’s a logic problem begging for an automated solution.&lt;/p&gt;

&lt;p&gt;This is the problem space that &lt;a href="https://hackbill.com" rel="noopener noreferrer"&gt;Hackbill&lt;/a&gt; occupies. By leveraging AI-powered scanning and real-time synchronization, it eliminates the manual overhead of debt collection among friends. In this article, we’ll dive into the technical architecture required to build a high-performance bill-splitting engine, focusing on OCR pipelines, LLM-based data structuring, and real-time state management.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The OCR Pipeline: From Pixels to Raw Text
&lt;/h2&gt;

&lt;p&gt;The first challenge in building a tool like Hackbill is converting a potentially blurry, low-light smartphone photo into machine-readable text. Traditional Optical Character Recognition (OCR) has come a long way, but receipts present unique challenges: variable fonts, crumpled paper, and complex layouts (columns for quantity, name, and price).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Pre-processing Step
&lt;/h3&gt;

&lt;p&gt;Before hitting an OCR engine, the image usually needs a pipeline to improve accuracy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Grayscale Conversion:&lt;/strong&gt; Removing color noise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perspective Correction:&lt;/strong&gt; Using edge detection (like Canny) to find the receipt corners and perform a 4-point perspective transform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptive Thresholding:&lt;/strong&gt; Handling uneven lighting across the paper.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Choosing an Engine
&lt;/h3&gt;

&lt;p&gt;While Tesseract is the open-source standard, modern cloud-based solutions like AWS Textract or Google Cloud Vision provide better results for multi-column layouts because they return "blocks" and "forms" rather than just raw strings.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Using LLMs for Structured Data Extraction
&lt;/h2&gt;

&lt;p&gt;Raw OCR output is often a mess of unstructured strings. For example, a line might read &lt;code&gt;1 BU RGER $15 .00&lt;/code&gt;. Traditional regex-based parsing is incredibly brittle here because every POS system formats receipts differently.&lt;/p&gt;

&lt;p&gt;This is where Large Language Models (LLMs) like GPT-4o or Claude 3.5 Sonnet shine. Instead of writing 500 lines of regex, you can pass the raw OCR text to an LLM with a system prompt designed to return a JSON schema.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Implementation (Node.js)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;extractReceiptItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    Extract the items, quantities, and prices from this receipt text.
    Return ONLY a JSON array of objects with keys: name, quantity, price.
    Text: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rawText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4o&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="na"&gt;response_format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json_object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using AI-powered scanning, &lt;a href="https://hackbill.com" rel="noopener noreferrer"&gt;Hackbill&lt;/a&gt; can intelligently identify which lines are items and which are metadata (like the date or the server's name), significantly reducing the "Review" phase for the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Real-time Collaboration and State Management
&lt;/h2&gt;

&lt;p&gt;Once the receipt is scanned and items are extracted, the next technical hurdle is the "Share and Claim" phase. In a developer-centric view, this is a distributed state problem. If three people are looking at the same bill, we need to ensure that two people don't claim the same beer at the same time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack for Live Syncing
&lt;/h3&gt;

&lt;p&gt;To achieve the "see who's claiming what live" feature mentioned in the Hackbill workflow, you generally have three options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;WebSockets (Socket.io):&lt;/strong&gt; Best for low-latency, bidirectional communication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-Sent Events (SSE):&lt;/strong&gt; Good for one-way updates (server to client).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Databases (Supabase/Firebase):&lt;/strong&gt; The most efficient for rapid development, as they handle the pub/sub logic out of the box.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Handling Conflicts
&lt;/h3&gt;

&lt;p&gt;When a user clicks "Claim," the client should send an optimistic update to the UI while the backend validates the request. If the item is already claimed by another &lt;code&gt;user_id&lt;/code&gt; in the database, the backend rejects the transaction, and the UI rolls back.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The Math of Fair Tip Distribution
&lt;/h2&gt;

&lt;p&gt;One of the most innovative features of the Hackbill philosophy is &lt;strong&gt;Fair Tip Distribution&lt;/strong&gt;. Most people simply split the tip evenly, but that’s technically unfair. If I ordered a $5 salad and you ordered a $50 steak, an even split of a $10 tip means I’m overpaying significantly relative to my consumption.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Algorithm
&lt;/h3&gt;

&lt;p&gt;Hackbill ensures only people who claimed items pay their share of the tip. Mathematically, this is calculated as a weighted percentage:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Calculate Subtotal:&lt;/strong&gt; Sum of all claimed items.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calculate User Subtotal:&lt;/strong&gt; Sum of items claimed by User A.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calculate Proportion:&lt;/strong&gt; &lt;code&gt;User A Proportion = User A Subtotal / Total Subtotal&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply Tip/Tax:&lt;/strong&gt; &lt;code&gt;User A Total = User A Subtotal + (Total Tip * User A Proportion) + (Total Tax * User A Proportion)&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Implementing this logic in your backend ensures that the final "Claim" amount is mathematically sound and socially frictionless.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Security and Privacy Considerations
&lt;/h2&gt;

&lt;p&gt;As developers, we must consider the sensitivity of receipt data. Receipts often contain the last four digits of a credit card, the merchant's address, and dining habits.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Minimization:&lt;/strong&gt; Only store the item names and prices. Discard the raw image after successful parsing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Short-lived Sessions:&lt;/strong&gt; Use unique, UUID-based URLs for sharing bills that expire after a set period (e.g., 24 hours).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption:&lt;/strong&gt; Ensure all data in transit is handled via HTTPS and PII (Personally Identifiable Information) is encrypted at rest.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion: Solving Social Friction with Code
&lt;/h2&gt;

&lt;p&gt;Building a tool like &lt;a href="https://hackbill.com" rel="noopener noreferrer"&gt;Hackbill&lt;/a&gt; is a masterclass in combining various modern technologies—Computer Vision, Natural Language Processing, and Real-time Web Systems—to solve a mundane human problem. &lt;/p&gt;

&lt;p&gt;For developers looking to build similar applications, the takeaway is clear: don't fight the unstructured nature of the real world with rigid regex. Embrace LLMs for data extraction, use real-time sync for collaboration, and always ensure your math handles edge cases like weighted tip distribution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ready to stop doing manual math?&lt;/strong&gt; Check out &lt;a href="https://hackbill.com" rel="noopener noreferrer"&gt;Hackbill&lt;/a&gt; to see these technical principles in action and streamline your next group dinner.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Takeaways for Devs:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OCR is the start, not the end:&lt;/strong&gt; Use LLMs to structure the messy data OCR produces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time is non-negotiable:&lt;/strong&gt; Use WebSockets or Supabase for a seamless "claiming" experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weighted Math &amp;gt; Simple Math:&lt;/strong&gt; Always calculate shares based on proportional subtotal to ensure fairness.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
