Don't Have to Read Docs Again, Ever?

Don't Have to Read Docs Again, Ever?

I Built a smart doc reading buddy using Modus & Dgraph for a hackathon

Ever spent hours debating whether to dig through docs, jumping between pages, just to find that one specific detail you need? Been there, done that.

What if I told you there's a way this whole process can be done on autopilot?

Ahem, introducing Docsy - a smart extension that skims through the documentation for you, and delivers you the exact parts you were looking for. All you have to do is just ask!

👉 Here’s the Github Repo, go ahead and follow the Readme to set it up and use✨


In this blog, I'll walk you through how exactly I built Docsy using Modus and Dgraph by hypermode, and everything else that went into it.

But before that, let me tell you why I built this in the first place-

Why Docsy?

Okay, confession - I'm a dev and I'm not really a big fan of reading docs (please don't cancel me🫣).

The thing is, it's not just me. We've all been there:

  • Getting lost in documentation rabbit holes (and finding cool stuff you don't need right now)

  • "I swear I just read about this somewhere..."

  • Finally finding the answer and thinking "how could I miss this?"

I wanted to transform this repetitive and sometimes frustrating process into something faster, smarter, and actually enjoyable. That's where Docsy came in.

And when I stumbled upon ModusHack, I knew it was a perfect opportunity to create a fun solution while playing with some new tech ^-^


The Tech Stack⚙️

🦄 Frontend: React + TypeScript + Tailwind

🧠 Backend: Modus (LLaMA) + Dgraph

But wait... what's this Modus and Dgraph we are talking about? 🤔

What is Modus?

Modus is this cool serverless framework that lets you work with AI models (like meta-llama/Meta-Llama-3.1-8B-Instruct in our case) without the typical headache of managing servers etc. that comes with it. It supports WebAssembly & Go i.e. its super fast.

And Dgraph?

Dgraph is the memory of our project. But it’s not just any database; it's a graph database with vector search capabilities! Yes, perfect for any AI project!

Next, how they work together?


How it works?

Here’s a brief architecture diagram of the application:

So, when you ask a question (probably something like "where the heck is this configuration option?"), all this is happening behind the scenes:

  1. The crawler scans and indexes all content to Dgraph

  2. Each documentation chunk gets converted into embeddings for semantic search

  3. Dgraph performs semantic search to find relevant documentation

  4. Modus processes your query and the result sent by Dgraph, through LLaMA

  5. Everything gets synthesized into a comprehensive response

Alright, enough theory - let's get our hands dirty! I’ll walk you through how I built this thing piece by piece 🏗️!


Let’s Build!🧱

This is what we're gonna do, we will break the whole process into 5 simple steps👇

Step: 1 -> Setting up

Step: 2 -> Dgraph setup

Step: 3 -> Adding crawler code

Step: 4 -> Setting Up Modus

Step: 5 -> Bringing It All Together

So, without further ado, let's get coding🚀


Step 1: Setting up ⚙️

Let’s start with creating the UI for Docsy and setting up the foundation of the extension.

Creating the Extension

  1. Set Up Your Project:

    • Create a new folder named extension.

    • Initialize it with npm init -y.

    • Add your dependencies:

        npm install react react-dom typescript tailwindcss
      
  2. Add Chrome-Specific Files:

    • Create a manifest.json file. This tells Chrome what the extension does. Add this basic setup:

        {
          "manifest_version": 3,
          "name": "Docsy",
          "version": "1.0",
          "permissions": ["tabs", "activeTab", "storage", "windows"],
          "background": {
            "service_worker": "background.js"
          },
          "action": {
            "default_popup": "index.html",
            "default_icon": "icon.png"
          }
        }
      
  3. Write the Popup UI:

    Create a src/App.tsx file and design the layout using TailwindCSS.

    • Add an input for queries and a section to display responses.

    • Use Tailwind classes to make it visually appealing.

This is how my UI looks like 👇 here is the code if you wana copy it :)

Connect to Backend

  • Create a background.js file to handle backend communication.

  • We will use chrome.runtime.sendMessage to communicate with our backend (Modus + Dgraph).

      chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
        if (message.action === "processQuery") {
          fetch(GRAPHQL_ENDPOINT_URL, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
              query: `
                query {
                  generateDocumentationResponse(
                    question: "${message.query}",
                    currentUrl: "${message.currentUrl}"
                  ) {
                    response
                    links { title url }
                  }
                }
              `,
            }),
          })
            .then((res) => res.json())
            .then((data) => sendResponse({ success: true, data }))
            .catch((error) => sendResponse({ success: false, error }));
          return true;
        }
      });
    

🤸 Let’s make it a lil fun?
If you want to trigger this extension just by pressing Alt + Space in your browser, it can simply be done by adding this to manifest.json👇

  "commands": {
    "_execute_action": {
      "suggested_key": {
        "default": "Alt+Space",
        "mac": "Alt+Space"
      },
      "description": "Open the popup"
    }
  },

