please fix my function for generating an ai summary using chatlogs from realtime database, when i try to generate the summary it says "error generating summary". Could you please fix and refine my code. also please make the ai summary to generate on the frontend, when ther user's profile is selected.

Frontend:

import React, { useState, useEffect, useContext } from 'react';
import { useParams } from 'react-router-dom';
import axios from 'axios';
import {
  Typography,
  Paper,
  Grid,
  CircularProgress, // For loading indicator
  Button, // Add Button for triggering AI summary
} from '@mui/material';
import { styled } from '@mui/system';
import { PieChart, Pie, Cell, ResponsiveContainer } from 'recharts';
import { AuthContext } from '../AuthContext'; // Import AuthContext for authentication
import { signOut } from 'firebase/auth';
import { auth } from '../firebase'; // Import your Firebase auth instance

const Container = styled(Paper)(({ theme }) => ({
  padding: theme.spacing(4),
  margin: theme.spacing(4),
}));

function UserPage() {
  const { id } = useParams(); // Get the user ID from the route parameters
  const [userData, setUserData] = useState(null);
  const { currentUser } = useContext(AuthContext); // Access currentUser from context
  const [error, setError] = useState(null); // Error state
  const [isLoading, setIsLoading] = useState(true); // Loading state
  const [generatingSummary, setGeneratingSummary] = useState(false); // State for AI summary generation

  useEffect(() => {
    // Function to fetch user data
    const fetchUserData = async () => {
      if (!currentUser) {
        setError('User is not authenticated.');
        setIsLoading(false);
        return;
      }

      try {
        const token = await currentUser.getIdToken(true); // Force token refresh
        const response = await axios.get(
          `https://us-central1-mind-gardener.cloudfunctions.net/api/users/${id}`,
          {
            headers: {
              Authorization: `Bearer ${token}`,
            },
          }
        );
        setUserData(response.data);
      } catch (err) {
        if (err.response) {
          if (err.response.status === 403) {
            setError('Access denied. You do not have permission to view this user.');
          } else if (err.response.status === 401) {
            setError('Unauthorized. Please log in again.');
          } else {
            setError('An error occurred while fetching user data.');
          }
        } else {
          setError('Failed to fetch user data.');
        }
      } finally {
        setIsLoading(false);
      }
    };

    fetchUserData();
  }, [id, currentUser]);

  const handleGenerateSummary = async () => {
    setGeneratingSummary(true);
    setError(null);

    try {
      const token = await currentUser.getIdToken(true); // Get fresh token
      const response = await axios.post(
        `https://us-central1-mind-gardener.cloudfunctions.net/api/generate-summary`,
        { userId: id },
        {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        }
      );
      setUserData((prevState) => ({
        ...prevState,
        summary: response.data.summary, // Update the summary field
      }));
    } catch (err) {
      setError('Error generating AI summary.');
    } finally {
      setGeneratingSummary(false);
    }
  };

  const handleLogout = () => {
    signOut(auth)
      .then(() => {
        console.log('User signed out successfully.');
      })
      .catch((err) => {
        console.error('Error during sign out:', err);
      });
  };

  if (isLoading) {
    return (
      <Typography variant="h6" align="center" sx={{ mt: 4 }}>
        <CircularProgress />
      </Typography>
    );
  }

  if (error) {
    return (
      <Typography variant="h6" align="center" color="error" sx={{ mt: 4 }}>
        {error}
      </Typography>
    );
  }

  if (!userData) {
    return (
      <Typography variant="h6" align="center" sx={{ mt: 4 }}>
        No user data available.
      </Typography>
    );
  }

  const data = [
    { name: 'Positive', value: userData.sentimentScore },
    { name: 'Negative', value: 100 - userData.sentimentScore },
  ];

  const COLORS = ['#0088FE', '#FF8042'];

  return (
    <Container elevation={3}>
      <Typography variant="h4">User ID: {userData.id}</Typography>
      <Typography variant="h6" gutterBottom>
        Detailed User Information
      </Typography>

      <Grid container spacing={4}>
        <Grid item xs={12} md={8}>
          <Typography variant="subtitle1" gutterBottom>
            AI-Generated Summary:
          </Typography>

          {/* Button to generate summary */}
          <Button
            variant="contained"
            color="primary"
            onClick={handleGenerateSummary}
            disabled={generatingSummary}
          >
            {generatingSummary ? 'Generating...' : 'Generate AI Summary'}
          </Button>

          {/* Display generated summary */}
          {userData.summary ? (
            <Typography variant="body1" sx={{ mt: 2 }}>
              {userData.summary}
            </Typography>
          ) : (
            <Typography variant="body1" sx={{ mt: 2 }}>
              {generatingSummary
                ? 'AI summary is being generated...'
                : 'Click the button to generate AI summary.'}
            </Typography>
          )}

          {/* Display chat logs or other user-specific data here */}
          <Typography variant="subtitle1" gutterBottom mt={4}>
            Chat Logs:
          </Typography>
          {Array.isArray(userData.chatLogs) && userData.chatLogs.length > 0 ? (
            userData.chatLogs.map((message, index) => (
              <Typography key={index} variant="body2">
                {message.sender === "user" ? "You" : "Bot"}: {message.text}
              </Typography>
            ))
          ) : (
            <Typography variant="body2">No chat logs available.</Typography>
          )}
        </Grid>
        <Grid item xs={12} md={4}>
          <ResponsiveContainer width="100%" height={200}>
            <PieChart>
              <Pie
                data={data}
                dataKey="value"
                innerRadius={60}
                outerRadius={80}
                fill="#8884d8"
                paddingAngle={5}
                startAngle={90}
                endAngle={-270}
              >
                {data.map((entry, index) => (
                  <Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
                ))}
              </Pie>
            </PieChart>
          </ResponsiveContainer>
          <Typography variant="body1" align="center">
            Sentiment Score: {userData.sentimentScore}%
          </Typography>
        </Grid>
      </Grid>
    </Container>
  );
}

export default UserPage;


Backend:

/* eslint-disable require-jsdoc */
/* eslint-disable max-len */

// Import necessary modules
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const express = require("express");
const cors = require("cors"); // For chatWithOpenAI function

// Access configuration variables
const databaseURL = functions.config().fbrt.database_url;
const openaiApiKey = functions.config().openai.apikey;

// Initialize Firebase Admin SDK with databaseURL
admin.initializeApp({
  credential: admin.credential.applicationDefault(),
  databaseURL: databaseURL,
});

// Create an Express app
const app = express();
app.use(cors({origin: true})); // Enable CORS for all origins
app.use(express.json()); // Parse JSON bodies

// Middleware to verify Firebase Auth token and check for 'psychologist' role
async function authenticate(req, res, next) {
  const authHeader = req.headers.authorization;

  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    res.status(401).send("Unauthorized: Missing or invalid token");
    return;
  }

  const idToken = authHeader.split("Bearer ")[1];

  try {
    const decodedToken = await admin.auth().verifyIdToken(idToken);

    // Check if the user has the 'psychologist' role
    if (decodedToken.role !== "psychologist") {
      res.status(403).send("Forbidden: Insufficient permissions");
      return;
    }

    req.user = decodedToken;
    next();
  } catch (error) {
    console.error("Error verifying Firebase ID token:", error);
    res.status(401).send("Unauthorized");
  }
}

// Route to fetch users data
app.get("/users", authenticate, async (req, res) => {
  try {
    // Fetch users data from Realtime Database
    const usersRef = admin.database().ref("users");
    const snapshot = await usersRef.once("value");
    const usersData = snapshot.val();

    res.status(200).json(usersData || {});
  } catch (error) {
    console.error("Error fetching users data:", error);
    res.status(500).send("Internal Server Error");
  }
});

// Route to fetch user activity logs
app.get("/activityLogs", authenticate, async (req, res) => {
  try {
    // Fetch activity logs from Realtime Database
    const logsRef = admin.database().ref("activityLogs");
    const snapshot = await logsRef.once("value");
    const logsData = snapshot.val();

    res.status(200).json(logsData || {});
  } catch (error) {
    console.error("Error fetching activity logs:", error);
    res.status(500).send("Internal Server Error");
  }
});


// Cloud Function for chatWithOpenAI
exports.chatWithOpenAI = functions.https.onRequest(async (req, res) => {
  // Set CORS headers to allow cross-origin requests
  res.set("Access-Control-Allow-Origin", "*");
  res.set("Access-Control-Allow-Headers", "Content-Type");

  // Handle preflight request (for CORS)
  if (req.method === "OPTIONS") {
    res.status(204).send("");
    return;
  }

  // Ensure only POST requests are accepted
  if (req.method !== "POST") {
    res.status(405).send({error: "Only POST requests are accepted"});
    return;
  }

  try {
    const {conversationHistory} = req.body;
    console.log("Received conversationHistory:", conversationHistory);

    // Validate conversationHistory
    if (!Array.isArray(conversationHistory)) {
      res.status(400).send({error: "\"conversationHistory\" must be an array"});
      return;
    }

    // Use OpenAI API key from environment variables
    const apiKey = openaiApiKey;

    if (!apiKey) {
      console.error("OpenAI API key is not configured.");
      res.status(500).send({error: "OpenAI API key is not configured"});
      return;
    }

    // System prompt to guide the assistant
    const systemPrompt = `You are a compassionate and skilled mental health assistant trained in Cognitive Behavioral Therapy (CBT) and mindfulness practices. Your mission is to support users in identifying, restructuring, and challenging negative thoughts through a natural, private conversation, similar to talking with a trusted friend.

**Guidelines:**

1. **Warm and Empathetic Tone:** Maintain a friendly, understanding, and non-judgmental manner. Ensure your responses are brief, clear, and resemble everyday human conversation.

2. **CBT Techniques:**
   - **Identify Negative Thoughts:** Help users recognize and articulate their negative thoughts.
   - **Explore Underlying Beliefs:** Encourage users to delve deeper into the beliefs driving their negative thoughts.
   - **Challenge and Restructure:** Assist users in examining the validity of their thoughts by considering real-life evidence and alternative perspectives.

3. **Mindfulness Integration:**
   - **Present Moment Awareness:** Guide users to focus on the here and now when appropriate.
   - **Breathing Exercises:** Suggest simple mindfulness practices, such as deep breathing, to help users center themselves.

4. **Step-by-Step Support:**
   - **Progressive Solutions:** Introduce coping strategies and solutions gradually to avoid overwhelming the user.
   - **Actionable Steps:** Break down information into manageable, practical actions that users can implement.

5. **Encourage Self-Reflection:**
   - **Open-Ended Questions:** Pose questions that prompt users to reflect on their feelings and thoughts more deeply.
   - **Active Listening:** Acknowledge user feelings and validate their experiences to foster a sense of understanding.

6. **Concise Responses:**
   - **Avoid Lengthy Paragraphs:** Keep replies short and to the point to facilitate a smooth and engaging conversation.
   - **Clear and Direct Language:** Use straightforward language to ensure clarity and ease of understanding.

7. **Safety and Boundaries:**
   - **Recognize Distress Signals:** Be attentive to signs of severe distress or mentions of self-harm.
   - **Encourage Professional Help:** Prompt users to seek professional assistance when necessary, ensuring their safety is prioritized.

**Example Interaction:**

*User:* I've been feeling really overwhelmed and can't stop thinking about my failures.

*Assistant:* I'm sorry you're feeling this way. Can you share more about these thoughts of failure?

*User:* I keep thinking I messed up that important presentation at work.

*Assistant:* That sounds stressful. What evidence do you have that supports or contradicts this thought?

*User:* Well, my manager actually praised my effort afterwards.

*Assistant:* That's a positive sign! How can we view the presentation more balanced, considering both the feedback and your feelings?

*User:* Maybe I focused too much on one part and overlooked others, but overall it was well-received.

*Assistant:* It sounds like you did better than you initially thought. How can you remind yourself of this next time you start feeling overwhelmed by negative thoughts?

*User:* I could write down the positive feedback and review it when I feel down.

*Assistant:* That’s a great idea. Keeping a list of positive feedback can help you stay balanced. Would you like to discuss ways to implement this?

---

\n\n`;

    // Function to summarize conversation if it exceeds a certain number of turns
    const summarizeConversation = async (messages) => {
      const summaryPrompt = `Summarize the following conversation into a concise summary (3-5 sentences) that captures the main points and context:

${messages
      .map(
          (turn) =>
            `${turn.role === "user" ? "User" : "Assistant"}: ${turn.content}`,
      )
      .join("\n")}

Summary:`;

      const summaryPayload = {
        model: "gpt-4",
        messages: [
          {
            role: "system",
            content: "You are an assistant that summarizes conversations concisely.",
          },
          {role: "user", content: summaryPrompt},
        ],
        max_tokens: 150,
        temperature: 0.5,
      };

      const summaryResponse = await fetch("https://api.openai.com/v1/chat/completions", {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${apiKey}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(summaryPayload),
      });

      if (!summaryResponse.ok) {
        const errorData = await summaryResponse.json();
        console.error("Error summarizing conversation:", JSON.stringify(errorData, null, 2));
        throw new Error("Failed to summarize conversation");
      }

      const summaryData = await summaryResponse.json();
      return summaryData.choices[0].message.content.trim();
    };

    // Transform conversationHistory into OpenAI's message format
    let messages = [{role: "system", content: systemPrompt}];

    if (conversationHistory.length > 0) {
      conversationHistory.forEach((turn) => {
        if (turn.sender === "user") {
          messages.push({role: "user", content: turn.text});
        } else if (turn.sender === "bot") {
          messages.push({role: "assistant", content: turn.text});
        }
      });
    }

    // Optionally summarize if conversation is too long
    const MAX_TURNS = 40; // Adjust based on token limits and requirements
    if (messages.length > MAX_TURNS) {
      // Extract the last MAX_TURNS messages
      const recentMessages = messages.slice(-MAX_TURNS);
      const summary = await summarizeConversation(recentMessages);
      // Reset messages with system prompt and summary
      messages = [
        {role: "system", content: systemPrompt},
        {role: "user", content: `Summary of previous conversation: ${summary}`},
      ];
    }

    console.log("Constructed messages array:", messages);

    // Create the payload for OpenAI API
    const payload = {
      model: "gpt-4",
      messages: messages,
      max_tokens: 150, // Limit the length of the response
      temperature: 0.7, // Control creativity
      top_p: 0.9, // Sampling method for diverse responses
      n: 1, // Number of responses to generate
      stop: null, // Let the model decide when to stop
    };

    // OpenAI API endpoint
    const OPENAI_ENDPOINT = "https://api.openai.com/v1/chat/completions";

    // Send the request to OpenAI
    const response = await fetch(OPENAI_ENDPOINT, {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${apiKey}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(payload),
    });

    if (!response.ok) {
      const errorData = await response.json();
      console.error("Error from OpenAI API:", JSON.stringify(errorData, null, 2));
      res.status(response.status).send({error: "Error from OpenAI API", details: errorData});
      return;
    }

    // Parse the response from OpenAI
    const data = await response.json();
    console.log("Data from OpenAI API:", JSON.stringify(data, null, 2));

    // Extract assistant's reply
    const assistantReply = data.choices[0].message.content.trim();

    // Send the assistant's reply back to the client
    res.status(200).send({reply: assistantReply});
  } catch (error) {
    console.error("Error in Cloud Function:", error);
    res.status(500).send({error: "Internal server error"});
  }
});

