Skip to content

Commit

Permalink
chat bot for everyone
Browse files Browse the repository at this point in the history
  • Loading branch information
dhrumilp12 committed Jun 11, 2024
1 parent 62eb7c7 commit c2cd2e7
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 68 deletions.
12 changes: 8 additions & 4 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState,useEffect } from 'react';
import React, { useState,useEffect, useContext } from 'react';
import { UserProvider } from './Components/userContext';
import { BrowserRouter as Router, Routes, Route, useLocation } from 'react-router-dom';
import ChatComponent from './Components/chatComponent'; // Ensure this path is correct
Expand All @@ -10,30 +10,34 @@ import ChatInterface from './Components/chatInterface';
import MoodLogging from './Components/moodLogging';
import MoodLogs from './Components/moodLogs';
import { CssBaseline, Box } from '@mui/material';
import { UserContext } from './Components/userContext';

function App() {
const { user } = useContext(UserContext);

useEffect(() => {
document.body.style.backgroundColor = '#f5f5f5';

}, []);

return (
<UserProvider>

<Layout>
<Routes>
<Route path="/" element={<ChatComponent />} />
<Route path="/" element={user?.userId ?<ChatComponent />:<ChatInterface />} />
<Route path="/chat" element={<ChatInterface />} />
<Route path="/auth" element={<AuthComponent />} />
<Route path="/user/profile/:userId" element={<UserProfile />} />
<Route path="/user/mood_logging" element={<MoodLogging />} />
<Route path="/user/mood_logs" element={<MoodLogs />} />
</Routes>
</Layout>
</ UserProvider>

);
}

function Layout({ children }) {
const { user } = useContext(UserContext);
const location = useLocation();
const noNavRoutes = ['/auth']; // List of routes that shouldn't show the navbar or sidebar
const showNav = !noNavRoutes.includes(location.pathname);
Expand Down
277 changes: 229 additions & 48 deletions client/src/Components/chatInterface.jsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,244 @@
import React, { useState, useContext, useCallback } from 'react';
import React, { useState, useContext,useCallback } from 'react';
import axios from 'axios';
import { Box, Card, CardContent, Typography, TextField, Button, List, ListItem, ListItemText, CircularProgress, Snackbar, Divider } from '@mui/material';
import MuiAlert from '@mui/material/Alert';
import SendIcon from '@mui/icons-material/Send';
import ExitToAppIcon from '@mui/icons-material/ExitToApp';
import PersonIcon from '@mui/icons-material/Person';
import { UserContext } from './userContext';
import Aria from '../Assets/Images/Aria.jpg'; // Adjust the path to where your logo is stored
import { Avatar } from '@mui/material';

const ChatInterface = () => {


const ChatComponent = () => {
const { user } = useContext(UserContext);
const userId = user?.userId;
const userId = user?.userId;
const [chatId, setChatId] = useState(0);
const [turnId, setTurnId] = useState(0);
const [input, setInput] = useState('');
const [messages, setMessages] = useState([]);

const sendMessage = async () => {
if (!input.trim()) return;
const [isLoading, setIsLoading] = useState(false);
const [open, setOpen] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState('');
const [snackbarSeverity, setSnackbarSeverity] = useState('info');

const body = JSON.stringify({
prompt: input,
turn_id: turnId
});

const response = await fetch(`/api/ai/mental_health/${userId}/${chatId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: body
});

const data = await response.json();
const handleSnackbarClose = (event, reason) => {
if (reason === 'clickaway') {
return;
}
setOpen(false);
};

const finalizeChat = useCallback(async () => {
if (chatId === null) return;
setIsLoading(true);
try {
const response = await fetch(`/api/ai/mental_health/finalize/${userId}/${chatId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});

const data = await response.json();
if (response.ok) {
setMessages([...messages, { message: input, sender: 'user' }, { message: data.message, sender: 'agent' }]);
setTurnId(prev => prev + 1);
setInput('');
setSnackbarMessage('Chat finalized successfully');
setSnackbarSeverity('success');
// Reset chat state to start a new chat
setChatId(null);
setTurnId(0);
setMessages([]);
// Optionally, fetch a new welcome message or reset other relevant states

} else {
console.error('Failed to send message:', data);
setSnackbarMessage('Failed to finalize chat');
setSnackbarSeverity('error');
}
};

// Handle input changes
const handleInputChange = useCallback((event) => {
setInput(event.target.value);
}, []);

return (
<div>
<h1>Welcome to Mental Health Companion</h1>
<div className="chat-container">
{messages.map((msg, index) => (
<div key={index} className={`message ${msg.sender}`}>
{msg.message}
</div>
))}
</div>
<input
type="text"
value={input}
onChange={handleInputChange}
placeholder="Type your message here..."
/>
<button onClick={sendMessage}>Send</button>
</div>
);
}
} catch (error) {
setSnackbarMessage('Error finalizing chat');
setSnackbarSeverity('error');
} finally {
setIsLoading(false);
setOpen(true);
}
}, [userId, chatId]);

const sendMessage = useCallback(async () => {
if (!input.trim()) return;
console.log(chatId);
setIsLoading(true);


try {
const body = JSON.stringify({
prompt: input,
turn_id: turnId
});
const response = await fetch(`/api/ai/mental_health/${userId}/${chatId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: body
});

const data = await response.json();
console.log(data);
if (response.ok) {
setMessages(prev => [...prev, { message: input, sender: 'user' }, { message: data, sender: 'agent' }]);
setTurnId(prev => prev + 1);
setInput('');
} else {
console.error('Failed to send message:', data);
}
}catch (error) {
console.error('Failed to send message:', error);
} finally {
setIsLoading(false);

}
}, [input, userId, chatId, turnId]);

// Handle input changes
const handleInputChange = useCallback((event) => {
setInput(event.target.value);
}, []);

export default ChatInterface;
return (
<>
<style>
{`
@keyframes blink {
0%, 100% { opacity: 0; }
50% { opacity: 1; }
}
`}
</style>
<Box sx={{ maxWidth: '100%', mx: 'auto', my: 2, display: 'flex', flexDirection: 'column', height: '91vh',borderRadius: 2, boxShadow: 1 }}>
<Card sx={{ display: 'flex', flexDirection: 'column', height: '100%',borderRadius: 2,boxShadow: 3 }}>
<CardContent sx={{ flexGrow: 1, overflow: 'auto',padding: 3 }}>
{messages.length === 0 && (
<Box sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
mt: -3,
mb: 2,
p: 2,
overflow: 'hidden', // Ensures nothing spills out of the box
maxWidth: '100%', // Limits the width to prevent overflow
maxHeight: '80%', // Adjusts the maximum height of the logo area
}}>
<img src={Aria} alt="App Logo" style={{
maxWidth: '100%',
maxHeight: '100%',
boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)',
width: 'auto', // Ensures the width automatically adjusts based on height
height: 'auto', // Auto height for proper scaling without specifying vh
objectFit: 'contain', // Ensures the image scales properly within its constraints
borderRadius: '50%' // Optional: Makes the image circular
}} />
</Box>

)}
<Box sx={{ display: 'flex', marginBottom: 2, marginTop:3}}>
<Avatar src={Aria} sx={{ width: 44, height: 44, marginRight: 2, }} alt="Aria" />
<Typography variant="h4" component="h1" gutterBottom>
Welcome to Mental Health Companion
</Typography>
</Box>


<List sx={{ maxHeight: '100%', overflow: 'auto' }}>
{messages.map((msg, index) => (
<ListItem key={index}sx={{
display: 'flex',
flexDirection: 'column',
alignItems: msg.sender === 'user' ? 'flex-end' : 'flex-start',
//backgroundColor: msg.sender === 'user' ? 'primary.light' : 'grey.100', // Adjust colors here
borderRadius: 2, // Optional: Adds rounded corners
mb: 0.5, // Margin bottom for spacing between messages
p: 1 // Padding inside each list item
}}>
<Box sx={{
display: 'flex',
alignItems: 'center',
color: msg.sender === 'user' ? 'common.white' : 'text.primary',
borderRadius: '16px',


}}>

{msg.sender === 'agent' && (
<Avatar src={Aria} sx={{ width: 36, height: 36, mr: 1 }} alt="Aria" />
)}


<ListItemText primary={msg.message} primaryTypographyProps={{

sx: {
color: msg.sender === 'user' ? 'common.white' : 'text.primary',
//textAlign: msg.sender === 'user' ? 'right' : 'left',
bgcolor: msg.sender === 'user' ? 'primary.main' : 'grey.200', // You can adjust the background color here
borderRadius: '16px', // Adds rounded corners to the text
px: 2, // padding left and right within the text
py: 1, // padding top and bottom within the text
display: 'inline-block', // Ensures the background color wraps the text only
}

}} />
{msg.sender === 'user' && (
<Avatar sx={{ width: 36, height: 36, ml: 1 }}>
<PersonIcon />
</Avatar>
)}
</Box>
</ListItem>
))}
</List>
</CardContent>
<Divider />
<Box sx={{ p: 2, pb: 1, display: 'flex', alignItems: 'center',bgcolor: 'background.paper' }}>
<TextField
fullWidth
variant="outlined"
placeholder="Type your message here..."
value={input}
onChange={handleInputChange}
disabled={isLoading}
sx={{ mr: 1, flexGrow: 1 }}
/>
{isLoading ? <CircularProgress size={24} /> : (
<Button variant="contained" color="primary" onClick={sendMessage} disabled={isLoading || !input.trim()} endIcon={<SendIcon />}>
Send
</Button>
)}
</Box>
<Button
variant="outlined"
color="error"
startIcon={<ExitToAppIcon />}
onClick={finalizeChat}
disabled={isLoading}
sx={{mt: 1,backgroundColor: theme => theme.palette.error.light + '33', // Adds an alpha value for transparency, making it lighter

'&:hover': {
color: 'common.white',// White text for better contrast
backgroundColor: theme => theme.palette.error.light, // Slightly darker on hover but still lighter than default
} }
}
>
{isLoading ? <CircularProgress color="inherit" /> : 'End Chat'}
</Button>
</Card>
<Snackbar open={open} autoHideDuration={6000} onClose={handleSnackbarClose}>
<MuiAlert elevation={6} variant="filled" onClose={handleSnackbarClose} severity={snackbarSeverity}>
{snackbarMessage}
</MuiAlert>
</Snackbar>
</Box>
</>
);
};


export default ChatComponent;
2 changes: 1 addition & 1 deletion client/src/Components/userContext.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { createContext, useState, useCallback } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
export const UserContext = createContext(null);
export const UserContext = createContext({ user: null });

export const UserProvider = ({ children }) => {
const [user, setUser] = useState(null);
Expand Down
2 changes: 1 addition & 1 deletion client/src/Components/userProfile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const theme = createTheme({
});

const StyledForm = styled(Paper)(({ theme }) => ({
marginTop: theme.spacing(10),
marginTop: theme.spacing(4),
padding: theme.spacing(4),
display: 'flex',
flexDirection: 'column',
Expand Down
3 changes: 3 additions & 0 deletions client/src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import { BrowserRouter } from 'react-router-dom';
import { UserProvider } from './Components/userContext';

ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<BrowserRouter>
<UserProvider>
<App />
</UserProvider>
</BrowserRouter>
</React.StrictMode>,
)
Loading

0 comments on commit c2cd2e7

Please sign in to comment.