Step 2: Setting Up Dgraph🛢

Time to give Docsy a memory! Dgraph will act as the knowledge base for storing and searching documentation.

Create a Dgraph Account

  1. Go to Dgraph Cloud and create an account.

  2. Set up a new backend and note your API endpoint and admin key.

Adding the Schema

We’ll use this schema to represent documentation pages and their relationships:

type Page {
  id: ID!
  title: String! @search(by: [term])
  url: String! @search(by: [term])
  content: String @search(by: [fulltext])
  embedding: [Float!]
  headings: [Heading!] @hasInverse(field: "parentPage")
}
type Heading {
  id: ID!
  title: String! @search(by: [term])
  embedding: [Float!]
  parentPage: Page!
}

Deploy the Schema

  1. Go to the Dgraph Cloud Console.

  2. Under the GraphQL Schema tab, paste the schema and deploy it.

Why Graph Databases?

  • Graph databases like Dgraph allow us to represent relationships (e.g., between a page and its headings).

  • The vector search feature enables semantic search for more intelligent results.

Step 3: Adding Crawlers🕷️

Now, let’s index documentation pages into Dgraph for semantic search.

Setting Up Puppeteer for Crawling

  1. Install Puppeteer:

     npm install puppeteer
    

    Writing the Crawler Script

    1. Create a crawl.js file in dgraph-backend/src/crawler.

    2. Use Puppeteer to extract links, content, and headings:

       const puppeteer = require("puppeteer");
      
       async function crawlDocumentation(startUrl, maxPages = 100) {
         const browser = await puppeteer.launch();
         const visitedUrls = new Set();
         const queue = [startUrl];
         const pages = [];
      
         while (queue.length && pages.length < maxPages) {
           const url = queue.shift();
           if (visitedUrls.has(url)) continue;
      
           const page = await browser.newPage();
           await page.goto(url);
           const content = await page.content();
      
           const links = await page.$$eval("a", (anchors) =>
             anchors.map((a) => a.href)
           );
      
           pages.push({ url, content });
           queue.push(...links);
           visitedUrls.add(url);
         }
         await browser.close();
         return pages;
       }
       module.exports = crawlDocumentation;
      

      Storing Crawled Data

      1. Send the extracted data to Dgraph:

         const { queryDgraph } = require("../dgraph/queryDgraph");
        
         async function storeCrawledData(pages) {
           const mutation = `
             mutation AddPages($pages: [AddPageInput!]!) {
               addPage(input: $pages) {
                 page { id title url }
               }
             }
           `;
           await queryDgraph(mutation, { pages });
         }
        

Step 4: Setting Up Modus👾

Now, let’s add the AI magic to Docsy with Modus.

Install Modus CLI

First, install the Modus CLI globally. This will help you create and manage your Modus project:

    npm install -g @hypermode/modus-cli

Create a New Modus Project

    modus new

When prompted, select AssemblyScript as the SDK (p.s. AssemblyScript is super similar to TypeScript).

Add the LLaMA Model

Docsy uses the meta-llama/Meta-Llama-3.1-8B-Instruct model for query processing. It’s hosted by Modus, so adding it is straightforward:

  1. Open the modus.json file in your Modus project.

  2. Add the following configuration under models:

    "models": {
      "text-generator": {
        "sourceModel": "meta-llama/Meta-Llama-3.1-8B-Instruct",
        "provider": "hugging-face",
        "connection": "hypermode"
      }
    }

Create Query Handling Logic

  1. Update the assembly/index.ts to handle queries:

     import { models } from "@hypermode/modus-sdk-as";
    
     export function generateDocumentationResponse(question: string): string {
       const model = models.getModel("text-generator");
       const input = model.createInput([{ role: "user", content: question }]);
       const response = model.invoke(input);
       return response.choices[0].message.content;
     }
    

Test Your Modus Backend

Once you run this command, your endpoint will be exposed on the url: https://localhost:8686/graphql.

    modus dev

Use tools like Postman or curl to make a request to the Modus endpoint and verify the responses.

Step 5: Bringing It All Together🦾

Finally, let’s connect the frontend, Dgraph backend, and Modus AI.

Connecting the Components

  1. Update background.js to handle query requests:

    • Query Dgraph for semantic search.

    • If Dgraph is rate-limited, use scraped data as a fallback❗

    • Send the query to Modus for processing.

And….There you have it🎉

I couldn’t cover everything. But here is the full source code 📦.

Do follow this readme to add the extension to your browser!


Conclusion👋

Well, you can now officially read docs like just a chill guy😎

Here are some resources for you👇

💜 Official Modus docs

🩷 Official Dgraph docs

💙 Hypermode Discord community

❤️ GitHub Repo


That's all folks!

I hope you had fun reading this blog. Don't forget to share your thoughts with me.

See you on the next one!!