[{"data":1,"prerenderedAt":453},["ShallowReactive",2],{"footer-primary":3,"footer-secondary":93,"footer-description":119,"beyond-the-core-media-ai-bundle":121,"beyond-the-core-media-ai-bundle-next":174,"sales-reps":201},{"items":4},[5,29,49,69],{"id":6,"title":7,"url":8,"page":8,"children":9},"522e608a-77b0-4333-820d-d4f44be2ade1","Solutions",null,[10,15,20,25],{"id":11,"title":12,"url":8,"page":13},"fcafe85a-a798-4710-9e7a-776fe413aae5","Headless CMS",{"permalink":14},"/solutions/headless-cms",{"id":16,"title":17,"url":8,"page":18},"79972923-93cf-4777-9e32-5c9b0315fc10","Backend-as-a-Service",{"permalink":19},"/solutions/backend-as-a-service",{"id":21,"title":22,"url":8,"page":23},"0fa8d0c1-7b64-4f6f-939d-d7fdb99fc407","Product Information",{"permalink":24},"/solutions/product-information-management",{"id":26,"title":27,"url":28,"page":8},"63946d54-6052-4780-8ff4-91f5a9931dcc","100+ Things to Build","https://directus.io/blog/100-tools-apps-and-platforms-you-can-build-with-directus",{"id":30,"title":31,"url":8,"page":8,"children":32},"8ab4f9b1-f3e2-44d6-919b-011d91fe072f","Resources",[33,37,41,45],{"id":34,"title":35,"url":36,"page":8},"f951fb84-8777-4b84-9e91-996fe9d25483","Documentation","https://docs.directus.io",{"id":38,"title":39,"url":40,"page":8},"366febc7-a538-4c08-a326-e6204957f1e3","Guides","https://docs.directus.io/guides/",{"id":42,"title":43,"url":44,"page":8},"aeb9128e-1c5f-417f-863c-2449416433cd","Community","https://directus.chat",{"id":46,"title":47,"url":48,"page":8},"da1c2ed8-0a77-49b0-a903-49c56cb07de5","Release Notes","https://github.com/directus/directus/releases",{"id":50,"title":51,"url":8,"page":8,"children":52},"d61fae8c-7502-494a-822f-19ecff3d0256","Support",[53,57,61,65],{"id":54,"title":55,"url":56,"page":8},"8c43c781-7ebd-475f-a931-747e293c0a88","Issue Tracker","https://github.com/directus/directus/issues",{"id":58,"title":59,"url":60,"page":8},"d77bb78e-cf7b-4e01-932a-514414ba49d3","Feature Requests","https://github.com/directus/directus/discussions?discussions_q=is:open+sort:top",{"id":62,"title":63,"url":64,"page":8},"4346be2b-2c53-476e-b53b-becacec626a6","Community Chat","https://discord.com/channels/725371605378924594/741317677397704757",{"id":66,"title":67,"url":68,"page":8},"26c115d2-49f7-4edc-935e-d37d427fb89d","Cloud Dashboard","https://directus.cloud",{"id":70,"title":71,"url":8,"page":8,"children":72},"49141403-4f20-44ac-8453-25ace1265812","Organization",[73,78,84,88],{"id":74,"title":75,"url":76,"page":77},"1f36ea92-8a5e-47c8-914c-9822a8b9538a","About","/about",{"permalink":76},{"id":79,"title":80,"url":81,"page":82},"b84bf525-5471-4b14-a93c-225f6c386005","Careers","#",{"permalink":83},"/careers",{"id":85,"title":86,"url":87,"page":8},"86aabc3a-433d-434b-9efa-ad1d34be0a34","Brand Assets","https://drive.google.com/drive/folders/1lBOTba4RaA5ikqOn8Ewo4RYzD0XcymG9?usp=sharing",{"id":89,"title":90,"url":8,"page":91},"8d2fa1e3-198e-4405-81e1-2ceb858bc237","Contact",{"permalink":92},"/contact",{"items":94},[95,101,107,113],{"id":96,"title":97,"url":8,"page":98,"children":100},"8a1b7bfa-429d-4ffc-a650-2a5fdcf356da","Cloud Policies",{"permalink":99},"/cloud-policies",[],{"id":102,"title":103,"url":81,"page":104,"children":106},"bea848ef-828f-4306-8017-6b00ec5d4a0c","License",{"permalink":105},"/bsl",[],{"id":108,"title":109,"url":81,"page":110,"children":112},"4e914f47-4bee-42b7-b445-3119ee4196ef","Terms",{"permalink":111},"/terms",[],{"id":114,"title":115,"url":81,"page":116,"children":118},"ea69eda6-d317-4981-8421-fcabb1826bfd","Privacy",{"permalink":117},"/privacy",[],{"description":120},"\u003Cp>A composable backend to build your Headless CMS, BaaS, and more.&nbsp;\u003C/p>",{"id":122,"slug":123,"vimeo_id":124,"description":125,"tile":126,"length":127,"resources":128,"people":132,"episode_number":139,"published":140,"title":141,"video_transcript_html":142,"video_transcript_text":143,"content":8,"status":144,"episode_people":145,"recommendations":163,"season":164,"seo":8},"63ef529e-3a79-4116-a8b3-e9741dc70b3f","media-ai-bundle","906133845","Esther speaks to community member Marcus about their Media AI Bundle - a group of extensions that allow extraction of key details using AI tools. ","d7ad67a6-de8b-4f29-a5a8-c17b05389e34",22,[129],{"name":130,"url":131},"Media AI Bundle on GitHub","https://github.com/Arood/directus-extension-media-ai-bundle",[133,136],{"name":134,"url":135},"Esther Agbaje","https://twitter.com/_estheradebayo",{"name":137,"url":138},"Marcus Olovsson","https://marcusolovsson.com/",2,"2024-02-20","Media AI Bundle","\u003Cp>Speaker 0: But I'm also open to add more AI features, depending on use cases.\u003C/p>\u003Cp>Speaker 1: Hi there, and welcome to another episode of the Beyond the Core Show. It's a director show where we shine the spotlight on extension developers in the community. My name is Esther Agbaji, and I work as a developer advocate at Directus. And today, I'm joined by a super community member, Ahud. Ahud is the community winner of the AI hackathon that held a couple of months back, and he won the hackathon by creating the media AI bundle extension.\u003C/p>\u003Cp>And today, he's here with me to share all about the exciting journey to develop Hynis Extension and some of its features. So thank you, Arud, for joining me here. Could you share, like, some background about yourself and how you get to know about directors?\u003C/p>\u003Cp>Speaker 0: Sure. I I work as a developer, at an agency. Okay. And I was looking for, alternatives to CMSs like WordPress, for example, but I wanted something more, API focused.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: So so we had so we could find something that works with larger projects, and more, like, apps and such. And after trying some of them out, I I wasn't really happy with how they worked. They weren't, like, easy to use for the users, at least in my opinion. But then in a Reddit post, I think it was, someone was mentioning, directors and, like, how it was. They they said it was fantastic, but the the it was kind of, under the radar, at that time.\u003C/p>\u003Cp>So Okay. I checked it out, and I liked it too much. So, I started trying to, like, get it approved to to be used in our agency.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: And now we have successfully rolled out a few projects using it. And so far, it's been great.\u003C/p>\u003Cp>Speaker 1: Interesting. Interesting. And what's your favorite director's feature?\u003C/p>\u003Cp>Speaker 0: I think it's the interface. Okay. How extensible it is, and how how I can fine tune it for the editors.\u003C/p>\u003Cp>Speaker 1: Okay. Okay. So you like the fact that, like, it's very intuitive and is also extensible. Yeah. Yeah.\u003C/p>\u003Cp>I'm sure you probably like the extension feature because you've created not just 1 or 2 extensions at least that I know of. And, yeah, we are here to talk about the media AI bundle, which is a really cool extension. I saw the demo that you did during submission, and it was really good. So, what was the motivation for actually creating this extension?\u003C/p>\u003Cp>Speaker 0: It started off as, idea for a personal project of mine. I wanted to be able to take pictures, of sticky notes.\u003C/p>\u003Cp>Speaker 1: Interesting.\u003C/p>\u003Cp>Speaker 0: Like photos with my phone and upload them to a Kanban board or similar. So that's what got me started. I was I had some APIs in mind that I wanted to use, but now I had a like, an excuse to get it working in directors. So I started working on the, an operations bundle. And then I realized that this could be used for much more.\u003C/p>\u003Cp>For example, the the integration with alt text dot io so you can get alt text for images. So that kind of, formed it into becoming the media, bundle.\u003C/p>\u003Cp>Speaker 1: Okay. Okay. Nice to hear. So you mentioned the old text. Is it like an AI API?\u003C/p>\u003Cp>Speaker 0: Yeah.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: So it's like a service you sign up for, and they they transform the image into a readable text, like a sentence or\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: Sentences for that describes the image.\u003C/p>\u003Cp>Speaker 1: Okay. Okay. So, basically, the extension that you created, you upload an image, and it just gives you the old text or even if it's a screenshot of maybe, you know, text on a piece of paper, you can also read and extract that text also. Right?\u003C/p>\u003Cp>Speaker 0: Yeah. And I have 2 two operations currently in the bundle. 1 is for the, one I call describe, image, which does the alt text thing. It takes the image and extracts the text or sentence. You can also use Amazon Web Services, but then you'll only get, like, a comma separated list of words.\u003C/p>\u003Cp>So it's not as fancy. Okay. But it's an alternate alternative Alternative. Okay. Yeah.\u003C/p>\u003Cp>And the other one is the extract text operation that actually reads, with, like, OCR, and tries to find text in an image. So you can extract.\u003C/p>\u003Cp>Speaker 1: Okay. Extract the text from an image. Yeah. Alright. Yeah.\u003C/p>\u003Cp>Would you like to share your screen? So just walk us through maybe some parts of the code and then a quick demo of the extension?\u003C/p>\u003Cp>Speaker 0: So as I mentioned, it's a bundle. So you have a source directory with the different operations in this case. And the plan was to add more, as I get more, like, cases\u003C/p>\u003Cp>Speaker 1: Mhmm.\u003C/p>\u003Cp>Speaker 0: Use cases.\u003C/p>\u003Cp>Speaker 1: Use cases. Yeah.\u003C/p>\u003Cp>Speaker 0: So here we have the describe image, and the extract text from the image operation. So if you take the describe the image, I think that's the more more fun one.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: We have the front end part or the app part Mhmm. Which defines the operation. And here we have some settings that you can set up. You can choose if you want to use alt text dot io or Amazon Amazon\u003C/p>\u003Cp>Speaker 1: Cognition. Okay.\u003C/p>\u003Cp>Speaker 0: And you you will need API keys for these and Mhmm. You set them up in your environment variables. Okay. But I'm hoping to add some kind of, like, settings page or something, where you can do it a bit easier.\u003C/p>\u003Cp>Speaker 1: Mhmm.\u003C/p>\u003Cp>Speaker 0: And then on the, client side or or the server side\u003C/p>\u003Cp>Speaker 1: Service side. Yeah.\u003C/p>\u003Cp>Speaker 0: We have the API for this, or the director's API. So we get an image. You you can set up, like, a hook for or a flow with a hook for file upload.\u003C/p>\u003Cp>Speaker 1: Mhmm.\u003C/p>\u003Cp>Speaker 0: And then we'll check if we have, like, a image, if the file is an image, and then we will create a buffer from it so we can send the entire image from\u003C/p>\u003Cp>Speaker 1: Mhmm.\u003C/p>\u003Cp>Speaker 0: To this to the API.\u003C/p>\u003Cp>Speaker 1: Okay. So you first verify if it's an image before you then send it.\u003C/p>\u003Cp>Speaker 0: Yeah. So Okay. We don't waste any, like, credits or such. Okay. And then we get a result.\u003C/p>\u003Cp>And, I try to, like, return a common format for it. So it shouldn't depend matter which API you use. You should have, like, a you should be able to expect what kind of\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: Properties it will return, and they are documented in the readme.\u003C/p>\u003Cp>Speaker 1: In the readme. Okay.\u003C/p>\u003Cp>Speaker 0: So in this case, you get the description. But I also have, like, a dollar param row property that has the original payload. So if you want to get something specific from Amazon or from alt text, you can\u003C/p>\u003Cp>Speaker 1: You can get\u003C/p>\u003Cp>Speaker 0: that as well.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: Nice. Without having to exchange the the extension. And the same thing here for Amazon. The API used there is called detect labels.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: Yeah.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: Nice. That's how it works.\u003C/p>\u003Cp>Speaker 1: That's That's the one for describing the image. Yeah? Yeah. Okay. Okay.\u003C/p>\u003Cp>Let's check out the one for, like, extracting the text from image briefly.\u003C/p>\u003Cp>Speaker 0: Yeah. It works pretty much the same, except it doesn't have it only has Amazon recognition for now.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: I am we I am planning to add ash Azure Vision AI.\u003C/p>\u003Cp>Speaker 1: Azure. Okay.\u003C/p>\u003Cp>Speaker 0: Because we use that a lot at my work.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: But for now, it's just Amazon.\u003C/p>\u003Cp>Speaker 1: Alright.\u003C/p>\u003Cp>Speaker 0: But the principle is the same. We we you you we receive an image. We take the stream, and send it to, an API. Mhmm. And the only difference here is, of course, which, API we're sending it to.\u003C/p>\u003Cp>So in this case, it's the detect text command\u003C/p>\u003Cp>Speaker 1: Command. Okay.\u003C/p>\u003Cp>Speaker 0: On the Amazon SDK. And in this case, you get a bit more parameters back, property spec. So you can get either the I try to transform them into lines, with text and, like, where in the image it's located. But you also get a full text if you're just trying to, like, transcribe an image.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: Okay. So if you want that quick and easy fix, you can use the full text form.\u003C/p>\u003Cp>Speaker 1: Full text. Okay. Okay.\u003C/p>\u003Cp>Speaker 0: But if you want to, like, get down with the greater details, you can use the lines.\u003C/p>\u003Cp>Speaker 1: The lines. Yeah. That's very clear and nifty. Did you face any challenges or issues when you were building, you know, all of these bundles?\u003C/p>\u003Cp>Speaker 0: I think the for for the most part, it's it's been pretty\u003C/p>\u003Cp>Speaker 1: No. It's pretty straightforward. Okay.\u003C/p>\u003Cp>Speaker 0: Yeah. Of course, the the I guess the one thing that was a bit tricky is, like, trying to find the right services. I know that that has been added to the documentation now.\u003C/p>\u003Cp>Speaker 1: Yes. It has.\u003C/p>\u003Cp>Speaker 0: When I wrote this, there wasn't really much.\u003C/p>\u003Cp>Speaker 1: Wasn't. Yeah. True. I remember. Yeah.\u003C/p>\u003Cp>True. But now we've included services in the docs.\u003C/p>\u003Cp>Speaker 0: Yeah. So getting the, like, asset service and figuring out how that works, took a bit of time. It wasn't wasn't hard, but you had to, like, shake your house.\u003C/p>\u003Cp>Speaker 1: Again, to the core and the doors.\u003C/p>\u003Cp>Speaker 0: Yeah. But that's also a strength of directors, I think, yeah, that you can do that.\u003C/p>\u003Cp>Speaker 1: Yeah. Can you imagine that? Okay. That's cool. Let's go into the bundle to see how it works in directors.\u003C/p>\u003Cp>Speaker 0: Yes. So I have a flow here. Let me see in a bit.\u003C/p>\u003Cp>Speaker 1: Yeah. Yeah. It's good now.\u003C/p>\u003Cp>Speaker 0: Called file uploads.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: And here we have when I created this, I made a trigger with non blocking action with the scope files.\u003C/p>\u003Cp>Speaker 1: Files that's uploaded.\u003C/p>\u003Cp>Speaker 0: Mhmm. Currently, there's no filter for it. I think I'm gonna write a feature request for that. I think it would be useful to, like, be wait for the\u003C/p>\u003Cp>Speaker 1: Before I wait for some time before I\u003C/p>\u003Cp>Speaker 0: finish before fires up. Yeah. Because right now, you you when you upload it, you you get sent to the, like, start page, and you don't see the changes until they have performed. So you have to wait a bit.\u003C/p>\u003Cp>Speaker 1: I see. Yeah.\u003C/p>\u003Cp>Speaker 0: But for now, it works well with the non blocking one. Then we have the operation from my extension, describe image. And here we are select which API we want to use and you are able to change the field if you want to. But in most cases, it's the trigger dot key, which is the image you have uploaded. But I'm left it a bit configurable if you have more advanced flows.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: Then when this is run, you get some data. So I have an update data operation here.\u003C/p>\u003Cp>Speaker 1: Mhmm.\u003C/p>\u003Cp>Speaker 0: Where I simply just update the, payload of the file that's created in Directus. So in this case, I put the description from the operation into the description field.\u003C/p>\u003Cp>Speaker 1: Mhmm. Yeah.\u003C/p>\u003Cp>Speaker 0: In some cases, I might put a transcript or similar in between just to clean up a bit, especially if I use the other, operation that can the the extract text one. So if you if you would need to, like, make sure that it's not too long or something like that.\u003C/p>\u003Cp>Speaker 1: Okay. Do that. I just remembered, did you, maybe handle errors and all in the whole, you know, operations?\u003C/p>\u003Cp>Speaker 0: Some errors, but in most cases, it will silently fail. Like, if you upload a image that isn't or a file that isn't an image. It will just silently It's a test. Failed.\u003C/p>\u003Cp>Speaker 1: So you don't Okay.\u003C/p>\u003Cp>Speaker 0: Yeah. So you don't get, like, a lot of error messages. But, I'm not sure if I I think I have some,\u003C/p>\u003Cp>Speaker 1: yeah, some error message. Okay.\u003C/p>\u003Cp>Speaker 0: Oh, actually, I see. You seem to throw even if the image is\u003C/p>\u003Cp>Speaker 1: If it's not image, it threw as an error also. Yeah.\u003C/p>\u003Cp>Speaker 0: Or maybe I added that. Yeah. Anyway Yeah. So you can do a failed state if you want.\u003C/p>\u003Cp>Speaker 1: Path also. Okay. Okay. Yeah. I think that's fine.\u003C/p>\u003Cp>Yeah. Would you like to maybe try with could we do a demo of just uploading a an image or a screenshot? Sure.\u003C/p>\u003Cp>Speaker 0: Just gonna find the good image to upload. Okay. So here we have my file library. And Mhmm. I'm gonna drop an image here from my other screen.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: And we wait a little bit, and then we check if we get\u003C/p>\u003Cp>Speaker 1: Nice. The tracking that we get. White cut. Yeah. Sitting on a blanket indicate very descriptive to the point.\u003C/p>\u003Cp>Yeah. Yeah. That makes a lot of sense. Lovely.\u003C/p>\u003Cp>Speaker 0: And, of course, the the big advantage of this would be, like, to have alternative texts in on websites if you have, someone with a disability so they can't see. Yes. Yep. Then they can get this re read up instead.\u003C/p>\u003Cp>Speaker 1: I would just love to know, in terms of improvements to the extension, the things that, you know, features that you would like to add, what are some of the features or improvements going forward that you love to add to the extension?\u003C/p>\u003Cp>Speaker 0: Yeah. So one thing I want to add is, like a settings page.\u003C/p>\u003Cp>Speaker 1: So The settings page?\u003C/p>\u003Cp>Speaker 0: Yeah. So so you can ease more easily add the API keys, I'm thinking. I'm also thinking, like, that that will be needed for, for example, the marketplace.\u003C/p>\u003Cp>Speaker 1: Yes.\u003C/p>\u003Cp>Speaker 0: Perhaps or at least it will make it easier. But I'm also open to add more AI features, depending on use cases. I had one, for example, with, trying to detect objects in an image. Okay. So that might be something we I'm gonna add later on.\u003C/p>\u003Cp>And as I mentioned, support for other services like Azure, perhaps Google, if if, anyone needs that.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: So so if anyone has any suggestions, I recommend posting it in on GitHub.\u003C/p>\u003Cp>Speaker 1: Feel free to. Yeah. Either comment or make an issue or just even comment in our Discord channel as well. Thank you. Alright.\u003C/p>\u003Cp>Yeah. I'm really excited to see when the marketplace launches. Hopefully, we're able to have this extension in the marketplace because I know lots of people would also find it equally useful and important in their projects as well. Alright. So the very final question I have is, I know you've also built the Jira panel.\u003C/p>\u003Cp>The last hackathon you worked on Jira panels. So what's will I say advice or you know? Yeah, advice would you have or give to anyone that is building extensions? Because you have bit of more experience in that aspect. So anyone building a custom director's extension.\u003C/p>\u003Cp>Speaker 0: I think my advice would be to not be afraid of looking into the, direct to source code, because there's a lot of it's built very modular. So a lot of the existing interfaces and operations and all of that are available. So you can see how they are built. So even if the even if you can't find anything in if you're looking for something in the documentation and not finding anything that you might find how, under interface or operation, have sold.\u003C/p>","But I'm also open to add more AI features, depending on use cases. Hi there, and welcome to another episode of the Beyond the Core Show. It's a director show where we shine the spotlight on extension developers in the community. My name is Esther Agbaji, and I work as a developer advocate at Directus. And today, I'm joined by a super community member, Ahud. Ahud is the community winner of the AI hackathon that held a couple of months back, and he won the hackathon by creating the media AI bundle extension. And today, he's here with me to share all about the exciting journey to develop Hynis Extension and some of its features. So thank you, Arud, for joining me here. Could you share, like, some background about yourself and how you get to know about directors? Sure. I I work as a developer, at an agency. Okay. And I was looking for, alternatives to CMSs like WordPress, for example, but I wanted something more, API focused. Okay. So so we had so we could find something that works with larger projects, and more, like, apps and such. And after trying some of them out, I I wasn't really happy with how they worked. They weren't, like, easy to use for the users, at least in my opinion. But then in a Reddit post, I think it was, someone was mentioning, directors and, like, how it was. They they said it was fantastic, but the the it was kind of, under the radar, at that time. So Okay. I checked it out, and I liked it too much. So, I started trying to, like, get it approved to to be used in our agency. Okay. And now we have successfully rolled out a few projects using it. And so far, it's been great. Interesting. Interesting. And what's your favorite director's feature? I think it's the interface. Okay. How extensible it is, and how how I can fine tune it for the editors. Okay. Okay. So you like the fact that, like, it's very intuitive and is also extensible. Yeah. Yeah. I'm sure you probably like the extension feature because you've created not just 1 or 2 extensions at least that I know of. And, yeah, we are here to talk about the media AI bundle, which is a really cool extension. I saw the demo that you did during submission, and it was really good. So, what was the motivation for actually creating this extension? It started off as, idea for a personal project of mine. I wanted to be able to take pictures, of sticky notes. Interesting. Like photos with my phone and upload them to a Kanban board or similar. So that's what got me started. I was I had some APIs in mind that I wanted to use, but now I had a like, an excuse to get it working in directors. So I started working on the, an operations bundle. And then I realized that this could be used for much more. For example, the the integration with alt text dot io so you can get alt text for images. So that kind of, formed it into becoming the media, bundle. Okay. Okay. Nice to hear. So you mentioned the old text. Is it like an AI API? Yeah. Okay. So it's like a service you sign up for, and they they transform the image into a readable text, like a sentence or Okay. Sentences for that describes the image. Okay. Okay. So, basically, the extension that you created, you upload an image, and it just gives you the old text or even if it's a screenshot of maybe, you know, text on a piece of paper, you can also read and extract that text also. Right? Yeah. And I have 2 two operations currently in the bundle. 1 is for the, one I call describe, image, which does the alt text thing. It takes the image and extracts the text or sentence. You can also use Amazon Web Services, but then you'll only get, like, a comma separated list of words. So it's not as fancy. Okay. But it's an alternate alternative Alternative. Okay. Yeah. And the other one is the extract text operation that actually reads, with, like, OCR, and tries to find text in an image. So you can extract. Okay. Extract the text from an image. Yeah. Alright. Yeah. Would you like to share your screen? So just walk us through maybe some parts of the code and then a quick demo of the extension? So as I mentioned, it's a bundle. So you have a source directory with the different operations in this case. And the plan was to add more, as I get more, like, cases Mhmm. Use cases. Use cases. Yeah. So here we have the describe image, and the extract text from the image operation. So if you take the describe the image, I think that's the more more fun one. Okay. We have the front end part or the app part Mhmm. Which defines the operation. And here we have some settings that you can set up. You can choose if you want to use alt text dot io or Amazon Amazon Cognition. Okay. And you you will need API keys for these and Mhmm. You set them up in your environment variables. Okay. But I'm hoping to add some kind of, like, settings page or something, where you can do it a bit easier. Mhmm. And then on the, client side or or the server side Service side. Yeah. We have the API for this, or the director's API. So we get an image. You you can set up, like, a hook for or a flow with a hook for file upload. Mhmm. And then we'll check if we have, like, a image, if the file is an image, and then we will create a buffer from it so we can send the entire image from Mhmm. To this to the API. Okay. So you first verify if it's an image before you then send it. Yeah. So Okay. We don't waste any, like, credits or such. Okay. And then we get a result. And, I try to, like, return a common format for it. So it shouldn't depend matter which API you use. You should have, like, a you should be able to expect what kind of Okay. Properties it will return, and they are documented in the readme. In the readme. Okay. So in this case, you get the description. But I also have, like, a dollar param row property that has the original payload. So if you want to get something specific from Amazon or from alt text, you can You can get that as well. Okay. Nice. Without having to exchange the the extension. And the same thing here for Amazon. The API used there is called detect labels. Okay. Yeah. Okay. Nice. That's how it works. That's That's the one for describing the image. Yeah? Yeah. Okay. Okay. Let's check out the one for, like, extracting the text from image briefly. Yeah. It works pretty much the same, except it doesn't have it only has Amazon recognition for now. Okay. I am we I am planning to add ash Azure Vision AI. Azure. Okay. Because we use that a lot at my work. Okay. But for now, it's just Amazon. Alright. But the principle is the same. We we you you we receive an image. We take the stream, and send it to, an API. Mhmm. And the only difference here is, of course, which, API we're sending it to. So in this case, it's the detect text command Command. Okay. On the Amazon SDK. And in this case, you get a bit more parameters back, property spec. So you can get either the I try to transform them into lines, with text and, like, where in the image it's located. But you also get a full text if you're just trying to, like, transcribe an image. Yeah. Okay. So if you want that quick and easy fix, you can use the full text form. Full text. Okay. Okay. But if you want to, like, get down with the greater details, you can use the lines. The lines. Yeah. That's very clear and nifty. Did you face any challenges or issues when you were building, you know, all of these bundles? I think the for for the most part, it's it's been pretty No. It's pretty straightforward. Okay. Yeah. Of course, the the I guess the one thing that was a bit tricky is, like, trying to find the right services. I know that that has been added to the documentation now. Yes. It has. When I wrote this, there wasn't really much. Wasn't. Yeah. True. I remember. Yeah. True. But now we've included services in the docs. Yeah. So getting the, like, asset service and figuring out how that works, took a bit of time. It wasn't wasn't hard, but you had to, like, shake your house. Again, to the core and the doors. Yeah. But that's also a strength of directors, I think, yeah, that you can do that. Yeah. Can you imagine that? Okay. That's cool. Let's go into the bundle to see how it works in directors. Yes. So I have a flow here. Let me see in a bit. Yeah. Yeah. It's good now. Called file uploads. Okay. And here we have when I created this, I made a trigger with non blocking action with the scope files. Files that's uploaded. Mhmm. Currently, there's no filter for it. I think I'm gonna write a feature request for that. I think it would be useful to, like, be wait for the Before I wait for some time before I finish before fires up. Yeah. Because right now, you you when you upload it, you you get sent to the, like, start page, and you don't see the changes until they have performed. So you have to wait a bit. I see. Yeah. But for now, it works well with the non blocking one. Then we have the operation from my extension, describe image. And here we are select which API we want to use and you are able to change the field if you want to. But in most cases, it's the trigger dot key, which is the image you have uploaded. But I'm left it a bit configurable if you have more advanced flows. Yeah. Then when this is run, you get some data. So I have an update data operation here. Mhmm. Where I simply just update the, payload of the file that's created in Directus. So in this case, I put the description from the operation into the description field. Mhmm. Yeah. In some cases, I might put a transcript or similar in between just to clean up a bit, especially if I use the other, operation that can the the extract text one. So if you if you would need to, like, make sure that it's not too long or something like that. Okay. Do that. I just remembered, did you, maybe handle errors and all in the whole, you know, operations? Some errors, but in most cases, it will silently fail. Like, if you upload a image that isn't or a file that isn't an image. It will just silently It's a test. Failed. So you don't Okay. Yeah. So you don't get, like, a lot of error messages. But, I'm not sure if I I think I have some, yeah, some error message. Okay. Oh, actually, I see. You seem to throw even if the image is If it's not image, it threw as an error also. Yeah. Or maybe I added that. Yeah. Anyway Yeah. So you can do a failed state if you want. Path also. Okay. Okay. Yeah. I think that's fine. Yeah. Would you like to maybe try with could we do a demo of just uploading a an image or a screenshot? Sure. Just gonna find the good image to upload. Okay. So here we have my file library. And Mhmm. I'm gonna drop an image here from my other screen. Okay. And we wait a little bit, and then we check if we get Nice. The tracking that we get. White cut. Yeah. Sitting on a blanket indicate very descriptive to the point. Yeah. Yeah. That makes a lot of sense. Lovely. And, of course, the the big advantage of this would be, like, to have alternative texts in on websites if you have, someone with a disability so they can't see. Yes. Yep. Then they can get this re read up instead. I would just love to know, in terms of improvements to the extension, the things that, you know, features that you would like to add, what are some of the features or improvements going forward that you love to add to the extension? Yeah. So one thing I want to add is, like a settings page. So The settings page? Yeah. So so you can ease more easily add the API keys, I'm thinking. I'm also thinking, like, that that will be needed for, for example, the marketplace. Yes. Perhaps or at least it will make it easier. But I'm also open to add more AI features, depending on use cases. I had one, for example, with, trying to detect objects in an image. Okay. So that might be something we I'm gonna add later on. And as I mentioned, support for other services like Azure, perhaps Google, if if, anyone needs that. Okay. So so if anyone has any suggestions, I recommend posting it in on GitHub. Feel free to. Yeah. Either comment or make an issue or just even comment in our Discord channel as well. Thank you. Alright. Yeah. I'm really excited to see when the marketplace launches. Hopefully, we're able to have this extension in the marketplace because I know lots of people would also find it equally useful and important in their projects as well. Alright. So the very final question I have is, I know you've also built the Jira panel. The last hackathon you worked on Jira panels. So what's will I say advice or you know? Yeah, advice would you have or give to anyone that is building extensions? Because you have bit of more experience in that aspect. So anyone building a custom director's extension. I think my advice would be to not be afraid of looking into the, direct to source code, because there's a lot of it's built very modular. So a lot of the existing interfaces and operations and all of that are available. So you can see how they are built. So even if the even if you can't find anything in if you're looking for something in the documentation and not finding anything that you might find how, under interface or operation, have sold.","published",[146,153],{"people_id":147},{"id":148,"first_name":149,"last_name":150,"avatar":151,"bio":152,"links":8},"60c9fd68-1b7a-4423-97ac-c8768bd8227a","Esther","Agbaje","cff9cdc8-bb76-4fea-a9e3-74c40d3f8274","Educator",{"people_id":154},{"id":155,"first_name":156,"last_name":157,"avatar":158,"bio":8,"links":159},"2637c128-4c57-41f8-9b3c-bc98892ee125","Marcus","Olovsson","4dd3b6a1-ce81-42c9-a66f-f3c9ddf33018",[160],{"service":161,"url":162},"github","https://github.com/Arood",[],{"id":165,"number":166,"year":167,"episodes":168,"show":171},"9e90c8ed-0bf8-43bb-8c4e-29ece4187819",1,"2024",[169,122,170],"e22f53b4-e915-4b89-8057-6cccdcc58d5a","8f4235cb-a9f3-4d25-ab5a-0af8f0fc892e",{"title":172,"tile":173},"Beyond the Core","67399d60-cf53-404b-b5d4-a35b52850130",{"id":170,"slug":175,"season":165,"vimeo_id":176,"description":177,"tile":178,"length":179,"resources":180,"people":187,"episode_number":192,"published":193,"title":194,"video_transcript_html":195,"video_transcript_text":196,"content":8,"seo":8,"status":144,"episode_people":197,"recommendations":200},"pdf-generator","906150239","Esther speaks to community member Bart about TextToAnything - an extension which allows generation of PDFs, QRCodes and Barcodes within Directus through the TextToAnyThing API.\n\nLearn more about TextToAnything at texttoanything.nl/docs/directus.\n","10bc1cde-ffac-438d-b9c5-a7f554a5bfc5",18,[181,184],{"name":182,"url":183},"TextToAnything on GitHub","https://github.com/Attacler/TextToAnything-Directus",{"name":185,"url":186},"Text to Anything Docs","https://texttoanything.nl/docs/directus/",[188,189],{"name":134,"url":135},{"name":190,"url":191},"Bart Don","https://www.linkedin.com/in/bart-don-38b9a51b6/",3,"2024-03-19","PDF Generator","\u003Cp>Speaker 0: So the extensibility of Directus really drives me to watch Directus itself because it allows you to turn Directus into either a normal website, a CMS, for your, web shop, or even just a project's tool.\u003C/p>\u003Cp>Speaker 1: Hi. Hi. Hi, everyone. Welcome to another episode of the Beyond the Core Show. It's a director who will shine a spotlight on extensions that have been created by community members.\u003C/p>\u003Cp>As always, I'm your host, Esther Akbaje, developer advocate at directors. And today on this episode, I have with me Bart. I would like to say Bart is a super community member because he's really involved in community and has created a good number of extensions. So very excited to have this conversation, but thank you for joining me here today.\u003C/p>\u003Cp>Speaker 0: Hi, Esther. Thank you for having me. So, yeah, as you already said, I'm very active within the community, both with helping out and also creating new extensions. So\u003C/p>\u003Cp>Speaker 1: Okay. Yeah. It's good to have you. I'm excited for this conversation. Would you like to introduce yourself a bit more, maybe what you do, where you're based?\u003C/p>\u003Cp>Speaker 0: Sure. So I'm Bart Lund. I'm 23 years old. I'm from the Netherlands, and I'm actually a software engineer for a company that doesn't use directors, but that, of course, doesn't matter. Yeah.\u003C/p>\u003Cp>So in my free time, I've created a company with 2 friends of mine, and we're actually using Directus as the CMS for websites, web shops, and smaller back end tooling. Apart from that, I've been here since release, gonna date 42, if I'm correct. So that's almost 3 years.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: And I'm very active within the community. I'm trying to help out people whenever I can. So\u003C/p>\u003Cp>Speaker 1: Nice. Nice. I'm curious to know, where did you hear about Directus? Like, do you remember?\u003C/p>\u003Cp>Speaker 0: So I do remember we were talking about, like, what kind of CMS are we going to use? Because, obviously, Nuxt or something like it is not the only thing that, can handle data. So then we came across Trappy, and we were like, there are some limitations. It doesn't feel just right. And then we came across directors.\u003C/p>\u003Cp>Back then, it was a little bit of a mess because it was a release candidate, but we really, really liked how you can extend directors and do anything with it, as you'd like. So then we decided, like, hey, we're going to do directors, man. That's\u003C/p>\u003Cp>Speaker 1: Here you are. Right. Together. Yeah. Yeah.\u003C/p>\u003Cp>And you've actually done so many amazing or built so many amazing extensions with directors. I know today we are here to talk about the text to anything extension. So just tell me more about it. Like, what does this extension really do?\u003C/p>\u003Cp>Speaker 0: Text to anything is a generic name because it's going to do a lot of things. So the main focus right now is on generating PDF Mhmm. Both from your raw HTML if you want to provide it, or you can use a template, which is also based on HTML, but you can view it inside of the visual editor. And you can, of course, use parameters inside of it. Next to that, it's also, allowing you to generate QR codes and barcodes.\u003C/p>\u003Cp>And in the future, there will also be, like, HTML towards an image or just an image towards text itself. So we have OCR. But those are just future plans for now.\u003C/p>\u003Cp>Speaker 1: Okay. Okay. I I know that when I initially saw this extension, it was very exciting to me because I'd actually not seen a tool that could do so many things and still seem very simple. So, what really inspired this extension? Like, what what made you feel like, okay.\u003C/p>\u003Cp>I think this extension is something that will be useful to the community?\u003C/p>\u003Cp>Speaker 0: So first of all, we, of course, have to create, invoices ourselves and PDFs for them. Okay. Because we're also, so I left the company. It's a little side story, but I left the company for, like, a half year now. But we also need to generate PDFs.\u003C/p>\u003Cp>We also\u003C/p>\u003Cp>Speaker 1: Mhmm.\u003C/p>\u003Cp>Speaker 0: Are using it like as our CMS. So we have our users, our invoices, our projects inside of, directors. So we needed to create PDFs. At first, we were using a hacky workaround. And now I actually decided to, like, create an official extension for it.\u003C/p>\u003Cp>And I also saw inside of the community that people were asking, like, how can we ever create a PDF if it's not in direct us already? So that's why I decided to make an extension for it.\u003C/p>\u003Cp>Speaker 1: Yeah. That's definitely interesting. I can't really wait to see it in action today. So, before we jump into the code, what what would you say was one of the most difficult things or challenges that you faced when you were developing this extension?\u003C/p>\u003Cp>Speaker 0: So the main thing that's very hard about PDF is that you need something that renders the PDF. So in your browser, it's really easy because you have HTML, CSS already rendered for you. But when you're talking about only back end, you don't want to spin up a browser just to create your PDF. So at first, I started actually doing that. So I tried to integrate the browser.\u003C/p>\u003Cp>It's called Puppeteer inside of your your directives, but it requires a lot of resources like CPU, RAM. And it doesn't feel right because you're make using a CMS. And for every CMS instance, you're also spawning a browser to generate PDFs for\u003C/p>\u003Cp>Speaker 1: you. Okay.\u003C/p>\u003Cp>Speaker 0: So to tackle that, I actually created a API, which basically, allows you to post any, HTML or whatever, and it will convert it into the PDF for you and give it back.\u003C/p>\u003Cp>Speaker 1: Okay. Okay. Yeah. It makes a lot of sense. So would you like to share your screen and just walk us through, like, code, some code decisions that you had to make and just talk about what each code block does?\u003C/p>\u003Cp>Speaker 0: So whenever you're creating an extension, you probably need multiple folders or directories, or even extensions themselves. So you can create a bundle a bundle to, bundle it altogether. And in my case, I have a lot of extensions that are required to make it all work. Okay. So we start off with the installation hook.\u003C/p>\u003Cp>The installation hook is actually meant to create any collections that are not non existent at the moment and also add any fields if they are not there. Next to that it also talks to my API so you can actually get the pdfs or whatever.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: So first we actually create the templates collection so you can so we can use something to store the templates and the data about it.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: Then in case there are no fields yet for that collection, we're creating the actual fields.\u003C/p>\u003Cp>Speaker 1: Alright.\u003C/p>\u003Cp>Speaker 0: And the reason why I'm doing it like this is if something happens or you delete a field by accident the code will run next time you restart directives and it's just correct.\u003C/p>\u003Cp>Speaker 1: Mhmm. Okay. Makes sense. Yeah.\u003C/p>\u003Cp>Speaker 0: And then we also need an API key because there's a paywall between the API of mine and Directus itself. The reason for this is that I actually have some costs that I sadly have to make to make this API work. So in this case, it adds a field to director settings, which you can then of course populate later on. We have the same with some other fields and then we get into the actual interesting part. Yeah.\u003C/p>\u003Cp>So within the global dish, which is like a global variable within your node. Yes. Runtime. I'm creating a text to anything, variable, which allows you to do any action that you can do within flows also inside of your own code. So if you have a hook or a schedule that needs to generate barcodes, PDF codes, you can just do it.\u003C/p>\u003Cp>And to keep it everything as minimal as possible, Directus is using Axios. So I'm also using that to call out the API itself.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: Apart from that, it's fairly simple to me. I'm not sure if you see anything that makes you wonder. Likewise,\u003C/p>\u003Cp>Speaker 1: you can do that. No. Just the generate PDF. You have how many, functions do you have? You have the generate PDF function.\u003C/p>\u003Cp>What other function do you have? PDF template version.\u003C/p>\u003Cp>Speaker 0: We have those 4 at the moment.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: And the generate PDF from template actually reuses the generate PDF function, but it just parses your template and make sure that everything goes correctly. Okay. So apart from that, we, of course, also have the flow nodes because you can also use them inside the flow. So one of the things that we have here is really short, basically for every flow node because it's using the, functions that I just showed you.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: One difficulty that I actually had was to make a selection, like an input select field within the flows. So you can actually select the template that you want to use. So in the end I created an interface for it that allows you to do just that. You will probably see it within a second.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: I'm not sure if you want to see any other things. I'm\u003C/p>\u003Cp>Speaker 1: sure I I know you have a GitHub, repo, so everyone can just like, anyone interested in digging more on the code can just check it out. Yeah.\u003C/p>\u003Cp>Speaker 0: So within directives, after you've installed the extension, you have a module.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: Which allows you to create any template you like. So, for example, this is a really simple one and actually does not hold any values. Okay. For example, this one. So on the left, it allows you to type any template data that you actually want to use.\u003C/p>\u003Cp>On the right, you can actually see, like, a preview of how it would look like inside of the PDF itself.\u003C/p>\u003Cp>Speaker 1: Yeah. So this how it will look like as a PDF. Right?\u003C/p>\u003Cp>Speaker 0: Yes. And right now Okay. This is just for demo purposes. So it's not very stylish, but you can just use any HTML that you want and place it inside of the source code. This, by the way, is the what you see is what you get editor from the Reactors itself.\u003C/p>\u003Cp>Okay. It has the same functionality built in.\u003C/p>\u003Cp>Speaker 1: Interesting. Interesting. And yeah. Okay. Yeah.\u003C/p>\u003Cp>That makes a lot of sense. So, basically, you just put in any text, and it just gives you the PDF format straight up. What if I'm interested in maybe getting a barcode? How would that\u003C/p>\u003Cp>Speaker 0: look like? So barcodes are not require, do not require any template, obviously. Yeah. So if we go into flows we actually just created this flow. So in here, you can actually use the operation for that.\u003C/p>\u003Cp>So if you want the barcode, you can Mhmm. Put in the type of the barcode, the contents, and you can also select type. I actually included a library that, has a lot of types.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: And from there, you can also adjust the width and the height. And if you want, you can also include any text. So because barcodes are more static than the actual PDF that you want to generate, I decided to not create any editor for it.\u003C/p>\u003Cp>Speaker 1: Okay. Okay. Yeah. So, basically, that's it. And and I'm sure it's similar process for, QR code as well.\u003C/p>\u003Cp>Right?\u003C/p>\u003Cp>Speaker 0: Yes. That's true. Okay. So I can actually show you what it's doing. In here, I have created a sample collection with invoices.\u003C/p>\u003Cp>Speaker 1: Okay.\u003C/p>\u003Cp>Speaker 0: And in here, we have an invoice number, name, date, and also a relationship with the actual items that I have on this invoice. So then we have flows, and we can actually generate the PDF for it.\u003C/p>\u003Cp>Speaker 1: PDF. Okay.\u003C/p>\u003Cp>Speaker 0: Yeah. So it's actually going to use the templates that we just saw inside of the editor. And once it's done, we actually have a PDF in here.\u003C/p>\u003Cp>Speaker 1: Oh, nice.\u003C/p>\u003Cp>Speaker 0: Yeah. So I'll show you the logs after this. Okay. But here we have the PDF template that we just had.\u003C/p>\u003Cp>Speaker 1: Interesting. Love it. I can see myself using this extension. Really interesting.\u003C/p>\u003Cp>Speaker 0: Nice. So in the logs, you will actually wait. Inside of the flow, you can see, like, hey. We have our trigger. We have the button, and it's going to read the invoices.\u003C/p>\u003Cp>So we actually have, like, the invoice data, and then we're going to use the generate from template, which allows you to give it any name. You can also use the variables in like normal flow supported. And then you can actually select a template, which you just created inside of the settings step. Yeah. And here we have our template variables.\u003C/p>\u003Cp>So in here, you'll see that you actually get returned an ID. So if you want to make sure that the name is correct or that it's inside of the correct folder or link it up to any older record that you have, you can just use this ID and proceed with it.\u003C/p>\u003Cp>Speaker 1: Yeah. Very useful. Very useful. See a lot of things. You like, you thought out, you know, how this extension can be very useful for many people and how it can be very efficient for them.\u003C/p>\u003Cp>So, yeah, lots of thoughts has gone into it here. Yeah. So in terms of how the community can be, involved in this extension, like, how can they be involved in the extension? How can they find it? Where can they find it?\u003C/p>\u003Cp>How can they use it?\u003C/p>\u003Cp>Speaker 0: Okay. So I have a get a report story. So any issues in there, I will actually try and solve it as quickly as possible. And apart from that, it provides guides on how to use, how to use it, what variables you can use, how to actually set it up. So GitHub is the way to go, I guess.\u003C/p>\u003Cp>And, otherwise, if you have any questions, you can also ask me in this in Discord.\u003C/p>\u003Cp>Speaker 1: In Discord. Yeah. Okay. Cool. So my final question, which is like a fun one, is, what's your favorite director's feature?\u003C/p>\u003Cp>Speaker 0: Actually, the one I started with. So the extensibility of directors really drives me to watch directors itself because it allows you to turn directors into either a normal website, a CMS, for your, web shop, or even just a project tool or an ERP. It's like the use cases of directors are very widespread from what I've seen.\u003C/p>\u003Cp>Speaker 1: Okay. So extensions are like your favorite feature?\u003C/p>\u003Cp>Speaker 0: Of course. I'm a programmer, so you could expect\u003C/p>\u003Cp>Speaker 1: that. That makes that makes a lot of sense. Actually, it makes a lot of sense. I've had people say flows. Flows are like I think flows are like mine, actually, but extensions are also really great.\u003C/p>\u003Cp>Yeah. But I see how you combine flows and extensions in this particular extension, so that makes a lot of\u003C/p>\u003Cp>Speaker 0: sense. Yeah. And also with flows, it it feels like demi mode to me because Go can obviously do a lot more.\u003C/p>\u003Cp>Speaker 1: Yeah. Yeah. You have a point. But, thank you, Bart. It's been amazing just chatting with you and just you working us through how you build the extensions, the need for it, and diving the part into your code.\u003C/p>\u003Cp>So, I'm excited to see how the community engages and just starts using the extension and even more extensions that you build in the future. I'm excited about that as well. Yeah. So, thank you everyone for joining us, and we'll see you in another episode of the Beyond the Crossroad. Till next time.\u003C/p>\u003Cp>Bye.\u003C/p>","So the extensibility of Directus really drives me to watch Directus itself because it allows you to turn Directus into either a normal website, a CMS, for your, web shop, or even just a project's tool. Hi. Hi. Hi, everyone. Welcome to another episode of the Beyond the Core Show. It's a director who will shine a spotlight on extensions that have been created by community members. As always, I'm your host, Esther Akbaje, developer advocate at directors. And today on this episode, I have with me Bart. I would like to say Bart is a super community member because he's really involved in community and has created a good number of extensions. So very excited to have this conversation, but thank you for joining me here today. Hi, Esther. Thank you for having me. So, yeah, as you already said, I'm very active within the community, both with helping out and also creating new extensions. So Okay. Yeah. It's good to have you. I'm excited for this conversation. Would you like to introduce yourself a bit more, maybe what you do, where you're based? Sure. So I'm Bart Lund. I'm 23 years old. I'm from the Netherlands, and I'm actually a software engineer for a company that doesn't use directors, but that, of course, doesn't matter. Yeah. So in my free time, I've created a company with 2 friends of mine, and we're actually using Directus as the CMS for websites, web shops, and smaller back end tooling. Apart from that, I've been here since release, gonna date 42, if I'm correct. So that's almost 3 years. Okay. And I'm very active within the community. I'm trying to help out people whenever I can. So Nice. Nice. I'm curious to know, where did you hear about Directus? Like, do you remember? So I do remember we were talking about, like, what kind of CMS are we going to use? Because, obviously, Nuxt or something like it is not the only thing that, can handle data. So then we came across Trappy, and we were like, there are some limitations. It doesn't feel just right. And then we came across directors. Back then, it was a little bit of a mess because it was a release candidate, but we really, really liked how you can extend directors and do anything with it, as you'd like. So then we decided, like, hey, we're going to do directors, man. That's Here you are. Right. Together. Yeah. Yeah. And you've actually done so many amazing or built so many amazing extensions with directors. I know today we are here to talk about the text to anything extension. So just tell me more about it. Like, what does this extension really do? Text to anything is a generic name because it's going to do a lot of things. So the main focus right now is on generating PDF Mhmm. Both from your raw HTML if you want to provide it, or you can use a template, which is also based on HTML, but you can view it inside of the visual editor. And you can, of course, use parameters inside of it. Next to that, it's also, allowing you to generate QR codes and barcodes. And in the future, there will also be, like, HTML towards an image or just an image towards text itself. So we have OCR. But those are just future plans for now. Okay. Okay. I I know that when I initially saw this extension, it was very exciting to me because I'd actually not seen a tool that could do so many things and still seem very simple. So, what really inspired this extension? Like, what what made you feel like, okay. I think this extension is something that will be useful to the community? So first of all, we, of course, have to create, invoices ourselves and PDFs for them. Okay. Because we're also, so I left the company. It's a little side story, but I left the company for, like, a half year now. But we also need to generate PDFs. We also Mhmm. Are using it like as our CMS. So we have our users, our invoices, our projects inside of, directors. So we needed to create PDFs. At first, we were using a hacky workaround. And now I actually decided to, like, create an official extension for it. And I also saw inside of the community that people were asking, like, how can we ever create a PDF if it's not in direct us already? So that's why I decided to make an extension for it. Yeah. That's definitely interesting. I can't really wait to see it in action today. So, before we jump into the code, what what would you say was one of the most difficult things or challenges that you faced when you were developing this extension? So the main thing that's very hard about PDF is that you need something that renders the PDF. So in your browser, it's really easy because you have HTML, CSS already rendered for you. But when you're talking about only back end, you don't want to spin up a browser just to create your PDF. So at first, I started actually doing that. So I tried to integrate the browser. It's called Puppeteer inside of your your directives, but it requires a lot of resources like CPU, RAM. And it doesn't feel right because you're make using a CMS. And for every CMS instance, you're also spawning a browser to generate PDFs for you. Okay. So to tackle that, I actually created a API, which basically, allows you to post any, HTML or whatever, and it will convert it into the PDF for you and give it back. Okay. Okay. Yeah. It makes a lot of sense. So would you like to share your screen and just walk us through, like, code, some code decisions that you had to make and just talk about what each code block does? So whenever you're creating an extension, you probably need multiple folders or directories, or even extensions themselves. So you can create a bundle a bundle to, bundle it altogether. And in my case, I have a lot of extensions that are required to make it all work. Okay. So we start off with the installation hook. The installation hook is actually meant to create any collections that are not non existent at the moment and also add any fields if they are not there. Next to that it also talks to my API so you can actually get the pdfs or whatever. Okay. So first we actually create the templates collection so you can so we can use something to store the templates and the data about it. Okay. Then in case there are no fields yet for that collection, we're creating the actual fields. Alright. And the reason why I'm doing it like this is if something happens or you delete a field by accident the code will run next time you restart directives and it's just correct. Mhmm. Okay. Makes sense. Yeah. And then we also need an API key because there's a paywall between the API of mine and Directus itself. The reason for this is that I actually have some costs that I sadly have to make to make this API work. So in this case, it adds a field to director settings, which you can then of course populate later on. We have the same with some other fields and then we get into the actual interesting part. Yeah. So within the global dish, which is like a global variable within your node. Yes. Runtime. I'm creating a text to anything, variable, which allows you to do any action that you can do within flows also inside of your own code. So if you have a hook or a schedule that needs to generate barcodes, PDF codes, you can just do it. And to keep it everything as minimal as possible, Directus is using Axios. So I'm also using that to call out the API itself. Okay. Apart from that, it's fairly simple to me. I'm not sure if you see anything that makes you wonder. Likewise, you can do that. No. Just the generate PDF. You have how many, functions do you have? You have the generate PDF function. What other function do you have? PDF template version. We have those 4 at the moment. Okay. And the generate PDF from template actually reuses the generate PDF function, but it just parses your template and make sure that everything goes correctly. Okay. So apart from that, we, of course, also have the flow nodes because you can also use them inside the flow. So one of the things that we have here is really short, basically for every flow node because it's using the, functions that I just showed you. Yeah. One difficulty that I actually had was to make a selection, like an input select field within the flows. So you can actually select the template that you want to use. So in the end I created an interface for it that allows you to do just that. You will probably see it within a second. Yeah. I'm not sure if you want to see any other things. I'm sure I I know you have a GitHub, repo, so everyone can just like, anyone interested in digging more on the code can just check it out. Yeah. So within directives, after you've installed the extension, you have a module. Okay. Which allows you to create any template you like. So, for example, this is a really simple one and actually does not hold any values. Okay. For example, this one. So on the left, it allows you to type any template data that you actually want to use. On the right, you can actually see, like, a preview of how it would look like inside of the PDF itself. Yeah. So this how it will look like as a PDF. Right? Yes. And right now Okay. This is just for demo purposes. So it's not very stylish, but you can just use any HTML that you want and place it inside of the source code. This, by the way, is the what you see is what you get editor from the Reactors itself. Okay. It has the same functionality built in. Interesting. Interesting. And yeah. Okay. Yeah. That makes a lot of sense. So, basically, you just put in any text, and it just gives you the PDF format straight up. What if I'm interested in maybe getting a barcode? How would that look like? So barcodes are not require, do not require any template, obviously. Yeah. So if we go into flows we actually just created this flow. So in here, you can actually use the operation for that. So if you want the barcode, you can Mhmm. Put in the type of the barcode, the contents, and you can also select type. I actually included a library that, has a lot of types. Okay. And from there, you can also adjust the width and the height. And if you want, you can also include any text. So because barcodes are more static than the actual PDF that you want to generate, I decided to not create any editor for it. Okay. Okay. Yeah. So, basically, that's it. And and I'm sure it's similar process for, QR code as well. Right? Yes. That's true. Okay. So I can actually show you what it's doing. In here, I have created a sample collection with invoices. Okay. And in here, we have an invoice number, name, date, and also a relationship with the actual items that I have on this invoice. So then we have flows, and we can actually generate the PDF for it. PDF. Okay. Yeah. So it's actually going to use the templates that we just saw inside of the editor. And once it's done, we actually have a PDF in here. Oh, nice. Yeah. So I'll show you the logs after this. Okay. But here we have the PDF template that we just had. Interesting. Love it. I can see myself using this extension. Really interesting. Nice. So in the logs, you will actually wait. Inside of the flow, you can see, like, hey. We have our trigger. We have the button, and it's going to read the invoices. So we actually have, like, the invoice data, and then we're going to use the generate from template, which allows you to give it any name. You can also use the variables in like normal flow supported. And then you can actually select a template, which you just created inside of the settings step. Yeah. And here we have our template variables. So in here, you'll see that you actually get returned an ID. So if you want to make sure that the name is correct or that it's inside of the correct folder or link it up to any older record that you have, you can just use this ID and proceed with it. Yeah. Very useful. Very useful. See a lot of things. You like, you thought out, you know, how this extension can be very useful for many people and how it can be very efficient for them. So, yeah, lots of thoughts has gone into it here. Yeah. So in terms of how the community can be, involved in this extension, like, how can they be involved in the extension? How can they find it? Where can they find it? How can they use it? Okay. So I have a get a report story. So any issues in there, I will actually try and solve it as quickly as possible. And apart from that, it provides guides on how to use, how to use it, what variables you can use, how to actually set it up. So GitHub is the way to go, I guess. And, otherwise, if you have any questions, you can also ask me in this in Discord. In Discord. Yeah. Okay. Cool. So my final question, which is like a fun one, is, what's your favorite director's feature? Actually, the one I started with. So the extensibility of directors really drives me to watch directors itself because it allows you to turn directors into either a normal website, a CMS, for your, web shop, or even just a project tool or an ERP. It's like the use cases of directors are very widespread from what I've seen. Okay. So extensions are like your favorite feature? Of course. I'm a programmer, so you could expect that. That makes that makes a lot of sense. Actually, it makes a lot of sense. I've had people say flows. Flows are like I think flows are like mine, actually, but extensions are also really great. Yeah. But I see how you combine flows and extensions in this particular extension, so that makes a lot of sense. Yeah. And also with flows, it it feels like demi mode to me because Go can obviously do a lot more. Yeah. Yeah. You have a point. But, thank you, Bart. It's been amazing just chatting with you and just you working us through how you build the extensions, the need for it, and diving the part into your code. So, I'm excited to see how the community engages and just starts using the extension and even more extensions that you build in the future. I'm excited about that as well. Yeah. So, thank you everyone for joining us, and we'll see you in another episode of the Beyond the Crossroad. Till next time. Bye.",[198,199],"0e456a49-eade-4984-8104-1e91f02ca1d0","9d517928-56f0-4eec-8963-ecfcc8928ff0",[],{"reps":202},[203,259],{"name":204,"sdr":8,"link":205,"countries":206,"states":208},"John Daniels","https://meet.directus.io/meetings/john2144/john-contact-form-meeting",[207],"United States",[209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258],"Michigan","Indiana","Ohio","West Virginia","Kentucky","Virginia","Tennessee","North Carolina","South Carolina","Georgia","Florida","Alabama","Mississippi","New York","MI","IN","OH","WV","KY","VA","TN","NC","SC","GA","FL","AL","MS","NY","Connecticut","CT","Delaware","DE","Maine","ME","Maryland","MD","Massachusetts","MA","New Hampshire","NH","New Jersey","NJ","Pennsylvania","PA","Rhode Island","RI","Vermont","VT","Washington DC","DC",{"name":260,"link":261,"countries":262},"Michelle Riber","https://meetings.hubspot.com/mriber",[263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,240,451,452],"Albania","ALB","Algeria","DZA","Andorra","AND","Angola","AGO","Austria","AUT","Belgium","BEL","Benin","BEN","Bosnia and Herzegovina","BIH","Botswana","BWA","Bulgaria","BGR","Burkina Faso","BFA","Burundi","BDI","Cameroon","CMR","Cape Verde","CPV","Central African Republic","CAF","Chad","TCD","Comoros","COM","Côte d'Ivoire","CIV","Croatia","HRV","Czech Republic","CZE","Democratic Republic of Congo","COD","Denmark","DNK","Djibouti","DJI","Egypt","EGY","Equatorial Guinea","GNQ","Eritrea","ERI","Estonia","EST","Eswatini","SWZ","Ethiopia","ETH","Finland","FIN","France","FRA","Gabon","GAB","Gambia","GMB","Ghana","GHA","Greece","GRC","Guinea","GIN","Guinea-Bissau","GNB","Hungary","HUN","Iceland","ISL","Ireland","IRL","Italy","ITA","Kenya","KEN","Latvia","LVA","Lesotho","LSO","Liberia","LBR","Libya","LBY","Liechtenstein","LIE","Lithuania","LTU","Luxembourg","LUX","Madagascar","MDG","Malawi","MWI","Mali","MLI","Malta","MLT","Mauritania","MRT","Mauritius","MUS","Moldova","MDA","Monaco","MCO","Montenegro","MNE","Morocco","MAR","Mozambique","MOZ","Namibia","NAM","Niger","NER","Nigeria","NGA","North Macedonia","MKD","Norway","NOR","Poland","POL","Portugal","PRT","Republic of Congo","COG","Romania","ROU","Rwanda","RWA","San Marino","SMR","São Tomé and Príncipe","STP","Senegal","SEN","Serbia","SRB","Seychelles","SYC","Sierra Leone","SLE","Slovakia","SVK","Slovenia","SVN","Somalia","SOM","South Africa","ZAF","South Sudan","SSD","Spain","ESP","Sudan","SDN","Sweden","SWE","Tanzania","TZA","Togo","TGO","Tunisia","TUN","Uganda","UGA","United Kingdom","GBR","Vatican City","VAT","Zambia","ZMB","Zimbabwe","ZWE","UK","Germany","Netherlands","Switzerland","CH","NL",1773850430340]