Skip to content

ajkendal/scrimba-bot

Repository files navigation

🤖 Scrimb Bot

Scrimb Bot is the hands-on project you’ll build throughout the Build AI Apps with LangChain.js course.
It showcases how to use LangChain.js to create a working AI chatbot from scratch, with prompts, chains, and memory.


🎯 About the Course

This project is developed as part of the Scrimba course Build AI Apps with LangChain.js.
The course guides you step by step through:

  • Setting up LangChain.js in a Node.js environment
  • Designing prompts and building chains
  • Adding memory to conversations
  • Extending bots with tools and external data sources
  • Deploying and experimenting with AI apps

By the end of the course, you’ll have your own chatbot (Scrimb Bot) and the skills to extend it further.


🚀 Features

  • Console-based chatbot powered by LangChain.js
  • Structured prompts with role separation
  • Conversation memory for context-aware replies
  • Supabase integration for storing and retrieving data
  • OpenAI API for intelligent responses
  • Modular design for extending with new chains/tools
  • Built with modern JavaScript practices

📦 Tech Stack


Workflow

Workflow Diagram


🗄️ Setting Up the Database with Supabase

import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';
import { createClient } from '@supabase/supabase-js';
import { SupabaseVectorStore } from 'langchain/vectorstores/supabase';
import { OpenAIEmbeddings } from 'langchain/embeddings/openai';

// @supabase/supabase-js
try {
  const result = await fetch('scrimba-info.txt');
  const text = await result.text();
  const splitter = new RecursiveCharacterTextSplitter({
    chunkSize: 500,
    chunkOverlap: 50,
    separators: ['\n\n', '\n', ' ', ''], // default setting
  });

  const output = await splitter.createDocuments([text]);

  const sbApiKey = process.env.SUPABASE_API_KEY;
  const sbUrl = process.env.SUPABASE_URL_LC_CHATBOT;
  const openAIApiKey = process.env.OPENAI_API_KEY;

  const client = createClient(sbUrl, sbApiKey);

  await SupabaseVectorStore.fromDocuments(
    output,
    new OpenAIEmbeddings({ openAIApiKey }),
    {
      client,
      tableName: 'documents',
    }
  );
  console.log('success');
} catch (err) {
  console.log(err);
}

📝 Starter Code

When you first begin the course, your entry file (index.js, index.html, index.css) may look something like this:

document.addEventListener('submit', (e) => {
  e.preventDefault();
  progressConversation();
});

const openAIApiKey = process.env.OPENAI_API_KEY;

async function progressConversation() {
  const userInput = document.getElementById('user-input');
  const chatbotConversation = document.getElementById(
    'chatbot-conversation-container'
  );
  const question = userInput.value;
  userInput.value = '';

  // add human message
  const newHumanSpeechBubble = document.createElement('div');
  newHumanSpeechBubble.classList.add('speech', 'speech-human');
  chatbotConversation.appendChild(newHumanSpeechBubble);
  newHumanSpeechBubble.textContent = question;
  chatbotConversation.scrollTop = chatbotConversation.scrollHeight;

  // add AI message
  const newAiSpeechBubble = document.createElement('div');
  newAiSpeechBubble.classList.add('speech', 'speech-ai');
  chatbotConversation.appendChild(newAiSpeechBubble);
  newAiSpeechBubble.textContent = result;
  chatbotConversation.scrollTop = chatbotConversation.scrollHeight;
}
<!DOCTYPE html>
<html>
  <head>
    <title>Scrimba Chatbot</title>
    <link rel="stylesheet" href="index.css" />
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=Poppins&family=Roboto&display=swap"
      rel="stylesheet"
    />
  </head>

  <body>
    <main>
      <section class="chatbot-container">
        <div class="chatbot-header">
          <img src="images/logo-scrimba.svg" class="logo" />
          <p class="sub-heading">Knowledge Bank</p>
        </div>
        <div
          class="chatbot-conversation-container"
          id="chatbot-conversation-container"
        ></div>
        <form id="form" class="chatbot-input-container">
          <input name="user-input" type="text" id="user-input" required />
          <button id="submit-btn" class="submit-btn">
            <img src="images/send.svg" class="send-btn-icon" />
          </button>
        </form>
      </section>
    </main>
    <script src="index.js" type="module"></script>
  </body>
</html>
:root {
  --border-rad-lg: 15px;
  --light-text: #fefefe;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  font-family: 'Poppins';
}

main {
  background-color: slategrey;
  background-image: url('images/scrimba-bg.jpeg');
  background-size: cover;
  background-repeat: no-repeat;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* chatbot elements */

.chatbot-container {
  background-color: #171f26;
  width: 360px;
  min-height: 380px;
  border-radius: var(--border-rad-lg);
  padding: 1em;
}

.chatbot-container > * {
  padding: 0.5em;
}

.chatbot-header {
  display: flex;
  flex-direction: column;
  gap: 0.6em;
}

.logo {
  width: 160px;
}

.chatbot-conversation-container {
  height: 250px;
  overflow-y: scroll;
  margin: 1em 0;
}

/* stop ugly scroll bar on some browsers */
.chatbot-conversation-container::-webkit-scrollbar {
  display: none;
}

.chatbot-conversation-container::-moz-scrollbar {
  display: none;
}

.speech {
  padding: 1em;
  max-width: 240px;
  color: var(--light-text);
  min-width: 90%;
  border-radius: var(--border-rad-lg);
  font-size: 1.07em;
}

.speech:first-child {
  margin-top: 0;
}

.speech-ai {
  background: #334959;
  border-top-left-radius: 0;
  margin: 1.2em 1em 0 0;
}

.speech-human {
  margin: 1.2em 0 0 1em;
  background: #2f4f4f;
  border-top-right-radius: 0;
}

.chatbot-input-container {
  display: flex;
}

input[type='text'],
button {
  background-color: transparent;
  border: 1px solid #586e88;
  border-radius: var(--border-rad-lg);
  padding: 1em;
}

input[type='text'] {
  color: var(--light-text);
  width: 100%;
  border-right: 0;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

button {
  border-left: 0;
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

.send-btn-icon {
  width: 20px;
  display: block;
}

/* text */
.sub-heading {
  color: #999999;
  font-family: 'Roboto', sans-serif;
  font-size: 12px;
  text-transform: uppercase;
  margin: 0;
}

This simple starting point helps you verify your setup and gives you a base to build on. As you progress through the course, you’ll:

  • Import and configure LangChain.js
  • Add chains and prompt templates
  • Connect memory and Supabase
  • Integrate the OpenAI API

📚 Learning Outcomes

By completing this project, you’ll learn how to:

  • Build AI apps with LangChain.js
  • Structure prompts and conversations
  • Add memory for contextual chatbots
  • Store and retrieve data with Supabase
  • Connect to the OpenAI API for responses
  • Deploy and iterate on AI applications

About

Scrimb Bot is a chatbot built in the Build AI Apps with LangChain.js course on Scrimba. It combines LangChain.js, OpenAI, and Supabase to demonstrate how to create AI-powered apps with memory, data storage, and intelligent responses.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors