<?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: Timotej Avsec</title>
    <description>The latest articles on DEV Community by Timotej Avsec (@timotej_avsec).</description>
    <link>https://dev.to/timotej_avsec</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%2F283808%2F23e3abbd-849b-4ec7-8377-351804040e8f.png</url>
      <title>DEV Community: Timotej Avsec</title>
      <link>https://dev.to/timotej_avsec</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/timotej_avsec"/>
    <language>en</language>
    <item>
      <title>LearnQuest – Your Gamified Learning Companion 🎮📚</title>
      <dc:creator>Timotej Avsec</dc:creator>
      <pubDate>Tue, 21 Jan 2025 18:08:43 +0000</pubDate>
      <link>https://dev.to/timotej_avsec/learnquest-your-gamified-learning-companion-1203</link>
      <guid>https://dev.to/timotej_avsec/learnquest-your-gamified-learning-companion-1203</guid>
      <description>&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;LearnQuest is a dynamic and engaging learning assistant that combines advanced features of Agent.ai to redefine how users interact with educational content. The agent creates an immersive, gamified experience by seamlessly integrating logical workflows, AI capabilities, and personalized tools for effective learning.&lt;/p&gt;

&lt;p&gt;It all starts with the user choosing a topic to explore. Here, LearnQuest gets smart: it asks whether the user has their own learning material to upload or would like the agent to search the web for them. If the user uploads files—like PDFs or notes—the agent extracts and processes the content into digestible learning chunks. If the user opts for web resources, LearnQuest uses Agent.ai to perform a Google search and gathers the top 25 results. Using an LLM, the agent organizes this raw data into logically grouped sections and delivers a clean, friendly summary. 🧠✨&lt;/p&gt;

&lt;p&gt;But it doesn’t stop there! To add a fun twist, LearnQuest brings in some humor by invoking a separate &lt;a href="https://agent.ai/profile/9kuy7lwvuud9yyzl" rel="noopener noreferrer"&gt;Meme Maker agent&lt;/a&gt;, generating a custom meme related to the learning topic. Because who says studying can’t be entertaining? 😄&lt;/p&gt;

&lt;p&gt;Quizzes are where the learning gets truly interactive. The agent invites the user to specify how many questions they’d like. Using the LLM again, it creates a tailored quiz based on the topic or uploaded material. Once the user submits their answers, the agent evaluates them with AI, providing a detailed breakdown of correct and incorrect responses, study recommendations for improvement, and even a final grade. The feedback loop is quick, constructive, and motivating.&lt;/p&gt;

&lt;p&gt;Finally, LearnQuest ensures the learning journey isn’t lost. The user can export the summary, quiz results, and recommendations to Google Docs or send them directly to their email, keeping their progress accessible for future reference.&lt;/p&gt;

&lt;p&gt;LearnQuest’s power comes from its seamless use of Agent.ai’s robust features: it integrates search results, leverages LLMs for summarization, grading, and categorization, processes logical workflows like file uploads and user inputs, and effortlessly combines data extraction with content delivery. The icing on the cake is its ability to invoke and incorporate another agent (the Meme Maker), making it a creative and playful companion for learners of all ages. 🎓🔥&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://agent.ai/agent/learn-quest" rel="noopener noreferrer"&gt;https://agent.ai/agent/learn-quest&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Selecting the topic and source of information
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0l2mxt7bggkh855wblh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0l2mxt7bggkh855wblh.png" alt="Topic input" width="800" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent fetches the information from the source and groups it into logical sections
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagrvekez5msh6xivucei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagrvekez5msh6xivucei.png" alt="Section text" width="800" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Invoking another (Meme Generator) agent to generate a thematic meme to make the learning more fun
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7recle5apwcknudjtte.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7recle5apwcknudjtte.png" alt="Meme" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Input how many questions do you want to be generated in a quiz
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyk48ocsr2j63w8ztfqks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyk48ocsr2j63w8ztfqks.png" alt="Quiz" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Quiz answers and LLM's grading
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxyqwf2ek276g5ks6nq8h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxyqwf2ek276g5ks6nq8h.png" alt="Answers" width="800" height="676"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent.ai Experience
&lt;/h2&gt;

&lt;p&gt;Agent.ai provided a very powerful framework for building AI agents, which can utilize not only LLM calls, but also come with a lot of useful building blocks, in my case the most useful are uploading and parsing files and searching for Google results. If I would to develop this agent from scratch, using some other programming language, the setup itself would take me more time as it did to make a whole agent using agent.ai&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>agentaichallenge</category>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>🎬 MovieCrafter: AI Movie Script &amp; Storyboard Generator ✨</title>
      <dc:creator>Timotej Avsec</dc:creator>
      <pubDate>Wed, 09 Oct 2024 11:43:35 +0000</pubDate>
      <link>https://dev.to/timotej_avsec/moviecrafter-ai-movie-script-storyboard-generator-50ln</link>
      <guid>https://dev.to/timotej_avsec/moviecrafter-ai-movie-script-storyboard-generator-50ln</guid>
      <description>&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I created the AI Movie Script &amp;amp; Storyboard Generator, an AI-powered tool that helps users craft movie scripts and visual storyboards with ease. Users simply input a movie title, description, and genre, and the application generates a complete script using OpenAI’s GPT-4. Next, the app generates corresponding storyboard images using DALL-E 3, visually mapping out key scenes in the movie. These images are stored securely using Pinata Cloud’s Files API, making it easy for users to access their creations via signed URLs. This project demonstrates how AI and decentralized storage can come together to streamline the creative process for filmmakers and storytellers. 🎥✨&lt;/p&gt;

&lt;h2&gt;
  
  
  Technologies
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Laravel (TALL stack): Tailwind CSS, Alpine.js, Laravel, Livewire creating a responsive and interactive frontend and a powerful backend.&lt;/li&gt;
&lt;li&gt;OpenAI GPT-4: For generating movie scripts from user-provided input.&lt;/li&gt;
&lt;li&gt;DALL-E 3: For creating visually engaging storyboard images.&lt;/li&gt;
&lt;li&gt;Pinata: For securely storing and managing the storyboard images via their Files API.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Since this application relies on OpenAI tokens, a live demo has not been deployed. However, you can explore the application by pulling the code from the repository or watching the demo video below:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/T9h8e30nCHY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshots:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Landing page
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanney9ecpyx61nfkg0be.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanney9ecpyx61nfkg0be.png" alt="landing page" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  List of projects
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frb51odwpwakzjf8qml6e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frb51odwpwakzjf8qml6e.png" alt="list of projects" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Create new movie script
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64n227pxupn5bocbtqyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64n227pxupn5bocbtqyq.png" alt="new movie screen" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Generated script and story boards
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vyq0lhrheasidyikfui.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vyq0lhrheasidyikfui.png" alt="generated screenplay" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbzcnquw7zebag7i6xd1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbzcnquw7zebag7i6xd1.png" alt="generated story boards" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  My Code
&lt;/h3&gt;

&lt;p&gt;The complete code for the project can be found in the GitHub repository:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/tavsec" rel="noopener noreferrer"&gt;
        tavsec
      &lt;/a&gt; / &lt;a href="https://github.com/tavsec/movie-crafter" rel="noopener noreferrer"&gt;
        movie-crafter
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🎬 AI Movie Script &amp;amp; Storyboard Generator – An AI-powered tool that creates movie scripts with GPT-4 and visual storyboards using DALL-E 3, securely stored with Pinata Cloud. 🚀✨
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🎬 MovieCrafter | AI Movie Script &amp;amp; Storyboard Generator&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Welcome to the AI Movie Script &amp;amp; Storyboard Generator – an innovative application built to streamline the process of creating movie scripts and visual storyboards using AI technology. This project was created as part of the DEV.to x Pinata Hackathon to showcase the powerful integration of Pinata for secure and efficient digital asset storage. 🚀&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tavsec/movie-crafter.github/assets/banner.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftavsec%2Fmovie-crafter.github%2Fassets%2Fbanner.png" alt="banner"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📖 Project Overview&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Ever had a great idea for a movie but didn't know where to start? With this tool, you can input a movie title, short description, and genre, and let our AI models handle the rest! Using OpenAI GPT-4 and DALL-E 3, the app generates a fully-fledged movie script and accompanying storyboard images that bring your ideas to life. The storyboards are stored on Pinata Cloud using their Files API, ensuring they're accessible and securely stored.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🛠️ Technologies Used&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This project is built using…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tavsec/movie-crafter" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  More Details
&lt;/h2&gt;

&lt;p&gt;For this project, Pinata plays a crucial role in securely storing and serving the AI-generated storyboard images. After the images are generated using DALL-E 3, they are uploaded to Pinata Cloud via their Files API. Each image is stored as an asset on Pinata, and I use signed URLs to make the images accessible to users without exposing them publicly. This ensures that the images remain secure and can be accessed by users anytime, without compromising privacy or security. Pinata’s efficient file storage API made this integration smooth and hassle-free, enabling me to focus on building the core features of the app.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>pinatachallenge</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>Nylas Assistant</title>
      <dc:creator>Timotej Avsec</dc:creator>
      <pubDate>Mon, 26 Aug 2024 19:12:53 +0000</pubDate>
      <link>https://dev.to/timotej_avsec/nylas-assistant-3pf5</link>
      <guid>https://dev.to/timotej_avsec/nylas-assistant-3pf5</guid>
      <description>&lt;h2&gt;
  
  
  What I Built and Why
&lt;/h2&gt;

&lt;p&gt;I built Nylas Assistant, an AI-powered email assistant that integrates the Nylas API with OpenAI and the Qdrant vector database. This project implements Retrieval-Augmented Generation (RAG) mechanisms, allowing users to interact with an AI agent that can search and retrieve information from their inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The core of Nylas Assistant involves seamless integration of email data, AI-driven insights, and real-time user interaction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Email Syncing&lt;/strong&gt;: Upon user login, a Laravel background worker  kicks off, syncing emails from the user’s inbox via the Nylas API. This is handled by the SyncEmailsToQdrant job, which processes each email to extract relevant content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Embeddings Generation&lt;/strong&gt;: The email content is then transformed into embeddings using the OpenAI API. These embeddings are vector representations of the email content, capturing semantic meaning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vector Storage with Qdrant&lt;/strong&gt;: The generated embeddings are stored in a Qdrant vector database. Qdrant is a high-performance, vector search engine that allows for efficient similarity searches. In this context, it’s used to store and index the embeddings, enabling quick retrieval based on context during chat interactions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI-Powered Chat&lt;/strong&gt;: When a user interacts with the chat UI, the OpenAI model retrieves the most relevant email embeddings from Qdrant, ensuring that the AI’s responses are contextually aware and tailored to the user’s specific email history.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have also written a comprehensive README file on the Github repository, which also includes steps to build and configure this application, so you can try it yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/xdt91I3DE_0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/tavsec" rel="noopener noreferrer"&gt;
        tavsec
      &lt;/a&gt; / &lt;a href="https://github.com/tavsec/nylas-assistant" rel="noopener noreferrer"&gt;
        nylas-assistant
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      OpenAI and Qdrant powered AI assistant, which connects to your email inbox using Nylas API and can be used as an assistant
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Nylas Assistant 🚀&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Nylas Assistant&lt;/strong&gt; is an AI-powered email assistant built with Laravel, &lt;a href="https://www.nylas.com/" rel="nofollow noopener noreferrer"&gt;Nylas&lt;/a&gt;, &lt;a href="https://openai.com/" rel="nofollow noopener noreferrer"&gt;OpenAI&lt;/a&gt;, and &lt;a href="https://qdrant.tech/" rel="nofollow noopener noreferrer"&gt;Qdrant&lt;/a&gt;. Sync your inbox, parse emails, and store them as OpenAI embeddings in a Qdrant vector database. Interact with an OpenAI agent through a chat-like interface that provides context-aware responses based on your emails. ✉️💡&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tavsec/nylas-assistantmedia/img.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a7zK86WM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tavsec/nylas-assistantmedia/img.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;🎯 Features&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Email Syncing&lt;/strong&gt;: Automatically syncs your inbox using the Nylas API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email Parsing&lt;/strong&gt;: Parses and stores emails as embeddings with OpenAI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Chat Interface&lt;/strong&gt;: Chat with an OpenAI agent that understands your email context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector Storage&lt;/strong&gt;: Efficient embedding storage and retrieval using Qdrant.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;🛠️ Tech Stack&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Laravel&lt;/strong&gt;: Backend framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nylas API&lt;/strong&gt;: For email syncing and management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI&lt;/strong&gt;: For generating embeddings and chat responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qdrant&lt;/strong&gt;: Vector database for storing and querying embeddings.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;🚀 Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Clone the repository.&lt;/li&gt;
&lt;li&gt;Install dependencies.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;composer install&lt;/pre&gt;

