Skip to content

Conversation

@i-am-that-guy
Copy link
Member

@i-am-that-guy i-am-that-guy commented Jan 12, 2026

Summary by CodeRabbit

  • New Features

    • Added Cortex AI chatbot: floating icon, interactive chat widget, typing indicator, Enter-to-send and RUN button.
    • Chatbot visible on DSA question and interview pages; context-aware replies seeded from current question or interview and conversation history.
    • Theme support: light/dark styling for chatbot UI.
  • Chores

    • Backend and environment updated to enable AI integration.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 12, 2026

📝 Walkthrough

Walkthrough

Adds an AI-powered chatbot: backend Gemini integration, RAG context fetching, prompt builder, chat API and route; frontend chatbot UI, visibility hook, context propagation from DSA/interview pages, and related styles and dependencies.

Changes

Cohort / File(s) Summary
Backend config & deps
backend/.env.example, backend/package.json
Added GEMINI_API_KEY env var; added deps @google/generative-ai and node-fetch.
Backend AI init
backend/src/services/ai.ts
Initialized Gemini client and exported geminiModel.
Backend RAG retrieval
backend/src/services/retrival.ts
New fetchRAGContext(questionContext?) fetching DSA/interview data with case branches and error fallback.
Backend prompt builder
backend/src/ai/chatBrain.ts
New buildPrompt({...}) that formats history and assembles role-based prompts across 5 questionContext cases.
Backend chat API
backend/src/controllers/chatController.ts, backend/src/routes/chat.route.ts, backend/src/app.ts
New POST /chat route and controller: fetches RAG, builds prompt, calls Gemini, returns reply; mounted router and ensured JSON parsing.
Frontend chatbot UI & styles
frontend/src/components/chatbot/ChatbotWrapper.jsx, frontend/src/components/chatbot/ChatbotIcon.jsx, frontend/src/App.css
New floating chatbot icon and wrapper UI (messages, typing indicator, markdown, send flow); added theming and typing animation CSS.
Frontend integration & visibility
frontend/src/App.jsx, frontend/src/hooks/useChatbotVisibility.js, frontend/package.json
Added ChatbotContainer with visibility hook and currentQuestionContext state; bumped framer-motion.
Frontend context utils & propagation
frontend/src/utils/buildQuestionContext.js, frontend/src/components/dsa/questions/QuestionView.jsx, frontend/src/pages/DsaDashboard.jsx
New buildQuestionContext; QuestionView and DsaDashboard now propagate setCurrentQuestionContext on interactions.
Frontend interview flow updates
frontend/src/components/interview/InterviewExperienceItem.jsx, frontend/src/pages/InterviewExp.jsx
Interview items accept setCurrentQuestionContext, expand with Markdown rendering, and pages set topic/collection contexts.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Frontend as Frontend App
    participant ChatUI as ChatbotWrapper
    participant Backend as /chat API
    participant RAG as RAG Service
    participant Gemini as Gemini Model

    User->>ChatUI: Open / Send message
    ChatUI->>Frontend: Read path, history, questionContext
    ChatUI->>Backend: POST /chat { path, userAnswer, questionContext, history }
    Backend->>RAG: fetchRAGContext(questionContext)
    alt DSA question or topic
        RAG->>Backend: return DSA context (question/topicOverview/relatedQuestions)
    else Interview experience or collection
        RAG->>Backend: return interview data (current/collection/metadata)
    end
    Backend->>Backend: buildPrompt(path, ragData, userAnswer, questionContext, history)
    Backend->>Gemini: start chat & send prompt
    Gemini-->>Backend: AI response
    Backend-->>ChatUI: { reply }
    ChatUI->>User: show typing indicator then display reply
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • Harish-Naruto
  • Shashwati12
  • shrutiiiyet

Poem

🐰 A little rabbit hops with glee and says hello,
Gemini whispers answers in a soft, bright glow.
Context blossoms, prompts take flight,
Chat bubbles dance into the night —
Code and carrots, quick and thorough! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Integrated context-aware chatbot' directly and accurately summarizes the main change: adding a context-aware AI chatbot system (Cortex) across the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jan 12, 2026

Deploying coc-members with  Cloudflare Pages  Cloudflare Pages

Latest commit: ce6cfd3
Status: ✅  Deploy successful!
Preview URL: https://07f0164c.coc-members.pages.dev
Branch Preview URL: https://chatbot.coc-members.pages.dev

View logs

@i-am-that-guy i-am-that-guy marked this pull request as ready for review January 12, 2026 14:23
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

