Important to know how to use API KEYS and understand the ai.js file.
import { HfInference } from '@huggingface/inference'This imports the Hugging Face Inference client from the package:
@huggingface/inference
This library lets you call AI models hosted on Hugging Face via API.
If this package is not installed, you must run:
npm install @huggingface/inferenceconst SYSTEM_PROMPT = `
You are an assistant that receives a list of ingredients...
`This is the instruction given to the AI.
It tells the model:
- it will receive ingredients
- it must suggest a recipe
- it can add extra ingredients
- it must format the response in markdown
Example response from the AI might be:
## Tomato Pasta
### Ingredients
- tomatoes
- pasta
- olive oil
- garlic
Markdown is useful because React can render it nicely.
const hf = new HfInference(process.env.HF_ACCESS_TOKEN)This line is very important.
It creates the Hugging Face client and injects your API key from the environment variable.
Your .env should look like:
HF_ACCESS_TOKEN=your_huggingface_key
And your .gitignore should contain:
.env
So the key never goes to GitHub.
export async function getRecipeFromMistral(ingredientsArr)This function:
- receives an array of ingredients
Example:
["tomato", "onion", "pasta"]const ingredientsString = ingredientsArr.join(", ")This transforms:
["tomato", "onion", "pasta"]
into:
"tomato, onion, pasta"
So it can be sent to the AI.
const response = await hf.chatCompletion({This sends a request to Hugging Face's API.
model: "mistralai/Mixtral-8x7B-Instruct-v0.1"This is the Mixtral model by Mistral AI.
It is a strong instruction-following LLM.
messages: [
{ role: "system", content: SYSTEM_PROMPT },
{ role: "user", content: `I have ${ingredientsString}. Please give me a recipe you'd recommend I make!` },
]This follows the ChatGPT-style format:
Defines the assistant behavior.
Example sent to the model:
I have tomato, onion, pasta. Please give me a recipe you'd recommend I make!
max_tokens: 1024This limits the maximum response size.
1024 tokens ≈ 700–800 words.
Good for recipes.
return response.choices[0].message.contentThe API returns a big JSON object.
Example structure:
response
└ choices
└ 0
└ message
└ content
You return only the text generated by the AI.
catch (err) {
console.error(err.message)
}If something fails (API error, invalid key, etc.), it logs the error.
It depends on your environment.
Works perfectly if you add:
import dotenv from "dotenv"
dotenv.config()Example:
import dotenv from "dotenv"
dotenv.config()
import { HfInference } from '@huggingface/inference'If this file runs inside React, it WILL NOT WORK because:
process.env.HF_ACCESS_TOKEN
is not available in the browser.
React requires prefixes:
VITE_HF_ACCESS_TOKEN
or
REACT_APP_HF_ACCESS_TOKEN
But exposing API keys in frontend is dangerous.
If this runs in React, your API key will be visible in the browser.
Anyone could steal it.
Best architecture:
React (frontend)
↓
Node / Express API
↓
HuggingFace API
So the key stays only on the server.
const recipe = await getRecipeFromMistral([
"chicken",
"rice",
"garlic"
])
console.log(recipe)AI response example:
## Garlic Chicken Rice
### Ingredients
- chicken
- rice
- garlic
- olive oil
✅ Summary
Your file:
- correctly calls Hugging Face inference API
- uses Mixtral
- formats a recipe assistant
- reads the API key from
.env
It will work if:
.envcontainsHF_ACCESS_TOKEN.envis ignored by gitdotenvis loaded (Node.js)@huggingface/inferenceis installed
Work with Node.js backend
Using Node.js as a backend lets you keep your API keys on the server, so they never reach the browser. The frontend (React) calls your backend, and the backend calls the AI API. This is the standard architecture used in production.
Without a backend:
React App (browser)
↓
HuggingFace API
Your key must be inside the React code → anyone can see it in DevTools.
With a backend:
React (frontend)
↓ HTTP request
Node.js backend
↓
HuggingFace API
Only the Node server knows the API key. The browser never sees it.
Example project structure:
project
│
├── frontend (React)
│
└── backend
├── server.js
├── ai.js
├── .env
├── package.json
Your API key lives only in the backend .env file.
Inside a new folder:
mkdir backend
cd backend
npm init -yInstall dependencies:
npm install express dotenv cors @huggingface/inferenceWhat these do:
- express → create API routes
- dotenv → load
.env - cors → allow your React app to call the backend
- huggingface sdk → call the AI
Create .env:
HF_ACCESS_TOKEN=your_huggingface_key
Add .env to .gitignore:
.env
node_modules
import { HfInference } from "@huggingface/inference"
const hf = new HfInference(process.env.HF_ACCESS_TOKEN)
export async function getRecipe(ingredients) {
const ingredientsString = ingredients.join(", ")
const response = await hf.chatCompletion({
model: "mistralai/Mixtral-8x7B-Instruct-v0.1",
messages: [
{ role: "system", content: "You are a recipe assistant." },
{ role: "user", content: `I have ${ingredientsString}. Suggest a recipe.` }
],
max_tokens: 500
})
return response.choices[0].message.content
}Now the API key stays on the server.
import express from "express"
import cors from "cors"
import dotenv from "dotenv"
import { getRecipe } from "./ai.js"
dotenv.config()
const app = express()
app.use(cors())
app.use(express.json())
app.post("/recipe", async (req, res) => {
const ingredients = req.body.ingredients
try {
const recipe = await getRecipe(ingredients)
res.json({ recipe })
} catch (err) {
res.status(500).json({ error: "AI request failed" })
}
})
app.listen(3000, () => {
console.log("Server running on port 3000")
})Your backend now exposes:
POST /recipe
Instead of calling HuggingFace directly, your React app calls your backend.
Example:
async function getRecipe(ingredients) {
const response = await fetch("http://localhost:3000/recipe", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ ingredients })
})
const data = await response.json()
return data.recipe
}Flow now becomes:
React → Node backend → HuggingFace
The browser only sees:
POST http://localhost:3000/recipe
It never sees your HuggingFace key.
Start the server:
node server.jsor better:
npm install nodemon
npx nodemon server.jsLater you can deploy the backend on:
- Render
- Railway
- Fly.io
- AWS
- DigitalOcean
Your .env variables become environment variables on the server.
This gives you:
- 🔒 secure API keys
- 🚀 scalable backend
- 📡 reusable API
- 🧠 real production architecture
Every professional AI SaaS works like this.