);
};
-export default ChatMessage;
+ChatMessageBot.propTypes = {
+ msg: PropTypes.shape({
+ bot: PropTypes.string,
+ user: PropTypes.string,
+ }).isRequired,
+ isLiked: PropTypes.bool,
+ isDisliked: PropTypes.bool,
+ onLike: PropTypes.func.isRequired,
+ onDislike: PropTypes.func.isRequired,
+};
+ChatMessageBot.defaultProps = {
+ isLiked: false,
+ isDisliked: false,
+};
+
+export default ChatMessageBot;
diff --git a/client/src/pages/chat/ChatMessageUser.jsx b/client/src/pages/chat/ChatMessageUser.jsx
new file mode 100644
index 0000000..8925bae
--- /dev/null
+++ b/client/src/pages/chat/ChatMessageUser.jsx
@@ -0,0 +1,20 @@
+import PropTypes from "prop-types";
+
+// ChatMessageUser Component
+const ChatMessageUser = ({ msg }) => {
+ return (
+
+ )
+}
+
+ChatMessageUser.propTypes = {
+ msg: PropTypes.shape({
+ user: PropTypes.string,
+ }).isRequired,
+};
+
+export default ChatMessageUser;
diff --git a/client/src/pages/chat/ChatWelcome.jsx b/client/src/pages/chat/ChatWelcome.jsx
index 0a18fd2..c9300a3 100644
--- a/client/src/pages/chat/ChatWelcome.jsx
+++ b/client/src/pages/chat/ChatWelcome.jsx
@@ -3,14 +3,12 @@ import { Typography } from '@mui/material';
import { useEffect, useState } from 'react';
import ChatInput from './ChatInput';
-import { useAuth } from '../../hooks/useAuth';
import TypewriterEffect from '../../components/typing/TypewriterEffect';
// ChatWelcome component
export default function ChatWelcome({ onSend }) {
- const { userData } = useAuth();
const [greeting, setGreeting] = useState("Good Morning");
useEffect(() => {
@@ -23,10 +21,11 @@ export default function ChatWelcome({ onSend }) {
}, []);
return (
-
+
- {greeting}, {userData?.name.split(' ')[0]} π
+ Hello! {greeting} π
+
How can I assist you today?
@@ -36,15 +35,20 @@ export default function ChatWelcome({ onSend }) {
+
)
}
+
+ChatWelcome.propTypes = {
+ onSend: PropTypes.func.isRequired,
+};
diff --git a/client/src/pages/feedback/Feedback.jsx b/client/src/pages/feedback/Feedback.jsx
new file mode 100644
index 0000000..fd7bb9c
--- /dev/null
+++ b/client/src/pages/feedback/Feedback.jsx
@@ -0,0 +1,83 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import { useState, useEffect } from 'react';
+import {
+ Container, Grid, Paper, Typography, Card,
+ Table, TableBody, TableCell, TableContainer, TableHead, TableRow
+} from '@mui/material';
+
+import { useAuth } from '../../hooks/useAuth';
+import { useLoading } from '../../hooks/useLoading';
+
+
+
+export default function Feedback() {
+
+ const { http } = useAuth();
+ const { setLoading } = useLoading();
+
+ const [feedback, setFeedback] = useState([]);
+
+ useEffect(() => {
+ fetchData();
+ }, []);
+
+
+ const fetchData = async () => {
+ try {
+ setLoading(true);
+ const response = await http.get('/feedback');
+ setFeedback(response.data);
+ } catch (error) {
+ console.error("Error fetching sources:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+
+
+ return (
+
+
+
+
+ π Negative Feedback's Received
+
+
+
+ {feedback?.length === 0 ? (
+
+ No feedback available.
+
+ ) : (
+
+
+
+
+ #
+ Recieved From
+ User Message
+ Bot Response
+ User Comment
+ DateTime
+
+
+
+ {feedback?.map((fed, index) => (
+
+ {index + 1}
+ {fed?.email}
+ {fed?.userMessage}
+ {fed?.botResponse}
+ {fed?.comment}
+ {new Date(fed?.createdAt).toLocaleString()}
+
+ ))}
+
+
+
+ )}
+
+
+ )
+}
diff --git a/client/src/pages/files/FilesMain.jsx b/client/src/pages/files/FilesMain.jsx
index c26fde2..1a89315 100644
--- a/client/src/pages/files/FilesMain.jsx
+++ b/client/src/pages/files/FilesMain.jsx
@@ -71,6 +71,7 @@ export default function FileMain() {
const handleOpenSource = async (source) => {
try {
+ setLoading(true);
const response = await http.get(`/source/file/${source?.file_id}`);
setSourceData({
fileId: source?.file_id,
@@ -80,6 +81,8 @@ export default function FileMain() {
setOpen(true);
} catch (error) {
console.error("Error fetching chunks:", error);
+ } finally {
+ setLoading(false);
}
}
diff --git a/client/src/pages/login/Account.jsx b/client/src/pages/login/Account.jsx
new file mode 100644
index 0000000..1bed9cd
--- /dev/null
+++ b/client/src/pages/login/Account.jsx
@@ -0,0 +1,21 @@
+import { Typography } from '@mui/material'
+import React from 'react'
+
+export default function Account() {
+ return (
+
+
+ This page is under construction, please check back later.
+
+
+ We are working hard to bring you the best experience possible.
+
+
+ Thank you for your patience!
+
+
+ ~ Aman Singh
+
+
+ )
+}
diff --git a/client/src/pages/login/Login.jsx b/client/src/pages/login/Login.jsx
new file mode 100644
index 0000000..9c7c07e
--- /dev/null
+++ b/client/src/pages/login/Login.jsx
@@ -0,0 +1,189 @@
+import Box from "@mui/material/Box";
+import { toast } from "react-toastify";
+import { useEffect, useState } from "react";
+import { useNavigate } from "react-router-dom";
+import { DotLottieReact } from "@lottiefiles/dotlottie-react";
+import {
+ Typography, Button, TextField, IconButton, Grid, InputAdornment, Avatar,
+ useTheme, useMediaQuery, Paper
+} from '@mui/material';
+import {
+ Login as LoginIcon, LockOutlined, Visibility, VisibilityOff
+} from "@mui/icons-material";
+
+import { useAuth } from "../../hooks/useAuth";
+import { useLoading } from "../../hooks/useLoading";
+import TypewriterEffect from "../../components/typing/TypewriterEffect";
+
+
+// Login Component
+export default function Login() {
+ const navigate = useNavigate();
+ const { setLoading } = useLoading();
+ const { isAuthenticated, http, refreshAuth } = useAuth();
+ const [showPass, setShowPass] = useState(false);
+
+ const theme = useTheme();
+ const isMdUp = useMediaQuery(theme.breakpoints.up('md'));
+
+ useEffect(() => {
+ if (isAuthenticated) {
+ navigate("/admin/source");
+ }
+ }, [isAuthenticated, navigate]);
+
+ const handleLogin = async (e) => {
+ e.preventDefault();
+ try {
+ setLoading(true);
+ await http.post('/auth/login', {
+ email: e?.target?.email?.value,
+ password: e?.target?.password?.value,
+ });
+ await refreshAuth();
+ toast.success('Login successful!');
+ } catch (error) {
+ console.error(error);
+ if (error?.response?.status === 401) {
+ toast.error('Invalid email or password');
+ } else {
+ toast.error(error?.response?.data?.detail[0]?.msg ?? 'An error occurred');
+ }
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+ {/* Left Section - Only on md+ screens */}
+ {isMdUp && (
+
+
+ GENAI-BOT
+
+
+
+
+
+
+
+
+
+
+ )}
+
+ {/* Right Section - Always visible */}
+
+
+
+
+
+
+ Sign in
+
+
+
+
+ setShowPass(!showPass)}
+ >
+ {showPass ? : }
+
+
+ ),
+ },
+ }}
+ />
+ }
+ sx={{
+ mt: 4,
+ background: "linear-gradient(to right, #4a90e2, #a163e6)",
+ color: "#fff",
+ '&:hover': {
+ background: "linear-gradient(to right, #3a78c2, #884fd1)",
+ },
+ fontWeight: 600
+ }}
+ >
+ Sign In
+
+
+
+
+ );
+}
diff --git a/client/src/pages/welcome/Welcome.css b/client/src/pages/welcome/Welcome.css
deleted file mode 100644
index 004aace..0000000
--- a/client/src/pages/welcome/Welcome.css
+++ /dev/null
@@ -1,7 +0,0 @@
-.welcome__buttons {
- display: flex;
- justify-content: center;
- gap: 1rem;
- margin-top: 1rem;
- flex-wrap: wrap;
-}
\ No newline at end of file
diff --git a/client/src/pages/welcome/Welcome.jsx b/client/src/pages/welcome/Welcome.jsx
deleted file mode 100644
index 419f02f..0000000
--- a/client/src/pages/welcome/Welcome.jsx
+++ /dev/null
@@ -1,143 +0,0 @@
-import { useEffect, useState } from "react";
-import Box from "@mui/material/Box";
-import { useNavigate } from "react-router-dom";
-import { Grid, Typography, Button } from "@mui/material";
-import { Login as LoginIcon, AppRegistration } from "@mui/icons-material";
-import { DotLottieReact } from "@lottiefiles/dotlottie-react";
-
-import './Welcome.css';
-import Login from "../../components/auth/Login";
-import Register from "../../components/auth/Register";
-import TypewriterEffect from "../../components/typing/TypewriterEffect";
-import { useAuth } from "../../hooks/useAuth";
-
-
-// Welcome component
-export default function Welcome() {
-
- const navigate = useNavigate();
- const { isAuthenticated } = useAuth();
- const [openReg, setOpenReg] = useState(false);
- const [openLogin, setOpenLogin] = useState(false);
-
- useEffect(() => {
- if (isAuthenticated) {
- navigate("/chat");
- }
- }, [isAuthenticated, navigate]);
-
-
- return (
-
-
- {openReg && }
- {openLogin && }
-
- {/* Background Image */}
-
- {/* Left Section */}
-
-
- GENAI-BOT
-
-
-
-
-
-
-
-
-
-
-
- {/* Right Section */}
-
-
-
- Enter the Knowledge Zone
-
-
- {/*
- Sign in or register to upload your project and unlock smart code assistance.
- */}
-
-
- }
- onClick={() => setOpenLogin(true)}
- sx={{
- background: "linear-gradient(to right, #4a90e2, #a163e6)",
- color: "#fff",
- '&:hover': {
- background: "linear-gradient(to right, #3a78c2, #884fd1)",
- },
- }}
- >
- Login
-
- }
- onClick={() => setOpenReg(true)}
- sx={{
- borderColor: "#4a90e2",
- color: "#4a90e2",
- '&:hover': {
- backgroundColor: "#e3f2fd",
- borderColor: "#3a78c2",
- },
- }}
- >
- Register
-
-
-
-
-
- );
-}
diff --git a/src/api/feedback.py b/src/api/feedback.py
new file mode 100644
index 0000000..3795d53
--- /dev/null
+++ b/src/api/feedback.py
@@ -0,0 +1,63 @@
+import uuid
+import json
+from pathlib import Path
+from datetime import datetime
+from fastapi import APIRouter, Request, HTTPException, Depends
+
+# local imports
+from src.services.auth_service import get_current_user
+
+
+feedback_router = APIRouter()
+
+
+# Path to the feedback data file
+FEEDBACK_FILE = Path("chroma_db/feedback_data.jsonl")
+
+
+@feedback_router.post("/dislike")
+async def chat(request: Request, user=Depends(get_current_user)):
+ try:
+ body = await request.json()
+ email = user['email']
+ comment = body.get('comment')
+ user_message = body.get('userMessage')
+ bot_response = body.get('botResponse')
+
+ if not comment or not user_message or not bot_response:
+ return HTTPException(status_code=400, detail="Invalid feedback data")
+
+ feedback = {
+ "id": str(uuid.uuid4()),
+ "email": email,
+ "comment": comment,
+ "userMessage": user_message,
+ "botResponse": bot_response,
+ "createdAt": datetime.now().isoformat()
+ }
+
+ with FEEDBACK_FILE.open("a", encoding="utf-8") as f:
+ f.write(json.dumps(feedback) + "\n")
+
+ except Exception as e:
+ print(f"Error processing feedback: {e}")
+ raise HTTPException(status_code=500, detail="Internal Server Error")
+
+ return {"message": "Feedback received successfully"}
+
+
+
+@feedback_router.get("/")
+async def get_feedback(user=Depends(get_current_user)):
+ try:
+ feedback_list = []
+ with FEEDBACK_FILE.open("r", encoding="utf-8") as f:
+ for line in f:
+ feedback = json.loads(line)
+ feedback_list.append(feedback)
+
+ return feedback_list
+
+ except Exception as e:
+ print(f"Error retrieving feedback: {e}")
+ raise HTTPException(status_code=500, detail="Internal Server Error")
diff --git a/src/router.py b/src/router.py
index 4c18d50..5c0a2b6 100644
--- a/src/router.py
+++ b/src/router.py
@@ -4,6 +4,7 @@
from src.api.auth import auth_router
from src.api.chat import chat_router
from src.api.chunk import chunk_router
+from src.api.feedback import feedback_router
# router for the main API
@@ -18,3 +19,6 @@
# Chat routes
router.include_router(chat_router, prefix="/chat", tags=["chat"])
+
+# Feedback routes
+router.include_router(feedback_router, prefix="/feedback", tags=["feedback"])