🤖 Fix all issues with AI agents
In @backend/src/ai/chatBrain.ts:
- Around line 107-125: The INTERVIEW_EXPERIENCE branch omits conversation
history which other branches include; update the prompt built in the if
(questionContext?.type === "INTERVIEW_EXPERIENCE") block to inject the formatted
history via formatHistory(history) (e.g., include "Conversation History:
${formatHistory(history)}" or similar) alongside baseRole, interview, and Full
Experience so the model retains prior messages; reference symbols:
questionContext, ragData/content, interview, baseRole, userAnswer, and
formatHistory(history).
- Around line 56-75: The prompt builds `context` using `ragData.question` and
`ragData.concept` directly which can produce literal "undefined" if `ragData` is
present but missing those properties; update the `context` construction in
chatBrain.ts (the const named `context` inside the `if (questionContext?.type
=== "DSA" && questionContext.questionId)` block) to safely access properties and
fall back to explicit defaults (e.g., using nullish coalescing or conditional
checks to replace missing `question` or `concept` with a clear placeholder like
"No details available" or "N/A") so the prompt never contains "undefined".

In @backend/src/app.ts:
- Around line 36-39: The middleware stack registers JSON body parsing twice
(app.use(json()) and app.use(express.json())), which is redundant; remove one
invocation to avoid duplicate parsing — delete the body-parser json() call (the
app.use(json()) line) and keep app.use(express.json()) (or vice versa) so only a
single JSON body parser is registered before routes like app.use("/chat",
chatRoutes).

In @backend/src/controllers/chatController.ts:
- Around line 50-53: The response currently exposes internal error details by
returning err.message in the res.status(500).json response; instead, remove
err.message from the client payload and replace it with a generic error string
(e.g., "Internal server error" or the existing helpful user-facing message), and
ensure the full error is logged server-side (using the existing logger or
console.error) inside the same catch block where res.status(500).json is called
(locate the res.status(500).json(...) and the err variable in chatController's
error handling code).

In @backend/src/services/ai.ts:
- Around line 3-7: Add a runtime check for process.env.GEMINI_API_KEY before
constructing GoogleGenerativeAI: verify the variable is defined and non-empty,
and if not, throw an Error (or call process.exit with a clear message) so the
app fails fast with a descriptive message; then pass the validated key into the
GoogleGenerativeAI constructor used to create genAI and geminiModel to avoid
relying on the non-null assertion.

In @backend/src/services/retrival.ts:
- Around line 22-27: In the INTERVIEW_COLLECTION branch where you fetch
interviews using questionContext.interviewIds, add error handling around the
fetch: after calling fetch(...) check res.ok before calling res.json(); if
!res.ok handle the error (e.g., log the response status/text and throw or return
an empty array) to avoid calling res.json() on a failed response and to ensure a
predictable return from the function; update the logic around the fetch in
retrival.ts (the block using questionContext.type === "INTERVIEW_COLLECTION" and
questionContext.interviewIds) to perform this check and handle non-OK responses
gracefully.

In @frontend/package.json:
- Around line 31-34: The package.json lists unused dependencies "framer-motion"
and "motion"; remove both entries from the dependencies block and update any
lockfile (run npm/yarn/pnpm install) to ensure they are removed from the
lockfile and node_modules; also run a repo-wide search for imports of
framer-motion and motion to confirm nothing is relying on them and update any
build or bundle configs if they referenced these package names.

In @frontend/src/components/chatbot/ChatbotIcon.jsx:
- Around line 75-93: The button lacks an accessible name; update the
motion.button (the clickable element that calls onClick and wraps
CodingCortexIcon) to include an aria-label describing its action (e.g., "Open
chat" or "Toggle chatbot") and, if the button toggles state, add
aria-pressed={isOpen} (or appropriate boolean state) to reflect its state for
screen readers; also add a title attribute matching the aria-label to help
sighted keyboard users and ensure the icon component (CodingCortexIcon) does not
interfere with the accessible name (remove role="img" or provide aria-hidden if
necessary).
- Line 1: Remove the Next.js-specific "use client" directive from the
ChatbotIcon.jsx module: open the ChatbotIcon.jsx component and delete the
top-line "use client" string so the file is a normal Vite/React module; no other
changes are required.

In @frontend/src/components/chatbot/ChatbotWrapper.jsx:
- Around line 119-143: The fetch block does not check HTTP status and may parse
an error body then access data.reply; after awaiting
fetch(`${import.meta.env.VITE_API_URL}/chat`, ...) check response.ok and if
false parse the response body for an error message (or throw a new Error(`HTTP
${response.status}`)) before using data; update the error path to call
setMessages([...updatedMessages, { from: "bot", text: errorMessage }]) and
ensure setIsTyping(false) is invoked in both error and non-error flows so you
never read data.reply when response.ok is false; adjust the try/catch to surface
server error text (from parsed body) or a clear fallback message.

In @frontend/src/components/dsa/questions/QuestionView.jsx:
- Around line 143-151: The onClick handler calls setCurrentQuestionContext
without checking it may be undefined; update the handler around
buildQuestionContext (using buildQuestionContext, selectedTopic, question) to
only call setCurrentQuestionContext if it exists (e.g., check truthiness or use
optional chaining) so the call is guarded and avoids a runtime error when the
prop is not provided.

In @frontend/src/components/interview/InterviewExperienceItem.jsx:
- Around line 67-86: The click handler currently calls handleCardClick() (which
toggles isExpanded) and then also calls setIsExpanded(!isExpanded), causing a
double-toggle that cancels the change; remove the explicit
setIsExpanded(!isExpanded) from the onClick block and ensure handleCardClick is
the single source of truth for toggling and setting
window.__CURRENT_QUESTION_CONTEXT__; also update onKeyDown to call
handleCardClick() (after e.preventDefault()) instead of directly toggling state
so keyboard activation updates the context and mirrors click behavior.

In @frontend/src/pages/DsaDashboard.jsx:
- Around line 19-24: The call to setCurrentQuestionContext inside DsaDashboard
can throw if the prop is not provided; add a defensive guard or default no-op:
ensure DsaDashboard checks that setCurrentQuestionContext is a function before
calling it (or provide a default prop/no-op function) and fix the indentation of
the setCurrentQuestionContext block so it matches surrounding code; reference
the setCurrentQuestionContext invocation in DsaDashboard to locate and update
the code.

In @frontend/src/pages/InterviewExp.jsx:
- Around line 22-32: The effect runs on every render because interviewsArray is
recreated each render; memoize it (e.g., useMemo(() => interviews.map(i =>
i.id), [interviews]) or compute a memoized interviewIds array) and then replace
the dependency interviewsArray with that memoized value (or use interviews
directly) in the useEffect that calls setCurrentQuestionContext so the effect
only fires when the underlying interviews actually change.
🧹 Nitpick comments (18)
backend/package.json (1)

63-63: Consider if node-fetch is necessary.

Since the project uses Bun (bun src/server.ts in scripts), native fetch is already available globally. The node-fetch dependency may be unnecessary unless there's a specific need for Node.js compatibility.

backend/src/controllers/chatController.ts (3)

6-13: Add input validation for request body fields.

The controller destructures fields from req.body without validating their presence or types. If userAnswer is missing or empty, buildPrompt will receive undefined, potentially causing unexpected behavior or prompt injection issues.

Proposed validation
 export async function chatController(req: Request, res: Response) {
   try {
     const {
       path,
       userAnswer,
       questionContext,
       history,
     } = req.body;
 
+    if (!userAnswer || typeof userAnswer !== 'string') {
+      return res.status(400).json({ reply: "Invalid or missing user message." });
+    }

18-23: Remove or reduce verbose debug logging in production.

Logging ragData.content previews could expose sensitive interview data or PII in production logs. Consider using a debug flag or proper log levels.

Suggested approach
     const ragData = await fetchRAGContext(questionContext);
-    if (ragData) {
-      console.log("✅ DATA FOUND. Company:", ragData.company || "N/A");
-      console.log("📝 CONTENT PREVIEW:", ragData.content?.substring(0, 50) + "...");
-    } else {
-      console.log("🔍 DATA TO AI: No record found.");
-    }
+    // Use structured logging with appropriate log levels in production
+    if (process.env.NODE_ENV === 'development' && ragData) {
+      console.debug("RAG data retrieved for company:", ragData.company || "N/A");
+    }

33-39: Add timeout handling for the Gemini API call to prevent indefinite hangs.

The chat.sendMessage(prompt) call at line 38 lacks timeout protection. If the Gemini API becomes slow or unresponsive, the request will hang indefinitely and exhaust server resources. Wrap the call using Promise.race() with a timeout, or use AbortController if the SDK supports it:

Example implementation
const timeoutMs = 30000; // 30 second timeout
const result = await Promise.race([
  chat.sendMessage(prompt),
  new Promise((_, reject) => 
    setTimeout(() => reject(new Error('Gemini API timeout')), timeoutMs)
  )
]);
backend/src/services/retrival.ts (2)

3-4: Consider adding TypeScript types for better type safety.

The function uses any throughout, which reduces type safety. Defining interfaces for questionContext and return types would improve maintainability and catch errors at compile time.

Example type definitions
interface QuestionContext {
  type: 'DSA' | 'INTERVIEW_COLLECTION' | 'INTERVIEW_EXPERIENCE';
  questionId?: string;
  topicId?: string;
  isTopicOnly?: boolean;
  interviewIds?: string[];
  id?: string;
}

export async function fetchRAGContext(questionContext?: QuestionContext): Promise<unknown | null> {

1-1: Filename typo: "retrival" should be "retrieval".

The filename retrival.ts is misspelled. Consider renaming to retrieval.ts for clarity.

backend/src/ai/chatBrain.ts (2)

104-106: Remove duplicate comment lines.

Lines 104-106 have duplicate/redundant comments for CASE 4.

Proposed cleanup
-  // --- CASE 4: SINGLE INTERVIEW EXPERIENCE ---
-  // chatBrain.ts update for CASE 4
 // --- CASE 4: SINGLE INTERVIEW EXPERIENCE ---
 if (questionContext?.type === "INTERVIEW_EXPERIENCE") {

6-18: Remove the unused path parameter from the function signature.

The path parameter is declared but never referenced in any of the function's cases or logic paths. If it's intended to provide context about the user's current page to the AI, integrate it into one of the prompts; otherwise, remove it to keep the function signature clean.

frontend/src/hooks/useChatbotVisibility.js (1)

8-14: Redundant path entries in visiblePaths.

Since you're using startsWith() for matching, /dsa/topics is already covered by /dsa, and /interview/preparation is already covered by /interview. You can simplify the array.

♻️ Suggested simplification
   const visiblePaths = [
     '/dsa',
     '/interview',
-    '/dsa/topics', 
-    '/interview/preparation', 
-    
   ];
frontend/src/App.css (2)

1-42: Consider removing commented-out code.

This block of commented-out code appears to be legacy/unused. Removing it would improve file clarity. Version control preserves history if needed.


62-68: Non-English comment.

The comment on line 65 is in Hindi. For consistency and broader team accessibility, consider using English.

♻️ Suggested change
 .typing-dot {
   width: 6px;
   height: 6px;
-  background-color: currentColor; /* 👈 theme ke hisaab se */
+  background-color: currentColor; /* inherits from theme */
   border-radius: 50%;
   animation: typing 1.4s infinite ease-in-out;
 }
frontend/src/pages/DsaDashboard.jsx (1)

7-10: Inconsistent indentation.

Lines 7 and 10 lack proper indentation compared to surrounding code.

♻️ Suggested fix
 export default function DsaDashboard({ setCurrentQuestionContext }) {
   const [currentView, setCurrentView] = useState("topics");
-const [selectedTopic, setSelectedTopic] = useState(null);
+  const [selectedTopic, setSelectedTopic] = useState(null);


-const handleBackToTopics = () => {
+  const handleBackToTopics = () => {
     setCurrentView("topics");
     setSelectedTopic(null);
   };
frontend/src/utils/buildQuestionContext.js (1)

1-26: Non-English comments should be in English.

The comments are in Hindi. For team-wide accessibility and consistency, consider translating to English.

♻️ Suggested translation
 export function buildQuestionContext({ topic, question = null }) {
-  // Agar topic hi nahi hai, toh kuch nahi bhej sakte
+  // If topic is missing, we can't build any context
   if (!topic) return null;

-  // Case 1: Agar sirf Topic level context chahiye (Jab user questions list dekh raha ho)
+  // Case 1: Topic-only context (when user is viewing the questions list)
   if (!question) {
     return {
       type: "DSA",
       topicId: topic.id,
       topicTitle: topic.title,
-      isTopicOnly: true, // Backend ko batane ke liye ki abhi question select nahi hua
+      isTopicOnly: true, // Indicates no specific question is selected yet
     };
   }

-  // Case 2: Agar user ne question select kar liya hai
+  // Case 2: Full context when user has selected a specific question
   return {
frontend/src/pages/InterviewExp.jsx (1)

7-7: Combine React imports for consistency.

The useEffect import can be combined with the existing useState import on line 1.

Proposed fix
-import { useState } from "react";
+import { useState, useEffect } from "react";
 import { motion, AnimatePresence } from "framer-motion";
 import { useInterview } from "@/hooks/useInterviews";
 import InterviewFilters from "@/components/interview/InterviewFilters";
 import InterviewExperienceForm from "@/components/interview/InterviewExperienceForm";
 import InterviewExperienceItem from "@/components/interview/InterviewExperienceItem";
-import { useEffect } from "react";
frontend/src/components/chatbot/ChatbotWrapper.jsx (3)

66-70: Missing dependency in useEffect.

The isTyping variable is used inside the effect but not listed in the dependency array. This could cause stale closure issues.

Proposed fix
 useEffect(() => {
   if (!isTyping) {
     scrollToBottom();
   }
-}, [messages]);
+}, [messages, isTyping]);

146-149: Dead code: stopStreaming function is never used.

The stopStreaming function and abortTypingRef are defined but never invoked anywhere in the component.

Consider either:

  1. Removing the unused code
  2. Wiring a "Stop" button to this function if streaming cancellation is intended
Option 1: Remove dead code
-const abortTypingRef = useRef(false);
 // ...
-const stopStreaming = () => {
-  abortTypingRef.current = true;
-  setIsTyping(false);
-};

74-101: Potential state update on unmounted component during welcome animation.

The typing animation uses nested setTimeout callbacks that continue executing even if the component unmounts, potentially causing a React warning or memory leak.

Proposed fix with cleanup
 const toggleChat = () => {
   setIsOpen((prev) => {
     const newState = !prev;

     if (newState && messages.length === 0) {
       const welcome = "SYSTEM_READY: Cortex online. How can I help you debug your experience today?";
       let currentText = "";
       let index = 0;
+      let cancelled = false;

-      setTimeout(() => {
+      const timeoutId = setTimeout(() => {
         const typeWelcome = () => {
-          if (index < welcome.length) {
+          if (cancelled) return;
+          if (index < welcome.length) {
             currentText += welcome.charAt(index);
             setMessages([{ from: "bot", text: currentText }]);
             index++;
             setTimeout(typeWelcome, 25);
           } else {
             setMessages([{ from: "bot", text: welcome }]);
           }
         };

         typeWelcome();
       }, 500);
+
+      // Store cleanup in a ref or return a cleanup mechanism
     }

     return newState;
   });
 };

Note: A more robust solution would use useEffect with proper cleanup for the animation.

frontend/src/components/interview/InterviewExperienceItem.jsx (1)

69-76: Avoid using global window object for React state.

Setting window.__CURRENT_QUESTION_CONTEXT__ is an anti-pattern in React. The context is already being propagated via setCurrentQuestionContext prop. Global variables bypass React's reactivity and can cause hard-to-debug issues.

Remove the global assignment entirely—the prop-based context setting in handleCardClick is sufficient.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ce1fbf and 92079b8.

⛔ Files ignored due to path filters (3)
  • backend/bun.lock is excluded by !**/*.lock
  • bun.lock is excluded by !**/*.lock
  • frontend/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (19)
  • backend/.env.example
  • backend/package.json
  • backend/src/ai/chatBrain.ts
  • backend/src/app.ts
  • backend/src/controllers/chatController.ts
  • backend/src/routes/chat.route.ts
  • backend/src/services/ai.ts
  • backend/src/services/retrival.ts
  • frontend/package.json
  • frontend/src/App.css
  • frontend/src/App.jsx
  • frontend/src/components/chatbot/ChatbotIcon.jsx
  • frontend/src/components/chatbot/ChatbotWrapper.jsx
  • frontend/src/components/dsa/questions/QuestionView.jsx
  • frontend/src/components/interview/InterviewExperienceItem.jsx
  • frontend/src/hooks/useChatbotVisibility.js
  • frontend/src/pages/DsaDashboard.jsx
  • frontend/src/pages/InterviewExp.jsx
  • frontend/src/utils/buildQuestionContext.js
🧰 Additional context used
🧬 Code graph analysis (9)
frontend/src/hooks/useChatbotVisibility.js (1)
frontend/src/components/chatbot/ChatbotWrapper.jsx (1)
  • location (49-49)
frontend/src/App.jsx (3)
frontend/src/hooks/useChatbotVisibility.js (2)
  • useChatbotVisibility (3-20)
  • useChatbotVisibility (3-20)
frontend/src/components/chatbot/ChatbotWrapper.jsx (1)
  • ChatbotWrapper (43-310)
frontend/src/pages/DsaDashboard.jsx (1)
  • DsaDashboard (5-70)
backend/src/routes/chat.route.ts (1)
backend/src/controllers/chatController.ts (1)
  • chatController (6-55)
backend/src/controllers/chatController.ts (3)
backend/src/services/retrival.ts (1)
  • fetchRAGContext (3-58)
backend/src/ai/chatBrain.ts (1)
  • buildPrompt (6-134)
backend/src/services/ai.ts (1)
  • geminiModel (5-7)
frontend/src/components/interview/InterviewExperienceItem.jsx (1)
frontend/src/hooks/useInterviews.js (1)
  • interview (24-28)
frontend/src/components/chatbot/ChatbotWrapper.jsx (3)
frontend/src/hooks/useChatbotVisibility.js (2)
  • location (4-4)
  • currentPath (5-5)
frontend/src/App.jsx (1)
  • currentQuestionContext (27-27)
frontend/src/components/chatbot/ChatbotIcon.jsx (1)
  • ChatbotIcon (45-96)
frontend/src/components/dsa/questions/QuestionView.jsx (1)
frontend/src/utils/buildQuestionContext.js (1)
  • buildQuestionContext (1-26)
frontend/src/pages/InterviewExp.jsx (2)
frontend/src/hooks/useInterviews.js (2)
  • useInterview (6-56)
  • interview (24-28)
frontend/src/components/interview/InterviewExperienceItem.jsx (1)
  • InterviewExperienceItem (14-375)
backend/src/ai/chatBrain.ts (1)
frontend/src/hooks/useInterviews.js (1)
  • interview (24-28)
🪛 dotenv-linter (4.0.0)
backend/.env.example

[warning] 4-4: [UnorderedKey] The API_URL key should go before the JWT_SECRET key

(UnorderedKey)


[warning] 5-5: [UnorderedKey] The GEMINI_API_KEY key should go before the JWT_SECRET key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (18)
frontend/package.json (2)

40-40: No functional change detected.

The react-markdown entry appears to be reordered with no version change. This is effectively a no-op and has no impact on functionality.


31-31: framer-motion version 12.25.0 exists and is available on npm.

The upgrade from ^12.23.24 to ^12.25.0 is confirmed as a valid minor version bump within the 12.x release series. Version 12.25.0 was published on January 9, 2026, and the latest available version is 12.26.1. No blocking issues identified for this upgrade.

backend/.env.example (1)

4-5: LGTM!

The new GEMINI_API_KEY environment variable is appropriately added to support the Gemini AI integration. The empty default values are suitable for an example file.

backend/src/app.ts (1)

39-39: Verify if the /chat endpoint should require authentication.

The chat route is mounted without any authentication middleware. Based on the controller, it processes user-specific context (userAnswer, questionContext, history). If this data is user-specific or should be protected, consider adding authentication middleware.

backend/package.json (1)

42-42: LGTM!

The @google/generative-ai dependency is appropriately added to support the Gemini integration.

backend/src/routes/chat.route.ts (1)

1-8: LGTM!

Clean route setup following Express conventions. The POST method is appropriate for chat interactions that send message payloads.

backend/src/ai/chatBrain.ts (2)

1-4: LGTM!

The formatHistory utility function is clean and handles the default empty array case appropriately.


19-35: Well-structured base role definition.

The baseRole clearly defines the AI's scope, goals, and rules. The strict domain limitation and refusal message help prevent off-topic responses.

frontend/src/App.jsx (4)

17-23: LGTM! Clean separation of chatbot visibility logic.

The ChatbotContainer component correctly encapsulates the visibility check via useChatbotVisibility() and conditionally renders ChatbotWrapper. This keeps the visibility logic close to where it's used.


27-27: LGTM!

State initialization for currentQuestionContext is appropriate at the App level for cross-component context sharing.


39-43: LGTM! Context propagation is correctly wired.

Passing setCurrentQuestionContext to both DsaDashboard and InterviewExp enables child components to update the chatbot context appropriately.


50-51: LGTM!

Rendering ChatbotContainer outside Routes is correct for a global overlay component that should persist across route changes.

frontend/src/components/dsa/questions/QuestionView.jsx (2)

184-201: LGTM! Correct use of stopPropagation.

The e.stopPropagation() on the "Mark Done" button correctly prevents the card's onClick from triggering when toggling completion status.


203-216: LGTM!

The external link button correctly uses stopPropagation and noopener,noreferrer for secure external navigation.

frontend/src/pages/InterviewExp.jsx (1)

218-220: LGTM!

Correctly passing setCurrentQuestionContext to InterviewExperienceItem for individual interview context propagation.

frontend/src/components/chatbot/ChatbotWrapper.jsx (1)

249-256: LGTM! Good use of ReactMarkdown with custom renderers.

The custom code and pre components provide consistent styling for code blocks in chat messages.

frontend/src/components/interview/InterviewExperienceItem.jsx (2)

38-52: Consider adding optional chaining for setCurrentQuestionContext.

Similar to QuestionsView.jsx, this function should guard against setCurrentQuestionContext being undefined, though the existing if check is acceptable.


237-366: LGTM! Comprehensive ReactMarkdown styling.

The custom component renderers provide consistent theming for all markdown elements. The neomorphic design language is applied cohesively throughout.

@aaryagodbole
Copy link
Collaborator

Summary by CodeRabbit

Release Notes

  • New Features

    • Added AI chatbot assistant (Cortex) for interactive learning support
    • Chatbot available on DSA questions and interview experience pages
    • Context-aware responses based on current content and learning history
    • Dark/light theme support for chatbot interface
  • Chores

    • Updated dependencies to support new AI functionality

✏️ Tip: You can customize this high-level summary in your review settings.

image

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @backend/src/ai/chatBrain.ts:
- Line 42: Remove the raw console.log that prints questionContext in chatBrain
(the line logging "🧠 QUESTION CONTEXT IN chatBrain 👉" and the questionContext
variable); either delete it or wrap it behind a runtime debug flag (e.g.,
process.env.DEBUG_CHATBRAIN) or replace with the project's structured logger
(e.g., processLogger.debug/processLogger.trace) ensuring sensitive fields from
questionContext are omitted or redacted before logging. Ensure changes occur in
the chatBrain module where questionContext is referenced so production runs no
longer emit that data to logs.
- Around line 6-18: Remove the unused path parameter from the buildPrompt
function signature and its type annotation in buildPrompt({...}) (the function
in chatBrain.ts), and then update every call site (notably in chatController.ts)
to stop passing path; ensure any destructuring or type declarations that
referenced path are also cleaned up and that all remaining parameters (ragData,
userAnswer, questionContext, history) are correctly passed in the same order or
as an object.

In @backend/src/controllers/chatController.ts:
- Around line 6-13: In chatController, validate required inputs from req.body
(at least userAnswer and path) before using them: check that userAnswer exists
and is a string and path exists (and is the expected type), coerce or validate
questionContext and set history to an array only if
Array.isArray(req.body.history) otherwise default to []; if validation fails
return a 400 response with a clear error message; update the destructuring usage
(userAnswer, path, questionContext, history) to use these validated values so
downstream logic only runs on valid input.
🧹 Nitpick comments (9)
frontend/src/components/interview/InterviewExperienceItem.jsx (2)

323-328: External links missing security attributes.

The custom a component should include target="_blank" and rel="noopener noreferrer" if links are expected to open externally. Without rel="noopener noreferrer", the opened page can access window.opener which is a security risk.

Proposed fix
 a: ({ node, ...props }) => (
   <a
     className="text-[#C1502E] font-bold underline decoration-4 decoration-[#C1502E] hover:bg-[#C1502E] hover:text-[#F5E6D3] px-1 transition-colors"
+    target="_blank"
+    rel="noopener noreferrer"
     {...props}
   />
 ),

156-160: Consider adding a fallback for missing profile photo.

If interview.member.profilePhoto is null or undefined, this will render a broken image. Consider adding a fallback or placeholder.

Example fix
 <img
-  src={interview.member.profilePhoto}
+  src={interview.member.profilePhoto || "/default-avatar.png"}
   alt={interview.member.name}
   className="w-10 h-10 rounded-full border-2 border-black dark:border-[#F5E6D3] object-cover"
+  onError={(e) => { e.target.src = "/default-avatar.png"; }}
 />
backend/src/controllers/chatController.ts (2)

19-21: Consider using a proper logger instead of console.log.

Using console.log for production logging lacks log levels, structured output, and proper redaction. Consider using a logging library that supports different environments.


54-57: Add explicit return for consistency.

Lines 39 and 43 use return res.json(...) and return res.status(503).json(...), but line 54 omits the return. While not functionally broken here (since it's the last statement), adding return maintains consistency and prevents accidental issues if code is added later.

Suggested fix
-    res.status(500).json({
+    return res.status(500).json({
       reply: "Cortex encountered an issue. Let's try that again in a moment.",
       error: process.env.NODE_ENV === 'development' ? err.message : undefined // Hide technical error in production
     });
backend/src/services/retrival.ts (4)

3-4: Consider adding type definitions for questionContext.

Using any type reduces type safety. Consider defining an interface or union type for the different context types (DSA, INTERVIEW_EXPERIENCE, INTERVIEW_COLLECTION) to catch type errors at compile time.

Example type definition
interface DSAContext {
  type: "DSA";
  questionId?: string;
  isTopicOnly?: boolean;
  topicId?: string;
  topicTitle?: string;
  questionName?: string;
}

interface InterviewExperienceContext {
  type: "INTERVIEW_EXPERIENCE";
  id: string;
  studentName?: string;
  company?: string;
  verdict?: string;
}

interface InterviewCollectionContext {
  type: "INTERVIEW_COLLECTION";
}

type QuestionContext = DSAContext | InterviewExperienceContext | InterviewCollectionContext;

export async function fetchRAGContext(questionContext?: QuestionContext) {

26-44: Parallelize independent API calls for better performance.

The two API calls on lines 27 and 32 are independent and can be executed concurrently using Promise.all to reduce latency.

Suggested optimization
     if (questionContext.type === "INTERVIEW_EXPERIENCE") {
-      const specificRes = await api.get(`/interviews/${questionContext.id}`);
-      const specificData = specificRes.data?.data;
-
-  
-     
-      const globalRes = await api.get(`/interviews?limit=20`);
-      const allInterviews = globalRes.data?.data || [];
+      const [specificRes, globalRes] = await Promise.all([
+        api.get(`/interviews/${questionContext.id}`),
+        api.get(`/interviews?limit=20`)
+      ]);
+      const specificData = specificRes.data?.data;
+      const allInterviews = globalRes.data?.data || [];

       return {

47-52: Fix inconsistent indentation.

Line 51 has incorrect indentation (appears to be 2 spaces instead of the expected 6 spaces to match the if-block scope).

Fix
     // Default Case
     if (questionContext.type === "INTERVIEW_COLLECTION") {
       const res = await api.get(`/interviews?limit=50`);
       const data = res.data?.data || res.data?.interviews || [];
-  return data;
+      return data;
     }

54-56: Enhance error logging to include stack trace.

Logging only error.message loses valuable debugging information. Consider logging the full error or at least including the stack trace in development environments.

Suggested improvement
   } catch (error: any) {
-    console.error("RAG Fetch Error:", error.message);
+    console.error("RAG Fetch Error:", error.message, error.stack);
     return questionContext; 
   }
backend/src/ai/chatBrain.ts (1)

44-62: Fix inconsistent indentation.

Lines 44-62 are not indented consistently with the rest of the function body. The if block starts at column 0 instead of being indented within the function.

The logic is correct, just needs proper indentation
-// --- CASE 1: DSA TOPIC ONLY ---
-if (questionContext?.type === "DSA" && questionContext.isTopicOnly) {
-  const questionsList = ragData?.relatedQuestions 
-    ? ragData.relatedQuestions.map((q: any) => `- ${q.title}`).join("\n")
-    : "No questions listed for this topic yet.";
-
-  return `
+  // --- CASE 1: DSA TOPIC ONLY ---
+  if (questionContext?.type === "DSA" && questionContext.isTopicOnly) {
+    const questionsList = ragData?.relatedQuestions 
+      ? ragData.relatedQuestions.map((q: any) => `- ${q.title}`).join("\n")
+      : "No questions listed for this topic yet.";
+
+    return `
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 92079b8 and ce6cfd3.

📒 Files selected for processing (9)
  • backend/src/ai/chatBrain.ts
  • backend/src/controllers/chatController.ts
  • backend/src/services/retrival.ts
  • frontend/src/components/chatbot/ChatbotWrapper.jsx
  • frontend/src/components/dsa/questions/QuestionView.jsx
  • frontend/src/components/interview/InterviewExperienceItem.jsx
  • frontend/src/pages/DsaDashboard.jsx
  • frontend/src/pages/InterviewExp.jsx
  • frontend/src/utils/buildQuestionContext.js
🚧 Files skipped from review as they are similar to previous changes (4)
  • frontend/src/components/chatbot/ChatbotWrapper.jsx
  • frontend/src/pages/InterviewExp.jsx
  • frontend/src/pages/DsaDashboard.jsx
  • frontend/src/utils/buildQuestionContext.js
🧰 Additional context used
🧬 Code graph analysis (4)
frontend/src/components/dsa/questions/QuestionView.jsx (2)
frontend/src/utils/buildQuestionContext.js (1)
  • buildQuestionContext (1-26)
frontend/src/hooks/useQuestions.js (1)
  • toggle (34-42)
backend/src/controllers/chatController.ts (3)
backend/src/services/retrival.ts (1)
  • fetchRAGContext (3-59)
backend/src/ai/chatBrain.ts (1)
  • buildPrompt (6-142)
backend/src/services/ai.ts (1)
  • geminiModel (5-7)
backend/src/services/retrival.ts (2)
frontend/src/utils/api/api.js (2)
  • res (42-42)
  • api (8-12)
frontend/src/hooks/useQuestions.js (1)
  • questions (11-22)
frontend/src/components/interview/InterviewExperienceItem.jsx (1)
frontend/src/hooks/useInterviews.js (1)
  • interview (24-28)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (13)
frontend/src/components/dsa/questions/QuestionView.jsx (1)

196-199: Good use of stopPropagation.

Correctly prevents the card's onClick from firing when clicking the "Mark Done" and "Open" action buttons.

frontend/src/components/interview/InterviewExperienceItem.jsx (3)

38-60: Well-structured context handling.

The null check on setCurrentQuestionContext (line 43) and only setting context when expanding is appropriate. Good defensive coding.


103-135: Action buttons correctly isolated from card click.

Good use of stopPropagation() to prevent the card's expand/collapse behavior when clicking Edit or Delete.


193-206: Clean expand/collapse animation.

The AnimatePresence with height animation and the negative margin for visual continuity with the card above is well-implemented.

backend/src/controllers/chatController.ts (3)

1-4: LGTM!

Imports are correctly structured and match the dependencies used within the controller.


23-29: LGTM!

Prompt building correctly passes all required parameters to buildPrompt.


36-48: Good error handling pattern for Gemini-specific errors.

The nested try-catch that specifically handles 503 overload errors while re-throwing others to the outer catch is a clean approach for differentiated error responses.

backend/src/services/retrival.ts (1)

8-22: LGTM!

The DSA case handling properly checks for questionId and topicId conditions and includes sensible fallbacks for missing data.

backend/src/ai/chatBrain.ts (5)

1-4: LGTM!

Clean utility function that properly formats conversation history for prompt inclusion.


19-40: LGTM!

The base role prompt is well-structured with clear goals, instructions, and boundaries for the AI assistant.


64-83: LGTM!

CASE 2 properly handles specific DSA questions with conversation history and appropriate fallback when ragData is unavailable.


85-108: LGTM!

Good defensive coding with Array.isArray check and performance optimization by limiting to 10 experiences. Clear instructions for the AI assistant.


135-141: LGTM!

The default fallback properly maintains conversation context and handles unmatched cases gracefully.

@Harish-Naruto
Copy link
Member

screenshot-2026-01-14_11-14-27 chatbot cant even list questions from a topic

@Harish-Naruto
Copy link
Member

screenshot-2026-01-14_11-10-07 infinite response time error handling is missing somewhere

@Harish-Naruto
Copy link
Member

screenshot-2026-01-14_11-01-53 fix ui for large response

@Harish-Naruto
Copy link
Member

image accuracy of this chatbot 🤣

@Harish-Naruto
Copy link
Member

image why everything is in capital letters ❓ ❓ ❓

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants