Skip to content

Running Embeddings and Vector Databases locally ​

Use this page to run the extracted ReelRecs movie chatbot from Embeddings and Vector Databases on your computer, with your own OpenAI key and the Supabase database you built during the course. Three things differ from Scrimba's editor: two packages must be installed by name, the reads in config.js need Vite's syntax, and the chat model the project names has been retired.

What you need first ​

Install a supported LTS version of Node.js. Node 24 is recommended and includes npm.

Check that both commands work. Your version numbers may be different:

bash
$ node --version
v24.18.0
$ npm --version
11.18.0

You also need three values:

  • An OpenAI API key. Create one you will delete when you are done: this project calls OpenAI straight from the browser, so the key ends up in the page.
  • Your Supabase project URL, from the Supabase project that holds the movies and the match_movies function you made during the course.
  • That project's publishable key, which starts with sb_publishable_. If your project shows only the older anon key, use that. Never use the secret key or the service_role key here.
JunoWhat you need first Install the LTS version of Node.js and check that node --version and npm --version both print a version.

Then collect your OpenAI key, your Supabase project URL and its publishable key. The Supabase project must be the one you filled with movies in the course.

JunoWhat you need first This project only reads your movies: nothing in it creates the table, the numbers or match_movies. If that Supabase project is empty, the chatbot runs but answers "Sorry, I don't know the answer."
JunoWhat you need first The publishable key can only do what your Row Level Security policies allow, which is why Supabase makes it for browser code. The OpenAI key has no such limit: whoever copies it can spend your credit until you delete it.

Install the packages ​

Open a terminal in the extracted folder. It is the one containing package.json, config.js and index.js:

bash
$ cd path-to-your-extracted-project

package.json lists only Vite, but config.js imports the OpenAI and Supabase packages too. Scrimba's editor installs those for you; on your computer, name them and npm installs them along with Vite:

bash
$ npm install openai @supabase/supabase-js
added 25 packages, and audited 26 packages in 9s

npm finishes by reporting how many packages it added.

JunoInstall the packages Open the terminal in the folder that contains package.json, then run npm install openai @supabase/supabase-js. npm ends by saying how many packages it added.

If npm says it cannot find package.json, you are in the wrong folder.

JunoInstall the packages npm installs what package.json lists, and naming two packages adds them to that list, so one command installs all three. A plain npm install would give you Vite alone.
JunoInstall the packages Without the two packages, npm start still serves the page: Vite's start-up scan only prints a warning, and the import fails when the browser asks for config.js, as an error over the page.

Change config.js and index.js ​

Scrimba's editor fills in process.env.OPENAI_API_KEY, process.env.SUPABASE_API_KEY and process.env.SUPABASE_URL for you. The browser has no process, and Vite does not create one, so all four reads in config.js must change; the OpenAI key is read twice. Vite hands browser code only the variables whose names start with VITE_, which is why each name gains that prefix.

Replace the contents of config.js with:

js
import OpenAI from 'openai';
import { createClient } from "@supabase/supabase-js";

/** OpenAI config */
if (!import.meta.env.VITE_OPENAI_API_KEY) throw new Error("OpenAI API key is missing or invalid.");
export const openai = new OpenAI({
  apiKey: import.meta.env.VITE_OPENAI_API_KEY,
  dangerouslyAllowBrowser: true
});

/** Supabase config */
const privateKey = import.meta.env.VITE_SUPABASE_API_KEY;
if (!privateKey) throw new Error(`Expected env var SUPABASE_API_KEY`);
const url = import.meta.env.VITE_SUPABASE_URL;
if (!url) throw new Error(`Expected env var SUPABASE_URL`);
export const supabase = createClient(url, privateKey);

Only the four reads differ from the file you downloaded. The two Supabase error messages still name the old variables; leave them as they are.

Then open index.js. The chat request asks for gpt-4, which OpenAI has retired. In getChatCompletion, change:

js
model: 'gpt-4',

to:

js
model: 'gpt-4o-mini',

Leave the other model in index.js, text-embedding-ada-002, as it is. The movies in your database were turned into numbers with that model, and your question has to be turned into numbers the same way to be compared with them.

JunoChange config.js and index.js Paste the new config.js over the old one, then change gpt-4 to gpt-4o-mini in index.js.

Don't touch text-embedding-ada-002; your database depends on it.

JunoChange config.js and index.js When Vite serves config.js, it replaces each import.meta.env.VITE_... read with the value from .env. A name without the prefix stays hidden from browser code, arrives as undefined, and trips the checks in config.js.
JunoChange config.js and index.jsconfig.js throws while it loads, before index.js attaches its form handler. So a bad read leaves a page that looks normal, but pressing Enter reloads it and your question vanishes.

Add your keys to .env ​

Create .env beside package.json with your three values:

dotenv
VITE_OPENAI_API_KEY=your-openai-api-key
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_API_KEY=your-publishable-key

Create .gitignore beside package.json and add:

txt
.env
node_modules/

