Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Lama Dev AI Chat Bot App Starter Setup
Demo Video of the app

https://github.com/user-attachments/assets/cefd957c-f2a0-405f-a845-8e9aee438f54

This template provides a minimal setup to get React 19 working in Vite with HMR and some ESLint rules.
25 changes: 25 additions & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local
.env

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
168 changes: 168 additions & 0 deletions backend/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import express from "express";
import cors from "cors";
import path from "path";
import url, { fileURLToPath } from "url";
import ImageKit from "imagekit";
import mongoose from "mongoose";
import Chat from "./models/chat.js";
import UserChats from "./models/userChats.js";
import { ClerkExpressRequireAuth } from "@clerk/clerk-sdk-node";

const port = process.env.PORT || 3000;
const app = express();

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

app.use(
cors({
origin: process.env.CLIENT_URL,
credentials: true,
})
);

app.use(express.json());

const connect = async () => {
try {
await mongoose.connect(process.env.MONGO);
console.log("Connected to MongoDB");
} catch (err) {
console.log(err);
}
};

const imagekit = new ImageKit({
urlEndpoint: process.env.IMAGE_KIT_ENDPOINT,
publicKey: process.env.IMAGE_KIT_PUBLIC_KEY,
privateKey: process.env.IMAGE_KIT_PRIVATE_KEY,
});

app.get("/api/upload", (req, res) => {
const result = imagekit.getAuthenticationParameters();
res.send(result);
});

app.post("/api/chats", ClerkExpressRequireAuth(), async (req, res) => {
const userId = req.auth.userId;
const { text } = req.body;

try {
// CREATE A NEW CHAT
const newChat = new Chat({
userId: userId,
history: [{ role: "user", parts: [{ text }] }],
});

const savedChat = await newChat.save();

// CHECK IF THE USERCHATS EXISTS
const userChats = await UserChats.find({ userId: userId });

// IF DOESN'T EXIST CREATE A NEW ONE AND ADD THE CHAT IN THE CHATS ARRAY
if (!userChats.length) {
const newUserChats = new UserChats({
userId: userId,
chats: [
{
_id: savedChat._id,
title: text.substring(0, 40),
},
],
});

await newUserChats.save();
} else {
// IF EXISTS, PUSH THE CHAT TO THE EXISTING ARRAY
await UserChats.updateOne(
{ userId: userId },
{
$push: {
chats: {
_id: savedChat._id,
title: text.substring(0, 40),
},
},
}
);

res.status(201).send(newChat._id);
}
} catch (err) {
console.log(err);
res.status(500).send("Error creating chat!");
}
});

app.get("/api/userchats", ClerkExpressRequireAuth(), async (req, res) => {
const userId = req.auth.userId;

try {
const userChats = await UserChats.find({ userId });

res.status(200).send(userChats[0].chats);
} catch (err) {
console.log(err);
res.status(500).send("Error fetching userchats!");
}
});

app.get("/api/chats/:id", ClerkExpressRequireAuth(), async (req, res) => {
const userId = req.auth.userId;

try {
const chat = await Chat.findOne({ _id: req.params.id, userId });

res.status(200).send(chat);
} catch (err) {
console.log(err);
res.status(500).send("Error fetching chat!");
}
});

app.put("/api/chats/:id", ClerkExpressRequireAuth(), async (req, res) => {
const userId = req.auth.userId;

const { question, answer, img } = req.body;

const newItems = [
...(question
? [{ role: "user", parts: [{ text: question }], ...(img && { img }) }]
: []),
{ role: "model", parts: [{ text: answer }] },
];

try {
const updatedChat = await Chat.updateOne(
{ _id: req.params.id, userId },
{
$push: {
history: {
$each: newItems,
},
},
}
);
res.status(200).send(updatedChat);
} catch (err) {
console.log(err);
res.status(500).send("Error adding conversation!");
}
});

app.use((err, req, res, next) => {
console.error(err.stack);
res.status(401).send("Unauthenticated!");
});

// PRODUCTION
app.use(express.static(path.join(__dirname, "../client/dist")));

app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "../client/dist", "index.html"));
});

app.listen(port, () => {
connect();
console.log("Server running on 3000");
});
32 changes: 32 additions & 0 deletions backend/models/chat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import mongoose from "mongoose";

const chatSchema = new mongoose.Schema({
userId: {
type: String,
required: true,
},
history: [
{
role: {
type: String,
enum: ["user", "model"],
required: true,
},
parts: [
{
text: {
type: String,
required: true,
},
},
],
img:{
type:String,
required:false
}
},
],
},{timestamps:true});

export default mongoose.models.chat || mongoose.model("chat",chatSchema)

30 changes: 30 additions & 0 deletions backend/models/userChats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import mongoose from "mongoose";

const userChatsSchema = new mongoose.Schema(
{
userId: {
type: String,
required: true,
},
chats: [
{
_id: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
createdAt: {
type: Date,
default: Date.now(),
},
},
],
},
{ timestamps: true }
);

export default mongoose.models.userChats ||
mongoose.model("userChats", userChatsSchema);
Loading