&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Set up environment variables. Add the following…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tavsec/nylas-assistant" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Your Journey
&lt;/h2&gt;

&lt;p&gt;For this hackathon, I aimed to create an application that demonstrates the combined power of the Nylas API and the OpenAI language model. My goal was to build a chatbot assistant that provides deeper insights into a user's inbox.&lt;/p&gt;

&lt;p&gt;I chose to develop the application using Laravel, even though PHP is not the typical choice for AI projects. I wanted to push the boundaries and see if I could build a robust AI application with it. I’m pleased with how it turned out!&lt;/p&gt;

&lt;p&gt;The most challenging part was converting emails to vector embeddings, especially considering the large number of emails a user might have. I addressed this by dispatching asynchronous background jobs that can be batched into smaller tasks. This approach allows users to start chatting with the assistant even if email syncing is still in progress.&lt;/p&gt;

&lt;p&gt;In the end, I created a simple chat UI that displays the chat history between the user and the assistant.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>nylaschallenge</category>
      <category>api</category>
      <category>ai</category>
    </item>
    <item>
      <title>Neon Scaffolder</title>
      <dc:creator>Timotej Avsec</dc:creator>
      <pubDate>Fri, 23 Aug 2024 11:59:54 +0000</pubDate>
      <link>https://dev.to/timotej_avsec/neon-scaffolder-42c8</link>
      <guid>https://dev.to/timotej_avsec/neon-scaffolder-42c8</guid>
      <description>&lt;h2&gt;
  
  
  My Kit
&lt;/h2&gt;

&lt;p&gt;For this challenge, I created the Neon Scaffolder, a Node.js CLI tool that goes beyond a single starter kit. Instead of focusing on one specific starting template, I wanted to build a dynamic system that can accommodate multiple starter kits, giving developers the flexibility to choose the setup that best fits their needs. With Neon Scaffolder, you can easily create and set up new projects that are instantly connected to a Neon database, using a variety of predefined templates like Laravel, Astro, and more.&lt;/p&gt;

&lt;p&gt;This tool is designed to save developers time by handling the boilerplate setup and configuration, allowing you to focus on what really matters—building your application. The templates are stored in a centralized GitHub organization, making it easy to manage, update, and add new templates as the ecosystem evolves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it out!
&lt;/h2&gt;

&lt;p&gt;If you want to try it out, all you need is NodeJS installed (version &amp;gt;= 18.0), and run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; neon-scaffolder
&lt;span class="nv"&gt;$ &lt;/span&gt;neon-scaffolder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will install the scaffolder, and run the set up project.&lt;/p&gt;
&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

&lt;p&gt;To demonstrate the dynamic capabilities of this application, I created two scaffolding templates, one for &lt;a href="https://laravel.com/" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt; and one for &lt;a href="https://astro.build/" rel="noopener noreferrer"&gt;Astro&lt;/a&gt;. &lt;/p&gt;
&lt;h4&gt;
  
  
  Laravel
&lt;/h4&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/dBojjzeFMEI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
&lt;h4&gt;
  
  
  Astro
&lt;/h4&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4_R6Wfh8fOg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;Here’s a quick overview of how Neon Scaffolder works:&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Creating a Neon Project
&lt;/h4&gt;

&lt;p&gt;When you run the CLI tool, it first interacts with the Neon API to create a new Neon project. This step sets up the necessary infrastructure in the Neon database, so you don’t have to worry about manual setup.&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Downloading the Template
&lt;/h4&gt;

&lt;p&gt;After creating the Neon project, the CLI will prompt you to select a template from the available options. Templates are stored in a centralized GitHub organization, which makes it easy to manage and update them.&lt;br&gt;
Once you choose a template, the CLI downloads the corresponding scaffold from the GitHub repository to your local machine.&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Templating the Project
&lt;/h4&gt;

&lt;p&gt;With the scaffold downloaded, Neon Scaffolder uses Mustache templating to configure the project. This step replaces placeholders in the template with the necessary configuration details, such as database connection strings and other project-specific settings.&lt;br&gt;
The result is a fully-configured project, ready to start development right away.&lt;/p&gt;
&lt;h2&gt;
  
  
  Link to Kit
&lt;/h2&gt;

&lt;p&gt;You can find the Neon Scaffolder on GitHub: &lt;a href="https://github.com/tavsec/neon-scaffolder" rel="noopener noreferrer"&gt;Neon Scaffolder Repository&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/tavsec" rel="noopener noreferrer"&gt;
        tavsec
      &lt;/a&gt; / &lt;a href="https://github.com/tavsec/neon-scaffolder" rel="noopener noreferrer"&gt;
        neon-scaffolder
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      CLI for scaffolding Neon projects for different frameworks
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🚀 Neon Scaffolder&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Neon Scaffolder&lt;/strong&gt; is a Node.js CLI tool designed to streamline the process of creating and setting up a new project connected to a &lt;a href="https://www.neon.tech" rel="nofollow noopener noreferrer"&gt;Neon database&lt;/a&gt;. With Neon Scaffolder, you can select from a variety of predefined templates (e.g., Laravel, Astro) and generate a fully-configured project ready for development out of the box.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/7b232775b558e6df10af584018b65fa7d35aa7480bfa4714a9fb3c0e19bf8f72/68747470733a2f2f692e6962622e636f2f6671327a4c30392f6f75742e676966"&gt;&lt;img src="https://camo.githubusercontent.com/7b232775b558e6df10af584018b65fa7d35aa7480bfa4714a9fb3c0e19bf8f72/68747470733a2f2f692e6962622e636f2f6671327a4c30392f6f75742e676966" alt="Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ Features&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🎯 Create Neon Projects&lt;/strong&gt;: Automatically create a new Neon project using the Neon API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📦 Predefined Templates&lt;/strong&gt;: Choose from multiple project templates such as Laravel, Astro, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔧 Dynamic Configuration&lt;/strong&gt;: The CLI uses Mustache templating to inject necessary configuration into the scaffolded project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🌐 GitHub Integration&lt;/strong&gt;: Templates are stored in the &lt;a href="https://github.com/orgs/neon-scaffolder/repositories" rel="noopener noreferrer"&gt;Neon Scaffolder GitHub organization&lt;/a&gt;, making it easy to add new templates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚡️ Out-of-the-box Setup&lt;/strong&gt;: Generated projects come pre-configured and connected to the Neon database, allowing you to start coding right away.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📥 Installation&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;To…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tavsec/neon-scaffolder" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;The repository includes a comprehensive README with detailed instructions on how to get started, including installation, usage, and how to contribute by adding new templates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Journey
&lt;/h2&gt;

&lt;p&gt;When I started this project, I didn’t want to limit myself to creating just one starter kit. Instead, I envisioned a system that could grow and adapt, offering multiple starter kits to suit a wide range of projects and developer preferences. The idea was to build something dynamic—where adding a new template is as simple as updating the centralized repository, without the need for heavy lifting on the user’s part.&lt;/p&gt;

&lt;p&gt;I learned a lot about creating flexible, user-friendly CLI applications (using NodeJS Commander library), as well as the power of templating engines like Mustache for dynamic configuration.&lt;/p&gt;

&lt;p&gt;Creating Neon Scaffolder has been a rewarding journey. I'm excited to see how others in the community will use this tool, and I’m hopeful that it will evolve with new templates and features, making it even more valuable to developers who want to hit the ground running with their projects with Neon.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>neonchallenge</category>
      <category>postgres</category>
      <category>database</category>
    </item>
    <item>
      <title>How I developed GitHub Actions file Generator application</title>
      <dc:creator>Timotej Avsec</dc:creator>
      <pubDate>Sat, 20 May 2023 17:05:48 +0000</pubDate>
      <link>https://dev.to/timotej_avsec/github-actions-file-generator-2nf</link>
      <guid>https://dev.to/timotej_avsec/github-actions-file-generator-2nf</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;I built a simple website, which will help developers generate GitHub actions file by filling up the single form.&lt;/p&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;p&gt;I think that my app belongs in two categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maintainer Must-Have&lt;/strong&gt;: this application helps maintainers to generate GitHub actions CICD file for their application, making their life easier&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DIY Deployments&lt;/strong&gt;: As this application also provides instructions and different deployment options (AWS S3, GitHub pages, Heroku, Netlify), this application can help developers set up their deployment environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://tavsec.github.io/github-actions-generator/"&gt;https://tavsec.github.io/github-actions-generator/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A25GYFw0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oka1lovbu6flwudi2lan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A25GYFw0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oka1lovbu6flwudi2lan.png" alt="Form for developer to fill" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vVSt0q7Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpbuelxxyu7yt4gs0dlh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vVSt0q7Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpbuelxxyu7yt4gs0dlh.png" alt="Generated instructions and CICD file" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;My main goal was to develop a simple application, where developer can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;choose Javascript framework (Angular, React, Vue),&lt;/li&gt;
&lt;li&gt;choose build processor (NPM or Yarn),&lt;/li&gt;
&lt;li&gt;optionally choose test suite and&lt;/li&gt;
&lt;li&gt;select their desired deployment method (AWS S3, GitHub pages, Heroku or Netlify)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on that information, the system will generate the GitHub actions file, which the developers can include in their repository. The system will also generate a list of instructions, which helps developer to set up their actions, along with instructions from external platforms, if needed.&lt;/p&gt;

&lt;p&gt;I was aiming to make the process as simple as possible for developer, but also customizable to some extend. For example, developer can override default build command under "additional settings" field, or change the test command. The developer can also change the default branch, on which the actions are triggered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/tavsec"&gt;
        tavsec
      &lt;/a&gt; / &lt;a href="https://github.com/tavsec/github-actions-generator"&gt;
        github-actions-generator
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Web application which can generate GitHub Actions file for selected options.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
github-actions-generator&lt;/h1&gt;
&lt;p&gt;This application was developed as a part of &lt;a href="https://dev.to/devteam/announcing-the-github-dev-2023-hackathon-4ocn" rel="nofollow"&gt;GitHub + Dev hackathon&lt;/a&gt;. The main purpose of this app is to help developers create GitHub Actions files from a simple form, and also provide them with the instructions on how to set up their CICD process.&lt;/p&gt;
&lt;p&gt;My entry: &lt;a href="https://dev.to/timotej_avsec/github-actions-file-generator-2nf" rel="nofollow"&gt;https://dev.to/timotej_avsec/github-actions-file-generator-2nf&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Setup&lt;/h2&gt;
&lt;p&gt;To run this application you need to have NPM and NodeJs installed. Once you have it, simply run &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm run dev&lt;/code&gt;. This will set up your local server.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tavsec/github-actions-generator"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;p&gt;MIT&lt;/p&gt;

