-
Notifications
You must be signed in to change notification settings - Fork 4
Integrated context-aware chatbot #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
📝 WalkthroughWalkthroughAdds 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
Deploying coc-members with
|
| Latest commit: |
ce6cfd3
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://07f0164c.coc-members.pages.dev |
| Branch Preview URL: | https://chatbot.coc-members.pages.dev |
bced22a to
92079b8
Compare
There was a problem hiding this 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 ifnode-fetchis necessary.Since the project uses Bun (
bun src/server.tsin scripts), nativefetchis already available globally. Thenode-fetchdependency 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.bodywithout validating their presence or types. IfuserAnsweris missing or empty,buildPromptwill 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.contentpreviews 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 usingPromise.race()with a timeout, or useAbortControllerif 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
anythroughout, which reduces type safety. Defining interfaces forquestionContextand 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.tsis misspelled. Consider renaming toretrieval.tsfor 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 unusedpathparameter from the function signature.The
pathparameter 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 invisiblePaths.Since you're using
startsWith()for matching,/dsa/topicsis already covered by/dsa, and/interview/preparationis 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
useEffectimport can be combined with the existinguseStateimport 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
isTypingvariable 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:stopStreamingfunction is never used.The
stopStreamingfunction andabortTypingRefare defined but never invoked anywhere in the component.Consider either:
- Removing the unused code
- 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
setTimeoutcallbacks 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
useEffectwith proper cleanup for the animation.frontend/src/components/interview/InterviewExperienceItem.jsx (1)
69-76: Avoid using globalwindowobject for React state.Setting
window.__CURRENT_QUESTION_CONTEXT__is an anti-pattern in React. The context is already being propagated viasetCurrentQuestionContextprop. Global variables bypass React's reactivity and can cause hard-to-debug issues.Remove the global assignment entirely—the prop-based context setting in
handleCardClickis sufficient.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
backend/bun.lockis excluded by!**/*.lockbun.lockis excluded by!**/*.lockfrontend/bun.lockis excluded by!**/*.lock
📒 Files selected for processing (19)
backend/.env.examplebackend/package.jsonbackend/src/ai/chatBrain.tsbackend/src/app.tsbackend/src/controllers/chatController.tsbackend/src/routes/chat.route.tsbackend/src/services/ai.tsbackend/src/services/retrival.tsfrontend/package.jsonfrontend/src/App.cssfrontend/src/App.jsxfrontend/src/components/chatbot/ChatbotIcon.jsxfrontend/src/components/chatbot/ChatbotWrapper.jsxfrontend/src/components/dsa/questions/QuestionView.jsxfrontend/src/components/interview/InterviewExperienceItem.jsxfrontend/src/hooks/useChatbotVisibility.jsfrontend/src/pages/DsaDashboard.jsxfrontend/src/pages/InterviewExp.jsxfrontend/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-markdownentry appears to be reordered with no version change. This is effectively a no-op and has no impact on functionality.
31-31:framer-motionversion 12.25.0 exists and is available on npm.The upgrade from
^12.23.24to^12.25.0is 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_KEYenvironment 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/chatendpoint 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-aidependency 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
formatHistoryutility function is clean and handles the default empty array case appropriately.
19-35: Well-structured base role definition.The
baseRoleclearly 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
ChatbotContainercomponent correctly encapsulates the visibility check viauseChatbotVisibility()and conditionally rendersChatbotWrapper. This keeps the visibility logic close to where it's used.
27-27: LGTM!State initialization for
currentQuestionContextis appropriate at the App level for cross-component context sharing.
39-43: LGTM! Context propagation is correctly wired.Passing
setCurrentQuestionContextto bothDsaDashboardandInterviewExpenables child components to update the chatbot context appropriately.
50-51: LGTM!Rendering
ChatbotContaineroutsideRoutesis 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 ofstopPropagation.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
stopPropagationandnoopener,noreferrerfor secure external navigation.frontend/src/pages/InterviewExp.jsx (1)
218-220: LGTM!Correctly passing
setCurrentQuestionContexttoInterviewExperienceItemfor individual interview context propagation.frontend/src/components/chatbot/ChatbotWrapper.jsx (1)
249-256: LGTM! Good use of ReactMarkdown with custom renderers.The custom
codeandprecomponents provide consistent styling for code blocks in chat messages.frontend/src/components/interview/InterviewExperienceItem.jsx (2)
38-52: Consider adding optional chaining forsetCurrentQuestionContext.Similar to
QuestionsView.jsx, this function should guard againstsetCurrentQuestionContextbeing undefined, though the existingifcheck 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.
There was a problem hiding this 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
acomponent should includetarget="_blank"andrel="noopener noreferrer"if links are expected to open externally. Withoutrel="noopener noreferrer", the opened page can accesswindow.openerwhich 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.profilePhotois 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.logfor production logging lacks log levels, structured output, and proper redaction. Consider using a logging library that supports different environments.
54-57: Add explicitreturnfor consistency.Lines 39 and 43 use
return res.json(...)andreturn res.status(503).json(...), but line 54 omits thereturn. While not functionally broken here (since it's the last statement), addingreturnmaintains 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
anytype 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.allto 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.messageloses 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
ifblock 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
📒 Files selected for processing (9)
backend/src/ai/chatBrain.tsbackend/src/controllers/chatController.tsbackend/src/services/retrival.tsfrontend/src/components/chatbot/ChatbotWrapper.jsxfrontend/src/components/dsa/questions/QuestionView.jsxfrontend/src/components/interview/InterviewExperienceItem.jsxfrontend/src/pages/DsaDashboard.jsxfrontend/src/pages/InterviewExp.jsxfrontend/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
questionIdandtopicIdconditions 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.isArraycheck 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.






Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.