A key that reaches a Git repository stays in its history even after you delete the file. The Git handbook covers the habit in ignoring files and good habits.

These keys are visible in the browser

Vite writes every VITE_ value into the code it sends to the browser, so anyone who opens this page can read your OpenAI key. Keep this version on your own computer: never deploy or share it, and never commit .env. A version you publish needs a backend that keeps the OpenAI key on the server, as in the Vercel AI SDK project.

JunoAdd your keys to .env Make a file called .env next to package.json with your three values, one per line, then list .env in .gitignore so Git never saves it.
JunoAdd your keys to .env Vite reads .env when it starts and then watches it: saving a change prints .env changed, restarting server..., and the open page reloads with the new values.
JunoAdd your keys to .env The VITE_ prefix is an exposure allowlist, not secret storage: the OpenAI key sits in the module Vite serves and in the header of every request the browser sends to OpenAI.

Start the chatbot and ask a question ​

Start the development server:

bash
$ npm start

Vite may first print a warning that begins (!) Your Vite config uses features. It does not stop the app. A different warning, (!) Failed to run dependency scan, means the two packages are missing: go back to the install step. Below the warnings, Vite prints the address to open:

text
  VITE v8.3.4  ready in 218 ms

  ➜  Local:   http://localhost:5173/

Open the exact Local address. The page shows ReelRecs and a box that says "How can I help?". Ask about a movie in your database and press Enter. Thinking... appears, and after a few seconds the answer replaces it. An answer about your movies means OpenAI and Supabase both work.

If your question disappears and nothing else happens, the page never got your keys; the first troubleshooting entries below match the terminal line.

If the page says "Sorry, something went wrong. Please try again.", look in the terminal where npm start is running. Vite copies the browser's error there, on a line containing Error in main function.; the troubleshooting below matches each message. The same line is in your browser's developer tools (F12, or Cmd+Option+J in Chrome on a Mac), on the Console tab.

Stop the project with Ctrl+C. If you save .env while it runs, Vite restarts itself (.env changed, restarting server...) and the page reloads with the new values.

JunoStart the chatbot and ask a question Run npm start, ignore the config warning if it appears, and open the Local address. Ask about one of your movies and wait for the answer.

If you get "Sorry, something went wrong", read the newest line in the terminal.

JunoStart the chatbot and ask a question One question runs three requests in order: OpenAI makes numbers from it, Supabase's match_movies finds the nearest movies, and OpenAI writes the reply. Any of them failing shows the same sorry message, so the error line tells you which one to fix.
JunoStart the chatbot and ask a questionmain wraps all three requests in one try/catch and logs only the error's message. Vite 8 forwards that console.error from the browser to the terminal, which is why the terminal shows a browser failure.

Troubleshooting ​

The terminal shows (!) Failed to run dependency scan, and the browser shows Failed to resolve import "openai" from "config.js": The two packages are not installed. Stop the project, run npm install openai @supabase/supabase-js in the folder that contains package.json, then start the project again.

Your question vanishes when you press Enter, and the terminal shows ReferenceError: process is not defined: A process.env read is still in config.js. Replace the file with the version shown above and save it.

Your question vanishes, and the terminal shows OpenAI API key is missing or invalid or Expected env var: Vite found no value. Check that .env is beside package.json and that each name starts with VITE_, then save it; Vite restarts itself and the page reloads. The messages name the old variables, but the names in .env are the VITE_ ones.

Error in main function. 401 Incorrect API key provided: OpenAI did not accept the key. Copy it again from your OpenAI account and check that it has not been deleted.

Error in main function. 429 You exceeded your current quota: The key works, but the account has no credit to spend. Add credit under Billing in your OpenAI account, then ask again.

Error in main function. Cannot read properties of null (reading 'map'): OpenAI worked, but Supabase sent back an error instead of movies. Check the project URL, use the publishable key, and check that match_movies exists in that same project. For the exact reason, open the developer tools' Network tab, ask again, and click the request named match_movies.

The chatbot answers "Sorry, I don't know the answer.": Everything ran, but Supabase found no movie close enough to your question. Ask about a movie that is in your table. If every question gets this answer, check in Supabase that the table has rows and that Row Level Security lets the publishable key read them.

Error in main function. followed by a message that names the model (gpt-4 or gpt-4o-mini): Check that index.js asks for gpt-4o-mini, not gpt-4. After January 14, 2027, OpenAI stops serving gpt-4o-mini too; from then on, use the replacement its deprecations page names.

JunoTroubleshooting Find the line in the terminal that starts with Error in main function. and match the words after it to a bold heading above. If your question just vanishes, look at config.js and .env first.
JunoTroubleshooting The failures come in the order the code runs: the packages, the reads in config.js, the OpenAI key, then Supabase, then your data. Fix the first one you meet; the next only shows once it is gone.
JunoTroubleshootingfindNearestMatch ignores the error that Supabase returns and calls data.map on the null beside it. So a wrong URL, a rejected key and a missing function all read as the same null; the Network tab holds the real reason.