&lt;h2&gt;
  
  
  Background (What made you decide to build this particular app?
&lt;/h2&gt;

&lt;p&gt;When I first started working with GitHub actions, I was overwhelmed with all of the possibilities that GitHub actions provide. I also discovered, that the simple process of building, testing and deploying the front end application is not a hard thing to do using GitHub actions, and can be easily configured. That's why I decided to develop this simple app, which helps frontend developers achieve this goal.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it (How did you utilize GitHub Actions or GitHub Codespaces? Did you learn something new along the way? Pick up a new skill?)
&lt;/h3&gt;

&lt;p&gt;I developed this application using NuxtJS framework. Most of the work was done on GitHub Codespaces, which worked out of the box for my project (NodeJS was set up, I only had to run two Node commands, and the development environment was set up!).&lt;/p&gt;

&lt;p&gt;The site is hosted on GitHub pages, and a simple Actions Job is set up, which deploys new version of the app every time new change is pushed to the &lt;code&gt;main&lt;/code&gt; branch. &lt;/p&gt;

&lt;p&gt;If you want to try the app, feel free to fork my repository above! I will probably be adding some new framework - my next goal would be to enable Docker option for building, and some other, container-oriented platform for deployments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

</description>
      <category>githubhack23</category>
      <category>webdev</category>
      <category>github</category>
    </item>
    <item>
      <title>Video content search using MongoDB Atlas Search and Google Machine Learning</title>
      <dc:creator>Timotej Avsec</dc:creator>
      <pubDate>Fri, 25 Nov 2022 12:15:46 +0000</pubDate>
      <link>https://dev.to/timotej_avsec/video-content-search-using-mongodb-atlas-search-and-google-machine-learning-1f32</link>
      <guid>https://dev.to/timotej_avsec/video-content-search-using-mongodb-atlas-search-and-google-machine-learning-1f32</guid>
      <description>&lt;h1&gt;
  
  
  What I built
&lt;/h1&gt;

&lt;p&gt;I’ve built an application in Golang, which is able to find video content from all of the videos that have been uploaded to the application. It utilises the Google Cloud Video Intelligence API to detect the features (content) inside the video.&lt;/p&gt;

&lt;h1&gt;
  
  
  Category Submission:
&lt;/h1&gt;

&lt;p&gt;I decided to submit my application into multiple categories. Below is a list of all of the categories that I would like to submit my application in, as well as description as why I think the app can be submited into listed category.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search No More:&lt;/strong&gt; 
Main feature of the application is to perform a quick search on ALL of the uploaded videos. That’s why I used Atlas Search, as it provides quick setup and is querying super fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Think Outside the JS Box:&lt;/strong&gt;
As an backend developer, it was my goal for quite some time now to learn Golang, but I was procrastinating with learning Go, that’s why decided that the best way to learn new programming language is to build something with it. That’s why I picked Golang as my API language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Cloud Superstar:&lt;/strong&gt;
The “brains” behind the Video Feature detection Google Cloud Video Intelligence API, which provides Golang SDK and enables the developer to utilise powerful Google Cloud ML engine to detect the video features.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  App Link
&lt;/h1&gt;

&lt;p&gt;Because I use Google Cloud Video Intelligence API, which is not free, I did not want to post my application publicly and create some “unwanted” costs on my Google Cloud bill 😃. However, I recorded a short demo video, as well as screenshoted the application. After all, if you would like to try my app, you can always clone Git repo, add your Google Cloud credentials, and run the API.&lt;/p&gt;

&lt;h1&gt;
  
  
  Video
&lt;/h1&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/tr0CMyarsYA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Screenshots
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dxxktsb98r3n3jbsv85.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dxxktsb98r3n3jbsv85.png" alt="search page" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmgxev9e46jte08y1e1e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmgxev9e46jte08y1e1e.png" alt="video upload modal" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Background
&lt;/h1&gt;

&lt;p&gt;My main motivation to build this application was to learn a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;learn how to implement MongoDB into application using SDKs and libraries, and also connect Atlas Search&lt;/li&gt;
&lt;li&gt;learn how Google Cloud Video Intelligence works&lt;/li&gt;
&lt;li&gt;learn new programming language (Golang)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  How I built it
&lt;/h1&gt;

&lt;p&gt;I started my project with developing API server in Golang. For the HTTP library I used &lt;a href="https://github.com/gin-gonic/gin" rel="noopener noreferrer"&gt;Gin&lt;/a&gt; framework, as it provides an friendly interface to build REST ready API.&lt;/p&gt;

&lt;p&gt;For my application, two endpoints were enough. One was used for video upload, and one for video search. This is how endpoints are defined in Gin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/videos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Controllers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VideoStore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/videos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Controllers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VideoSearch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Server running on :8080"&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;h2&gt;
  
  
  Video upload and feature detection
&lt;/h2&gt;

&lt;p&gt;Video store method consists of the folowing steps:&lt;/p&gt;
&lt;h3&gt;
  
  
  File upload and transfer to Google Storage Buckets
&lt;/h3&gt;

&lt;p&gt;User can upload the video to our API. Our API then uploads it to the Google Storage Bucket. This is the code that accomplishes that:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="c"&gt;// Client init, ...&lt;/span&gt;
&lt;span class="c"&gt;// ...&lt;/span&gt;

&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uploadedFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"video"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uploadedFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;".mp4"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusUnprocessableEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Uploaded file must be mp4 video"&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="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Upload file to Storage Bucket&lt;/span&gt;
    &lt;span class="n"&gt;sw&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StorageBucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileUuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Uploaded file is added as an record to the MongoDB database, so we can reference it later. We save video file name, size and unique UUID, which we can reference when retrieving the private object.
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ...&lt;/span&gt;

&lt;span class="n"&gt;coll&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MongoClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MONGO_DB_DATABASE"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"videos"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"filename"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uploadedFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filename&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uploadedFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fileUuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()}}&lt;/span&gt;
    &lt;span class="n"&gt;mongoRecord&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;coll&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InsertOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TODO&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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;3.File can be sent to Google Video Intelligence API, and retrieve the video features.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnnotateVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;videopb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnnotateVideoRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;InputUri&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"gs://"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GOOGLE_CLOUD_STORAGE_BUCKET"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fileUuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;Features&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;videopb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Feature&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;videopb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Feature_LABEL_DETECTION&lt;/span&gt;&lt;span class="p"&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;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to start annotation job: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to annotate: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetAnnotationResults&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Retrieved features are saved to the corresponding video entity in MongoDB database, where Atlas search can index them.
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mongoRecord&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InsertedID&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"$set"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"features"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;featuresList&lt;/span&gt;&lt;span class="p"&gt;}}}}&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;coll&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UpdateOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TODO&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After that, the video upload process is complete. If you would like to see the whole method, and not only the code snippets, you can access it on the GitHub: &lt;a href="https://github.com/tavsec/devto-mongodb-hackathon-api/blob/main/Controllers/VideoController.go" rel="noopener noreferrer"&gt;https://github.com/tavsec/devto-mongodb-hackathon-api/blob/main/Controllers/VideoController.go&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujeipgsc8pfiuchxj58q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujeipgsc8pfiuchxj58q.png" alt="Logic flow" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Video search
&lt;/h2&gt;

&lt;p&gt;If user wants to search all of the keywords, there is a VideoSearch method for that. The steps to utilise the Atlas Search engine is the following:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;SearchBody&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Keyword&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`form:"keyword"`&lt;/span&gt;
    &lt;span class="n"&gt;Page&lt;/span&gt;    &lt;span class="kt"&gt;int64&lt;/span&gt;  &lt;span class="s"&gt;`form:"page"`&lt;/span&gt;
    &lt;span class="n"&gt;PerPage&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;  &lt;span class="s"&gt;`form:"perPage"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;PaginatedResult&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Videos&lt;/span&gt;     &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Video&lt;/span&gt;
    &lt;span class="n"&gt;Pagination&lt;/span&gt; &lt;span class="n"&gt;pag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaginationData&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;VideoSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;searchBody&lt;/span&gt; &lt;span class="n"&gt;SearchBody&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BindQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;searchBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AbortWithError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MongoClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MONGO_DB_DATABASE"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"videos"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;searchStage&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"$search"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MONGO_DB_SEARCH_INDEX"&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"wildcard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;}}},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;searchBody&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Keyword&lt;/span&gt;&lt;span class="p"&gt;}}}}}&lt;/span&gt;

    &lt;span class="n"&gt;aggPaginatedData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;pag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TODO&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;searchBody&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PerPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;searchBody&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Aggregate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;searchStage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;storageClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SignedURLOptions&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Scheme&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SigningSchemeV4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Expires&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Minute&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Video&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;aggPaginatedData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Video&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;marshallErr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;marshallErr&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SignedURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;storageClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GOOGLE_CLOUD_STORAGE_BUCKET"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SignedURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PaginatedResult&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Videos&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Pagination&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;aggPaginatedData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pagination&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;As you can see, Atlas Search provides simple interface to search. All we need is the following line:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="n"&gt;searchStage&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"$search"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MONGO_DB_SEARCH_INDEX"&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"wildcard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;}}},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;searchBody&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Keyword&lt;/span&gt;&lt;span class="p"&gt;}}}}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I left the Atlas Search parameters as default, as I discovered that they work great for my usecase. They search across all of the saved video features:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frym12ybzqp817f9u0o51.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frym12ybzqp817f9u0o51.png" alt="search settings" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, the video upload process is complete. If you would like to see the whole method, and not only the code snippets, you can access it on the GitHub: &lt;a href="https://github.com/tavsec/devto-mongodb-hackathon-api/blob/main/Controllers/VideoController.go" rel="noopener noreferrer"&gt;https://github.com/tavsec/devto-mongodb-hackathon-api/blob/main/Controllers/VideoController.go&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj62pe3xdycxcd3x8488l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj62pe3xdycxcd3x8488l.png" alt="logic flow" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Link to Source Code
&lt;/h1&gt;
&lt;h2&gt;
  
  
  API
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/tavsec" rel="noopener noreferrer"&gt;
        tavsec
      &lt;/a&gt; / &lt;a href="https://github.com/tavsec/devto-mongodb-hackathon-api" rel="noopener noreferrer"&gt;
        devto-mongodb-hackathon-api
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      API server for Dev.to MongoDB hackathon, using Google Cloud services and Atlas search
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;devto-mongodb-hackathon-api&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;API for my DevTo MongoDB hackathon project.
&lt;a href="https://dev.to/timotej_avsec/video-content-search-using-mongodb-atlas-search-and-google-machine-learning-1f32" rel="nofollow"&gt;https://dev.to/timotej_avsec/video-content-search-using-mongodb-atlas-search-and-google-machine-learning-1f32&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Build&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Firstly, add you &lt;code&gt;application_default_credentials.json&lt;/code&gt; to the source of the project. This will enable Google Cloud API.&lt;/p&gt;
&lt;p&gt;Then, edit .env file&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;mv .env.example .env&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Edit contents of the .env file.&lt;/p&gt;
&lt;p&gt;Finally, you can run the application as you would any other Golang application:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;go build -o devto-mongodb-hackathon github.com/tavsec/devto-mongodb-hackathon-api&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;You can also use Docker:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;docker-compose up -d&lt;/pre&gt;

&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tavsec/devto-mongodb-hackathon-api" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Frontend
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/tavsec" rel="noopener noreferrer"&gt;
        tavsec
      &lt;/a&gt; / &lt;a href="https://github.com/tavsec/devto-mongodb-hackathon-app" rel="noopener noreferrer"&gt;
        devto-mongodb-hackathon-app
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Frontend application for DevTo Mongodb hackathon
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;devto-mongodb-hackathon-app&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Frontend application for my DevTo MongoDB hackathon project.
&lt;a href="https://dev.to/timotej_avsec/video-content-search-using-mongodb-atlas-search-and-google-machine-learning-1f32" rel="nofollow"&gt;https://dev.to/timotej_avsec/video-content-search-using-mongodb-atlas-search-and-google-machine-learning-1f32&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Build Setup&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; create and update .env file&lt;/span&gt;
$ cp .env.example .env

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; install dependencies&lt;/span&gt;
$ npm install

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; serve with hot reload at localhost:3000&lt;/span&gt;
$ npm run dev

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; build for production and launch server&lt;/span&gt;
$ npm run build
$ npm run start

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; generate static project&lt;/span&gt;
$ npm run generate&lt;/pre&gt;

&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tavsec/devto-mongodb-hackathon-app" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h1&gt;
  
  
  Permissive License
&lt;/h1&gt;

&lt;p&gt;Both repositories are licensed as MIT.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final thoughts
&lt;/h1&gt;

&lt;p&gt;I really enjoyed building this application, as I discovered and learned a lot about MongoDB, as well as Google Cloud APIs. I was also fascinated about ease of use of Atlas Search, as it basically worked out-of-the-box (well, for my use-case, anyways). I will deffinietly use MongoDB for some of my personal projects in the future.&lt;/p&gt;

</description>
      <category>emptystring</category>
    </item>
    <item>
      <title>How I created website mockup generator app?</title>
      <dc:creator>Timotej Avsec</dc:creator>
      <pubDate>Sun, 17 Apr 2022 12:26:35 +0000</pubDate>
      <link>https://dev.to/timotej_avsec/how-i-created-website-mockup-generator-app-4o28</link>
      <guid>https://dev.to/timotej_avsec/how-i-created-website-mockup-generator-app-4o28</guid>
      <description>&lt;p&gt;In this article, I will present to you the idea, execution and problems that I encountered during the development of my new app, called &lt;a href="https://marketron.app/"&gt;Marketron&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;Did you ever want to create a simple mockup of your website, to see how it would look like on other devices? And I don't mean opening up Chrome Inspector and enabling responsive views, but having the actual image of a device (be it iPhone, desktop computer, or any other device) with your website on it? It is possible of course, but it is time consuming, even for only one device. First, you have to create a screenshot of your website with the right resolution, so it will match the display size on your device. Then, you would have to find an image with your wanted device on it. After finding it, you would have to open an image editing software (Photoshop, for example), and spend some time resizing the screenshot and combining both images together, to make the mockup look good.&lt;/p&gt;

&lt;p&gt;But my idea was to simplify the whole process. I would like to just enter the URL of my website and select the image of device that I would like my website image to be on, and then let the application do the work. And that's how I came up with the idea for &lt;a href="https://marketron.app/"&gt;Marketron&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cfzkOkpG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4aqvrtas9t00mukw4z32.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cfzkOkpG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4aqvrtas9t00mukw4z32.png" alt="Screenshot of Marketron web application" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Execution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mockup generator
&lt;/h3&gt;

&lt;p&gt;First part of the web application that I had to do was to create a simple CLI tool, which would:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a screenshot of a website&lt;/li&gt;
&lt;li&gt;Transform that image, using perspective transform, to fit the selected template&lt;/li&gt;
&lt;li&gt;Merge transformed screenshot with template image&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I decided to go with Python to create the CLI app, since it offers some amazing libraries for image manipulation (Pillow and OpenCV), as well as library for getting the screenshots of a website (Selenium). &lt;/p&gt;

&lt;p&gt;The Python app was built on top of a &lt;a href="https://click.palletsprojects.com/en/8.1.x/"&gt;Click&lt;/a&gt; library, which made the development of a CLI app much easier. I predefined some template images with perspective transform parameters and created the app, which accepts website URL and a preset as an input arguments. The Python app will then get the screenshot of a website, perform a perspective transform on it, and save the generated image.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web API
&lt;/h3&gt;

&lt;p&gt;The API was the easiest part of the project. For the API project, I went with &lt;a href="https://laravel.com/"&gt;Laravel&lt;/a&gt;, as I'm quite familiar with it, and it offers everything I needed out of the box. I created the authentication controllers and Image service, which was just an proxy from the user to the Python app. I saved the generated images as a private objects on AWS S3 Buckets. When authorized user wanted to access the image, presigned URL was generated for the user only. This enabled images to be private for authorized users only, and were not accessible for unathorized users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend application
&lt;/h3&gt;

&lt;p&gt;When API and Python app were created, I quickly create a simple design for the website. Website only has 3 main screens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Landing page&lt;/li&gt;
&lt;li&gt;Generator page: page where the user can choose the desired configuration for mockup&lt;/li&gt;
&lt;li&gt;My mocks: page for signed in users, with the history of their mocks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole frontend application was created with &lt;a href="https://nuxtjs.org/"&gt;NuxtJS&lt;/a&gt; and &lt;a href="https://bootstrap-vue.org/"&gt;Bootstrap&lt;/a&gt; framework.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zojBKGFp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/otn2smjgp10ubafcnp14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zojBKGFp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/otn2smjgp10ubafcnp14.png" alt="Generator page of Marketron" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;As application is still in early stages, there are some things that would need improvements. Mainly: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed: I would like to improve the performance of Python application, to improve the speed of mockup generation&lt;/li&gt;
&lt;li&gt;More templates: enable user more choice when creating a mockup&lt;/li&gt;
&lt;li&gt;Configurable: give users more options when creating a mockup&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Thank you!
&lt;/h2&gt;

&lt;p&gt;Thank you for your time reading this article. I would like to hear your ideas and critiques of Marketron application, as it is nowhere near finished yet 😊. The application is available on &lt;a href="https://www.marketron.app"&gt;https://www.marketron.app&lt;/a&gt; .&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>design</category>
      <category>python</category>
    </item>
    <item>
      <title>How I created URL shortener using Serverless and MongoDB</title>
      <dc:creator>Timotej Avsec</dc:creator>
      <pubDate>Fri, 07 Jan 2022 15:16:21 +0000</pubDate>
      <link>https://dev.to/timotej_avsec/how-i-created-url-shortener-using-serverless-and-mongodb-2oe0</link>
      <guid>https://dev.to/timotej_avsec/how-i-created-url-shortener-using-serverless-and-mongodb-2oe0</guid>
      <description>&lt;h3&gt;
  
  
  Overview of My Submission
&lt;/h3&gt;

&lt;p&gt;For my hackathon project I decided to create a URL shortener, using two serverless technologies: Serverless Framework and MongoDB Atlas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Choose Your Own Adventure&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Code
&lt;/h3&gt;

&lt;p&gt;My application is separated into two different repositories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend for handling entry creation and redirects&lt;/li&gt;
&lt;li&gt;Frontend for displaying form and utilising API&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Backend
&lt;/h4&gt;

&lt;p&gt;Backend is created with Serverless Framework and is using NodeJS as a runtime. It is hosted on AWS Lambda.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/timotej-avsec" rel="noopener noreferrer"&gt;
        timotej-avsec
      &lt;/a&gt; / &lt;a href="https://github.com/timotej-avsec/mubo-backend" rel="noopener noreferrer"&gt;
        mubo-backend
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Serverless backend for Mubo URL shortener
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Serverless Framework Node REST API on AWS&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This template demonstrates how to make a simple REST API with Node.js running on AWS Lambda and API Gateway using the traditional Serverless Framework.&lt;/p&gt;
&lt;p&gt;This template does not include any kind of persistence (database). For a more advanced examples check out the &lt;a href="https://github.com/serverless/examples/" rel="noopener noreferrer"&gt;examples repo&lt;/a&gt; which includes Typescript, Mongo, DynamoDB and other examples.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Deployment&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;This example is made to work with the Serverless Framework dashboard which includes advanced features like CI/CD, monitoring, metrics, etc.&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ serverless login
$ serverless deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To deploy without the dashboard you will need to remove &lt;code&gt;org&lt;/code&gt; and &lt;code&gt;app&lt;/code&gt; fields from the &lt;code&gt;serverless.yml&lt;/code&gt;, and you won’t have to run &lt;code&gt;sls login&lt;/code&gt; before deploying.&lt;/p&gt;
&lt;p&gt;After running deploy, you should see output similar to:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;Serverless: Packaging service
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/timotej-avsec/mubo-backend" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h4&gt;
  
  
  Frontend
&lt;/h4&gt;

&lt;p&gt;Frontend is created with NuxtJS framework and is hosted on GitHub pages.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/timotej-avsec" rel="noopener noreferrer"&gt;
        timotej-avsec
      &lt;/a&gt; / &lt;a href="https://github.com/timotej-avsec/mubo-frontend" rel="noopener noreferrer"&gt;
        mubo-frontend
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      URL shortener with statistic tracking
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;mubo-frontend&lt;/h1&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Build Setup&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; install dependencies&lt;/span&gt;
$ npm install

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; serve with hot reload at localhost:3000&lt;/span&gt;
$ npm run dev

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; build for production and launch server&lt;/span&gt;
$ npm run build
$ npm run start

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; generate static project&lt;/span&gt;
$ npm run generate&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;For detailed explanation on how things work, check out the &lt;a href="https://nuxtjs.org" rel="nofollow noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Special Directories&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;You can create the following extra directories, some of which have special behaviors. Only &lt;code&gt;pages&lt;/code&gt; is required; you can delete them if you don't want to use their functionality.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;code&gt;assets&lt;/code&gt;&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The assets directory contains your uncompiled assets such as Stylus or Sass files, images, or fonts.&lt;/p&gt;
&lt;p&gt;More information about the usage of this directory in &lt;a href="https://nuxtjs.org/docs/2.x/directory-structure/assets" rel="nofollow noopener noreferrer"&gt;the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;code&gt;components&lt;/code&gt;&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The components directory contains your Vue.js components. Components make up the different parts of your page and can be reused and imported into your pages, layouts and even other components.&lt;/p&gt;
&lt;p&gt;More information about the…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/timotej-avsec/mubo-frontend" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;p&gt;Project is available on &lt;a href="https://www.mubo.one" rel="noopener noreferrer"&gt;https://www.mubo.one&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FH4hmQiq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FH4hmQiq.png" alt="Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>atlashackathon</category>
    </item>
    <item>
      <title>My First Front-End-Only Project</title>
      <dc:creator>Timotej Avsec</dc:creator>
      <pubDate>Fri, 14 Aug 2020 18:34:10 +0000</pubDate>
      <link>https://dev.to/timotej_avsec/my-first-front-end-only-project-375h</link>
      <guid>https://dev.to/timotej_avsec/my-first-front-end-only-project-375h</guid>
      <description>&lt;p&gt;Hey guys!&lt;/p&gt;

&lt;p&gt;Recently I decided to make a front-end-only application, since I felt that as a full-stack developer, I was lacking in my front-end skills. &lt;br&gt;
So here is a little post on how I created &lt;a href="https://www.moviez.io"&gt;moviez.io&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Idea
&lt;/h1&gt;

&lt;p&gt;I wanted to create something that would be challenging, but also useful. So after some time of thinking and brainstorming, I decided to go with movie-fetching app, which displays info about movies, TV series or actors.&lt;/p&gt;

&lt;h1&gt;
  
  
  Frameworks
&lt;/h1&gt;

&lt;p&gt;For JavaScript framework I decided to go with VueJS, since it is the primary FE framework that we use in our company and would benefit me the most to improve on it. &lt;/p&gt;

&lt;p&gt;I also went for &lt;a href="https://buefy.org/"&gt;Buefy&lt;/a&gt; Vue package, which is built on top of &lt;a href="https://bulma.io/"&gt;Bulma&lt;/a&gt; CSS framework.&lt;/p&gt;

&lt;h1&gt;
  
  
  Data source
&lt;/h1&gt;

&lt;p&gt;Since the idea was to create only front-end, the app had to fetch data from external API. I decided to go with &lt;a href="https://www.themoviedb.org/"&gt;TMDB&lt;/a&gt; since it provides clean API interface.&lt;/p&gt;

&lt;h1&gt;
  
  
  CI/CD
&lt;/h1&gt;

&lt;p&gt;For the convenience reasons I also implemented simple CI/CD using GitLab's CD/CD system. &lt;br&gt;
It works in the following way: when I push changes to my development branch, project gets built and is deployed on staging AWS S3 bucket. When the &lt;em&gt;development&lt;/em&gt; branch is merged into &lt;em&gt;master&lt;/em&gt; branch, project is built and deployed to primary/production AWS S3 bucket. On production server there is also AWS CloudFront, that enables caching and overall better loading times.&lt;/p&gt;

&lt;h1&gt;
  
  
  TODO
&lt;/h1&gt;

&lt;p&gt;There is still a lot of improvements to be done. Here are some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create and share list of your favourite movies / TV shows&lt;/li&gt;
&lt;li&gt;Enable users to write review to movies and rate them (even tho it will require some back-end action 😊)&lt;/li&gt;
&lt;li&gt;Improve overall page performance&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In the end, I feel like I have learned a lot through this simple project. Even through this project is relatively simple, I tried to follow &lt;a href="https://vuejs.org/v2/style-guide/"&gt;Vue good practises&lt;/a&gt; and front-end good practices overall.  &lt;/p&gt;

&lt;p&gt;So this is it from my part, if you have any opinions, well-intentioned criticism or just potential improvements, please do share them in the comments 🤗.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>vue</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