// Helper function to summarize chat logs usgi the GPT api
async function summarizeChatLogs(chatLogs) {
  const systemPrompt2 = `Summarize the following conversation into a concise summary (3-5 sentences) that captures the main points and context:\n\n`;

  const messagesForSummary = chatLogs.map((log) => {
    return `${log.sender === "user" ? "User" : "Assistant"}: ${log.text}`;
  }).join("\n");

  const summaryPrompt = systemPrompt2 + messagesForSummary + "\n\nSummary:";

  const summaryPayload = {
    model: "gpt-4-turbo",
    messages: [
      {role: "system", content: "You are an assistant that summarizes conversations concisely."},
      {role: "user", content: summaryPrompt},
    ],
    max_tokens: 150,
    temperature: 0.5,
  };

  try {
    const response2 = await fetch("https://api.openai.com/v1/chat/completions", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${openaiApiKey}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(summaryPayload),
    });
    if (!response2.ok) {
      throw new Error("Failed to summarize chat logs");
    }

    const summaryData = await response2.json();
    return summaryData.choices[0].message.content.trim();
  } catch (error) {
    console.error("Error summarizing chat logs:", error);
    throw error;
  }
}

// Route to fetch a specific user's data
app.get("/users/:id", authenticate, async (req, res) => {
  const userId = req.params.id;
  const {summarize} = req.query; // Optional query param to trigger summarization

  try {
    // Fetch user-specific chat sessions from Realtime Database
    const sessionsSnapshot = await admin
        .database()
        .ref(`chats/${userId}/sessions`)
        .once("value");
    const sessionsData = sessionsSnapshot.val();

    if (!sessionsData) {
      res.status(404).send("No chat sessions found for this user.");
      return;
    }

    // Initialize an empty array to hold all chat messages
    let chatLogs = [];

    // Iterate through each session
    Object.values(sessionsData).forEach((session) => {
      if (session.messages) {
        // If messages are stored as objects with numeric keys, convert them to an array
        const messagesArray = Object.values(session.messages);
        chatLogs = chatLogs.concat(messagesArray);
      }
    });

    if (summarize === "true") {
      // Call GPT API for summarization
      const summary = await summarizeChatLogs(chatLogs);
      res.status(200).json({summary});
    } else {
      // Respond with the aggregated chatLogs without summarizing
      res.status(200).json({
        id: userId,
        chatLogs,
      });
    }
  } catch (error) {
    console.error("Error fetching user chat data:", error);
    res.status(500).send("Internal Server Error");
  }
});

// Export the Express app as a Firebase Cloud Function
exports.api = functions.https.onRequest(app);