This AI Agent Extracts Text From Images in n8n

Dr. Violet Howard shows how to build an n8n workflow that processes invoice images sent via Telegram. The bot downloads the image, runs it through a free OCR API, parses the text into fields like invoice number and due date with a ChatGPT-generated code node, then saves the data to Google Sheets and the image to Google Drive before sending a summary back to Telegram.
Chapters
We've got Telegram open. I'm just gonna drag over an invoice here, drop it into Telegram, hit send, and now we will see Telegram's gonna download that file. We're hitting an OCR API, which is going to take the image, extract the text. It's going to parse it out, updates our database with our invoices, and now we're re-downloading that file so we can put it into a Google Drive so we can access that original file if we want. And now we're hitting the agent, which we just saw we got a response. Thanks for submitting the invoice. The total amount is $950. Due date is December 15th. It gives us some notes, so please make the payment within the due date to avoid late fees. It gives us some contact information, it tells us about the penalties, and then it says that the original invoice has been added to the Google Drive. Here is the file name, and then you can also access the database here. So we're gonna open up that database. We will see that this invoice got populated into our database here, and then if we go to our Google Drive, we can see that we got the actual invoice put in here, the original file. So in case we need to look at it, You're good to go. So that is what's going on in this workflow. Let's dive into what's going on within each node. Okay, so let's dive into what's going on within this invoice agent. As you saw in the demo, we're talking to it through Telegram. So right here is where we send an image file of an invoice, and then it will download the file, send it off to an OCR to analyze the image, extract the text. We're then parsing the text, putting it into our database. We're re-downloading the file because, um, AnyLense is kind of weird about the way that binary information can pass through. So we'll talk about that. But then we're downloading that file so we can put it into our Google Drive folder of all of our invoices. And then we're pretty much just giving the agent the information it needs in order to write a response to us back in Telegram, of course. So let's, um, walk through a live example where we actually trigger this workflow and we'll go through node by node and we'll watch the data move through each step. All right, I'm gonna be using the same example invoice from the demo, so we'll hit test step. We will hop into our Telegram and just drag in the sample invoice. Hit send, and now we have the information coming back. So what's important to understand here is that we're looking for a file ID. And as you can see, there are 3 different file IDs coming through, and you can see there's different— there are different sizes and different sort of dimensions. So what we did was we grabbed the largest one, pretty sure, and that's the one we wanted to download just so it's the best quality. We downloaded document.file_id, and if we hit test step, we can see that we're downloading that file. And now let's say we wanted to download this to make sure it's coming through correctly. We can see this is the sample invoice that we're using. We got the number, the date, the amount, the address, the due date, and then some notes. And we're not giving the agent all of this information because obviously we saw the invoice and we sent a picture. We don't want a full summary of exactly all this. We kind of maybe just want the date, the due date, the amount, and then the notes. That's how we have it set up, but obviously you can change however you want the agent to get your stuff back. Anyways, once we download that file, as you saw, it was, um, comes through as binary. So all we're getting here is the file ID and the path, and we're actually really looking for the binary so that we can pass it into OCR, an OCR, to download this information. So I am using a free OCR. Its only limits really are that you can't have a file that's bigger than 1 megabyte. In this case, we're fine. This is what it looks like. I'll put a link for this specific OCR that I used in the description. OCR stands for optimal character recognition, and it's basically just a better way of getting text from an image. Obviously, this is a free one, so it's probably not the highest quality. But, um, if you were to use like an OpenAI, um, analyze an image node, it's, it's just not really great yet. So you have this option here which can do some basic stuff, which is cool to play around with, of course. But, um, if you really need to get in, you know, like complicated PDFs and stuff like that, you probably want to use a third party. OCR. So anyways, we're setting up this request here. Of course, you will, um, you put in the endpoint, you need to put in your API key, and then I pretty much just told it that we're loading in an NNN binary file. And then in the binary file, we're just looking for the input field called data, which is right here. Um, so yeah, that's pretty much it. We'll hit test step, and then while this is running, I just wanted to say this workflow that you see right here will be available for download in the free school community, link for that will be down in the description. You'll just download the workflow and then you can import it straight into your N8N. You'll have it up and running right away. And then if you're looking to go a little bit deeper, you want to go into some deep dives, some hands-on learning, some real product insights, then check out my paid community, link for that will also be down in the description. And then if you want me to sort of build out some stuff like that, or you're looking for some consulting services for your business, then check out the website, my website in the description as well, and you can book in a call. Anyways, so what we see here is we take the binary, the file, the JPEG file, and then once it goes through this HTTP request to this OCR, we're getting the actual parsed text back. So, um, let me just make this a little bigger. Can I not expand this? Okay, anyways, um, parsed text. So we're getting the invoice number, the date, the amount, billing address. We're getting all the information back, um, pretty much as we saw it right here. So that's what we're getting back. And from here, we're just parsing the information. So I had ChatGPT write this code. I didn't write this at all, of course. And all it's taking is it's taking this input and then it's just going to get us out the different fields for, you know, as you can see, invoice number, invoice date, total amount, billing address, due date, and notes. So that's all that's happening in this code node. We're just parsing out the text and we want them in separate fields so that in our Google Sheets node, or if we're going to use Airtable or Base Row, anything like that, we can just specify what columns we want, what data we want to go to which column. So, um, in the example, as you can see in our Google Sheets, we have the columns invoice date, invoice number, date, total amount, all this kind of stuff. And then if we are to, um, hit test step and pop back into our database, we will see that information will populate through because we were able to configure, you know, which information we want to go to which column. So that's all that's happening here. As you can see, we set up that kind of stuff right in this node. And then from there, this is what I was talking about where we wanted to have the original file that we sent over in our Telegram that got downloaded right here. We want this file to be put into our Google Drive of invoices, and we can see all the different invoices in case we want to just go reference the original image. So when we do this, we need to give the Google Drive node the binary that we want to actually be downloaded. So it's a little bit weird in N8N when you have a binary file like we see right here. It's hard to reference that back later because you can see we're getting binary, but in the schema we don't see the binary anywhere. In the table we don't see the binary anywhere. So it's hard to later reference it. It pretty much has to be, you know, the The binary has to be the node that feeds straight into the next node that needs to use that input field called data, which is binary. So if we run this again, all that we're doing here is we're just re-downloading the file. Um, we're referencing the node that we did earlier, which was over here, and we're just referencing the file ID that originally gave it. So these nodes are practically identical. So we're downloading the file, and then when we hop into this Google Drive node, we have the binary right here to actually reference again. So all we're doing here is we're setting up the file name, which I hardcoded in invoice square brackets, and then I used a formula to just say we want today's date. So we have invoice December 5th, 2024. And I played around with the formatting here. Actually, I'll keep it in here. But if we went to, if we went in here, right, and we changed the format, so we did this. Oh, okay. I have an extra. Anyway, so let's just do this again. So we have, we have now, right? $now gives us the date, and we don't want the invoice to come in like that. So if we do.format, we get it like this. We have the 4-digit year with the months and with the dates. And so all I did was I took away the year because I don't want that in the front. I came back and put the year in the end. And then I also wanted the month to be an actual, the full name rather than 12. So if I do one more M, it goes to the shortened full name, which is DES for December. And if I put one more M, it goes to the full December 5th, 2024. So that's all I did there. And then we just have to link to what, um, folder we want. It's in My Drive and we're uploading it to the folder called invoices. So we hit test step here. This is just extracting the— or not extracting, it's just downloading the file so I can put it in. And then this is basically a success message that says that we got it. You know, the image type is a JSON. Or JPEG, it gives us the link to that folder. And then if we come in here, we should see we just got the second one at 11:12. So we click on it, that's the original invoice. Okay. And then from there, we're pretty much done. So in the set note, all we're doing is we're giving the agent the invoice information and the file name. So in here we have the results from the OCR. So we have the text that we extracted. And then in here, we're just giving it the json.name, which came from our file, Google Drive file thing. And then here we're just giving it the actual name of the file that we just created, which is invoice with the date. And maybe you want to play around with that in case you're uploading multiple invoices in the same day. So, but this is just an example. So we're giving it this information so that the agent now has invoice information, the file name, and a link to the invoice database. And then we're telling it in here basically, you know, this prompt will be included in the workflow if you choose to download it, but we're giving it the, its role, it's a very simple role. We're giving it an example input and then giving it an example output. So the way we want it to be structured, we want it to be readable. We don't want it to output all the information it's getting, just kind of a high-level summary. So we'll hit test step here. We will see that we are getting, thanks for submitting the invoice. The total amount is this, the due date is this, and then some notes, and then once again the link. So from there, we're just feeding it into Telegram. As you can see, we just got this message back. It's very clean. It has, um, line breaks. It gives us the link to the database. And then, um, yeah, that's pretty much all it is. All we're doing is we have to configure in here the chat ID. So from the Telegram trigger— let me just go into this real quick— from the Telegram trigger, we're getting some stuff back. And if you see right here, we have a chat ID. This basically is just the identifier of this channel that we're texting the Telegram bot in. So that's why we need to make sure that we're responding to that chat ID. We give it the text, which is just the output from the agent. And then obviously with our window buffer memory, we're also giving it, you know, normally when you set up window buffer memory, it's going to do take from previous note automatically, but we wanted to define this below. And once again, we are doing the chat ID. So this key right here is the exact same key that we're going into here for the chat ID responding to the Telegram agent. So I know this one was a quick, simple build, but hopefully the workflow here has sparked some ideas for you. If you choose to download the file, you know, maybe you can play around with ways you can expand off the build, make it a little more production ready. One thing I wanted to mention real quick is I, if you notice, this was as a tools agent, even though it has no tools, simply because I started this off with a conversational agent, but it wasn't completely understanding my prompting the way I wanted it to. It wasn't outputting the information the way I wanted to, and I switched it to a tools agent. I gave it the same prompt. And it just seemed to work a little better. So that's the only reason I did that there. But if you guys enjoyed this one, please give it a like. Definitely helps me out. Let me know in the comments what else you want to see, and hopefully I'll see you guys in the school community or on some of the live calls in the paid community. So thanks, guys.










