Skip to content

feat: add SolarChatbot component with styling and chat functionality#47

Open
VyapakBansal wants to merge 15 commits into
mainfrom
SolarChatBot
Open

feat: add SolarChatbot component with styling and chat functionality#47
VyapakBansal wants to merge 15 commits into
mainfrom
SolarChatBot

Conversation

@VyapakBansal
Copy link
Copy Markdown
Contributor

@VyapakBansal VyapakBansal commented May 16, 2026

  • Implemented ChatBot component with user interface for chat interactions.
  • Added styles for chat interface, including message bubbles, buttons, and avatars.
  • Integrated chat API for handling messages and responses using OpenAI and Supabase.
  • Included typing indicators and suggested questions for user engagement.

Summary by CodeRabbit

  • New Features
    • Interactive chatbot with floating trigger, animated messages, avatars, typing indicator, suggestion buttons, and responsive hide under 768px
  • Integration
    • Chatbot rendered globally across the app for site-wide access
  • Backend / Reliability
    • Streamlined chat service with contextual retrieval, streaming responses, and improved error reporting; vector-enabled DB model for documents
  • Chores
    • Added ingestion, scraping, and cleaning utilities; updated runtime packages to include AI SDKs and related tooling

Review Change Stack

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
solar-car-website-next Ready Ready Preview, Comment May 23, 2026 7:53pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a client-side animated ChatBot UI, a server-side chatAction implementing RAG (HuggingFace embeddings + Supabase search + streaming), dependency additions, a simplified /api/chat route, and layout/middleware wiring to expose the chat globally.

Changes

SOLARIS Chat System

Layer / File(s) Summary
Dependencies and Auth Setup
package.json, src/proxy.ts
Adds ai, @ai-sdk/openai, and @ai-sdk/react dependencies; marks /api/chat as a public route exempt from Clerk auth.
Prisma vector model & generator
prisma/schema.prisma
Enables postgresqlExtensions, adds extensions = [vector] to the datasource, and adds a Document model with Unsupported("vector(384)") embedding mapped to documents.
Data pipeline scripts (scrape → clean → ingest)
scripts/scrape.py, scripts/clean.py, scripts/ingest.py, scripts/main.py, scripts/requirements.txt
Adds scraping, cleaning, chunking, local embedding ingestion, DB writes into documents, a main runner with timing/memory reporting, and a requirements list.
Chat UI Styling
src/app/_components/ChatBot/ChatBot.module.scss
New CSS module defining trigger button, chat panel, header/status, message bubbles (user/bot), suggestion chips, input form states, typing dots, avatar layout, bold highlighting, and responsive hide on <768px.
Chat UI Primitives — Avatar & Trigger
src/app/_components/ChatBot/ChatAvatar.tsx, src/app/_components/ChatBot/ChatTrigger.tsx
Adds CarAvatar and TypingDots animated components and an animated floating ChatTrigger button with ring and image animation.
Chat Panel — Messages, Suggestions, Input
src/app/_components/ChatBot/ChatPanel.tsx
Implements ChatPanel rendering messages (with bold parsing), animated rows, default greeting, typing indicator, suggestion chips, auto-scroll, auto-resize textarea, and Enter-to-send input handling.
ChatBot Component — Orchestration
src/app/_components/ChatBot/ChatBot.tsx
Client-side SolarChatbot wires useChat (transport /api/chat), manages open/close state, and renders ChatTrigger/ChatPanel via AnimatePresence.
Chat API Route
src/app/api/chat/route.ts
POST /api/chat now parses { messages } and delegates to chatAction, returning the action result and including error message/stack on 500.
Backend RAG Pipeline
src/app/_components/ChatBot/actions.ts
Adds chatAction: prepares model messages, generates HuggingFace embeddings (validates 384-dim), calls Supabase match_documents RPC for context, injects context into a dynamic system prompt, and streams model responses via OpenRouter-compatible client.
Layout Integration & trpc import
src/app/layout.tsx, src/server/api/trpc.ts
Imports and renders ChatBot inside TRPCReactProvider and expands a portal import to include UserRole.
Misc
.gitignore
Adds *.pyc to ignore list.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • justin-phxm
  • promatty
  • alexwhelan12

"I hop and hum in pixel light,
A ring that spins through day and night,
I fetch the context, stitch a line,
And stream a thought — electric, fine,
SOLARIS chats — a tiny delight."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main addition: a SolarChatbot component with styling and chat functionality, which is directly reflected in the file changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch SolarChatBot

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.

Copy link
Copy Markdown

@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: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ChatBot`:
- Line 1: The index contains a gitlink for ChatBot (mode 160000) but no
.gitmodules, so either add a .gitmodules entry for the ChatBot submodule
pointing to the correct remote URL and update the index to reference that
submodule (include the ChatBot path and remote URL in .gitmodules and commit the
file), or remove the submodule gitlink entirely so ChatBot is tracked as normal
files (remove the 160000 gitlink for ChatBot from the index, ensure the contents
under src/app/_components/ChatBot/ are added to the repository as regular files,
and commit the change); pick one approach and update the index and commit
accordingly so the repository no longer contains an unresolved submodule
reference.

In `@src/app/_components/ChatBot/ChatBot.tsx`:
- Around line 326-331: The suggestion buttons currently call sendMessage({ text:
s }) even while a response is in-flight; update the SUGGESTED render to guard
against concurrent sends by checking the isLoading state: disable the button
(add disabled prop / styles change using styles.suggestionButton) when isLoading
is true and/or make the onClick handler first return if isLoading, and only call
sendMessage when not loading. Reference the SUGGESTED map, sendMessage, and
isLoading to locate and change the behavior.
- Around line 34-42: The type predicate in getMessageText uses `any`; change it
to a proper typed guard by replacing `(p: any)` with a narrower input type
(e.g., `p: unknown` or the concrete union/interface used by UIMessage parts) and
declare a corresponding type guard signature (for example `p is { type: "text";
text: string }`) so TypeScript can narrow safely; update or add the part type
definition (e.g., MessagePart or reuse UIMessagePart) if missing and use that
type in the filter to remove `any` while preserving the existing filter/map/join
logic in getMessageText.

In `@src/app/api/chat/route.ts`:
- Around line 301-302: The catch block in the chat API is returning raw stack
traces (err.message and err.stack) to clients; instead log the full error
server-side using the existing logger (or console.error) inside the catch and
replace the Response body with a generic message like "Internal Server Error"
and status 500; locate the catch that uses "err" and returns new Response(...)
in route.ts and change it to log the error (console.error(err) or
processLogger.error(err)) and return a generic 500 Response without exposing
err.message/err.stack.
- Around line 200-213: Validate and bound the incoming messages before trusting
req.json(): ensure the parsed value for messages is an array (reject with 400 if
not), verify lastMessage (the messages[messages.length - 1] used here) exists,
is from the user/has the expected role/type and contains non-empty text, and
enforce caps (e.g. limit history length by slicing messages to the last N items
and truncate the extracted query string to a safe max length) before any
embedding or external service calls (refactor around the messages, lastMessage
and query extraction logic to perform these checks and return 400 on
invalid/oversized input).
- Around line 279-289: The current mapping trusts client-supplied roles via
messages.map into modelMessages allowing injection of "system" or fake
"assistant" turns; change the sanitization so you only accept and preserve
"user" and "assistant" roles from the incoming messages and explicitly drop or
downgrade any other roles (e.g., coerce unknown roles to "user" or skip them),
and ensure the server-only SYSTEM_PROMPT(contextText) remains the sole system
message; update the mapping logic used to build modelMessages (the messages.map
call) to validate role values and not forward client-controlled "system" or
unauthorized "assistant" roles into the history before slicing and passing into
streamText.
- Around line 217-231: The embedding fetch call (creating hfRes) needs an
AbortController-based timeout so a stalled HuggingFace request won't hang the
route; create an AbortController, pass controller.signal into the fetch options
used when building the request to
"https://router.huggingface.co/…/feature-extraction", and start a timer (e.g.,
setTimeout) to call controller.abort() after a configured timeout (e.g., 5–10s).
Catch the abort error around the await fetch(hfRes) and treat it as a graceful
fallback to "no retrieval" (skip retrieval flow) so downstream code continues;
ensure you clear the timer on success and handle non-abort fetch errors
normally. Use the existing hfRes variable and the fetch call in route.ts as the
insertion point.

In `@src/middleware.ts`:
- Line 10: The /api/chat route in src/middleware.ts lacks any abuse guardrails;
add a rate-limiting/quota middleware and request validation on that route to
prevent unauthenticated mass calls to external APIs. Implement an IP- or
token-based limiter (e.g., token-bucket or express-rate-limit) and attach it to
the route handling "/api/chat" (wrap the existing router.post('/api/chat', ...)
or app.use('/api/chat', ...) handler), enforce per-IP or per-API-key limits,
return HTTP 429 when exceeded, and validate incoming payloads (size/fields)
before forwarding to HuggingFace/OpenRouter so requests are rejected early and
costs are contained.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c888bd29-5886-4e5b-b6f4-974f1cdc191f

📥 Commits

Reviewing files that changed from the base of the PR and between 7f8b531 and 9edf7c6.

⛔ Files ignored due to path filters (5)
  • package-lock.json is excluded by !**/package-lock.json
  • public/HeliosSideview.png is excluded by !**/*.png
  • public/assets/HeliosSideview.png is excluded by !**/*.png
  • public/assets/Logo.png is excluded by !**/*.png
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (7)
  • ChatBot
  • package.json
  • src/app/_components/ChatBot/ChatBot.module.scss
  • src/app/_components/ChatBot/ChatBot.tsx
  • src/app/api/chat/route.ts
  • src/app/layout.tsx
  • src/middleware.ts

Comment thread ChatBot Outdated
Comment thread src/app/_components/ChatBot/ChatBot.tsx Outdated
Comment thread src/app/_components/ChatBot/ChatBot.tsx Outdated
Comment thread src/app/api/chat/route.ts Outdated
Comment thread src/app/api/chat/route.ts Outdated
Comment thread src/app/api/chat/route.ts Outdated
Comment thread src/app/api/chat/route.ts Outdated
Comment thread src/proxy.ts
Copy link
Copy Markdown

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/middleware.ts`:
- Around line 21-43: The in-memory chatRateLimit Map used inside clerkMiddleware
is unsuitable for the Edge runtime; replace it with a distributed KV (e.g.,
Upstash Redis or Vercel KV) and perform an atomic increment+expire per-IP key to
enforce the window across instances: normalize the client identifier (parse and
use the first IP from "x-forwarded-for" or req.ip fallback, collapse IPv6/IPv4
formats, and consider hashing the value) to avoid bucket fragmentation, use an
INCR/EXPIRE (or equivalent) on a namespaced key like chat_rate:{hash(ip)} with
TTL equal to windowMs, and check the returned counter to decide whether to
return the 429 response; ensure keys are created with TTL to avoid unbounded
growth and handle Redis errors by falling back to a safe default (e.g., allow or
conservative deny) in clerkMiddleware.
- Around line 26-39: The code uses the raw x-forwarded-for header as the
chatRateLimit key and never evicts old entries, causing inconsistent keys and
unbounded growth; change the IP extraction (where
req.headers.get("x-forwarded-for") is read in the middleware) to parse the
header and use the first non-empty, trimmed IP (fall back to "127.0.0.1" or
req.ip if available) so comma-separated lists map to a single canonical key, and
add eviction logic for the chatRateLimit map (e.g., store per-entry
lastReset/lastSeen in the existing entry object and, when accessing or
incrementing inside the same block where entry is read/updated, delete entries
whose lastSeen/lastReset is older than a configurable TTL or run a short cleanup
pass to remove stale buckets) so old keys are removed and the map cannot grow
unbounded.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 462da927-51d4-448b-a751-c00745fce66d

📥 Commits

Reviewing files that changed from the base of the PR and between 9edf7c6 and d471c90.

📒 Files selected for processing (3)
  • src/app/_components/ChatBot/ChatBot.tsx
  • src/app/api/chat/route.ts
  • src/middleware.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/_components/ChatBot/ChatBot.tsx

Comment thread src/middleware.ts Outdated
Comment thread src/middleware.ts Outdated
Comment thread ChatBot/public/HeliosSideview.png Outdated
Comment thread package-lock.json Outdated
Comment thread src/app/api/chat/route.ts
Comment thread src/proxy.ts
Comment thread src/app/_components/ChatBot/ChatBot.tsx
@VyapakBansal
Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

Copy link
Copy Markdown
Contributor

Copilot AI commented May 16, 2026

@copilot resolve the merge conflicts in this pull request

Merge conflicts are resolved and merged from origin/main in commit 921b1ab.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • checkpoint.prisma.io
    • Triggering command: /usr/local/bin/node /usr/local/bin/node /home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/prisma/build/child {&#34;product&#34;:&#34;prisma&#34;,&#34;version&#34;:&#34;6.19.3&#34;,&#34;cli_install_type&#34;:&#34;local&#34;,&#34;information&#34;:&#34;&#34;,&#34;local_timestamp&#34;:&#34;2026-05-16T21:20:53Z&#34;,&#34;project_hash&#34;:&#34;90dbab93&#34;,&#34;cli_path&#34;:&#34;/home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/@prisma/client/n (dns block)
    • Triggering command: /usr/local/bin/node /usr/local/bin/node /home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/prisma/build/child {&#34;product&#34;:&#34;prisma&#34;,&#34;version&#34;:&#34;6.19.3&#34;,&#34;cli_install_type&#34;:&#34;local&#34;,&#34;information&#34;:&#34;&#34;,&#34;local_timestamp&#34;:&#34;2026-05-16T21:20:54Z&#34;,&#34;project_hash&#34;:&#34;90dbab93&#34;,&#34;cli_path&#34;:&#34;/home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/.bin/prisma&#34;,&#34;cl (dns block)
    • Triggering command: /usr/local/bin/node /usr/local/bin/node /home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/prisma/build/child {&#34;product&#34;:&#34;prisma&#34;,&#34;version&#34;:&#34;6.19.3&#34;,&#34;cli_install_type&#34;:&#34;local&#34;,&#34;information&#34;:&#34;&#34;,&#34;local_timestamp&#34;:&#34;2026-05-16T21:22:13Z&#34;,&#34;project_hash&#34;:&#34;90dbab93&#34;,&#34;cli_path&#34;:&#34;/home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/.bin/prisma&#34;,&#34;cl (dns block)
  • fonts.googleapis.com
    • Triggering command: /usr/local/bin/node /usr/local/bin/node /home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/.bin/next build (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copy link
Copy Markdown

@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: 1

♻️ Duplicate comments (4)
src/app/_components/ChatBot/ChatPanel.tsx (1)

227-233: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Prevent overlapping requests from suggested-question buttons.

Suggested chips currently bypass the isLoading guard, so users can trigger concurrent sendMessage calls.

Proposed fix
           {SUGGESTED.map((s) => (
             <button
               className={styles.suggestionButton}
+              disabled={isLoading}
               key={s}
               onClick={() => {
+                if (isLoading) return;
                 void sendMessage({ text: s });
               }}
             >
               {s}
             </button>
           ))}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/_components/ChatBot/ChatPanel.tsx` around lines 227 - 233, The
suggestion button currently calls sendMessage directly and can fire concurrent
requests; update the onClick handler and rendering to respect the isLoading flag
(from component state/props) so clicks are ignored when isLoading is true:
either early-return from the onClick (check isLoading before calling
sendMessage) and/or set the button's disabled attribute when isLoading, keeping
the same className (styles.suggestionButton) and preserving the payload ({ text:
s }) passed to sendMessage; reference the sendMessage function and the isLoading
variable in the ChatPanel component to locate where to add the guard.
src/app/_components/ChatBot/actions.ts (2)

135-155: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not trust client-authored assistant history on a public route.

messages comes straight from the request, so Lines 135-155 still let a caller inject arbitrary prior assistant content into the prompt. If you don't have server-side conversation storage, only forward user turns here.

Safer short-term fix
     const modelMessages = messages
       .filter(
-        (m): m is UIMessage & { role: "user" | "assistant" } =>
-          m.role === "user" || m.role === "assistant",
+        (m): m is UIMessage & { role: "user" } => m.role === "user",
       )
       .map((m) => ({
         content:
           ((m as unknown as Record<string, unknown>).content as
             | string

If you need assistant history for continuity, reload it from server-side state instead of trusting the client copy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/_components/ChatBot/actions.ts` around lines 135 - 155, The code
currently trusts client-sent assistant turns by building modelMessages from
messages filtered for role === "user" || "assistant"; change this to only accept
server-trusted user turns: update the filter to (m): m is UIMessage & { role:
"user" } => m.role === "user" (and remove mapping of assistant role), and if you
need assistant history rehydrate it from server-side conversation storage (not
from the incoming messages) before composing modelMessages; reference
modelMessages, messages, and UIMessage when making the change.

85-132: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make retrieval best-effort instead of failing the entire chat.

Right now any HuggingFace or Supabase hiccup aborts the request before streaming starts. On a public chat endpoint, Lines 85-132 should fall back to context = "" so SOLARIS can still answer or gracefully say it lacks context. Also default the no-documents case to an empty string instead of propagating undefined.

Proposed fix
-    const hfRes = await fetch(
-      "https://router.huggingface.co/hf-inference/models/sentence-transformers/all-MiniLM-L6-v2/pipeline/feature-extraction",
-      {
-        body: JSON.stringify({
-          inputs: [query],
-          options: { wait_for_model: true },
-        }),
-        headers: {
-          Authorization: `Bearer ${huggingFaceApiKey}`,
-          "Content-Type": "application/json",
-        },
-        method: "POST",
-        signal: AbortSignal.timeout(8000),
-      },
-    );
-
-    if (!hfRes.ok) {
-      throw new Error(`HF Error: ${hfRes.statusText}`);
-    }
-
-    const hfData = (await hfRes.json()) as number[] | number[][];
-    const embedding = Array.isArray(hfData[0]) ? hfData[0] : hfData;
-
-    if (embedding?.length !== 384) {
-      throw new Error("Failed to generate a valid 384-dimensional embedding");
-    }
-
-    // 2. Search Supabase for context
-    const { data: documents, error: searchError } = (await supabase.rpc(
-      "match_documents",
-      {
-        match_count: 5,
-        match_threshold: 0.1,
-        query_embedding: embedding,
-      },
-    )) as {
-      data: { content: string }[] | null;
-      error: { message: string } | null;
-    };
-
-    if (searchError) {
-      throw new Error(`Supabase Error: ${searchError.message}`);
-    }
-
-    const context = (documents as { content: string }[])
-      ?.map((doc) => doc.content)
-      .join("\n\n");
+    let context = "";
+
+    try {
+      const hfRes = await fetch(
+        "https://router.huggingface.co/hf-inference/models/sentence-transformers/all-MiniLM-L6-v2/pipeline/feature-extraction",
+        {
+          body: JSON.stringify({
+            inputs: [query],
+            options: { wait_for_model: true },
+          }),
+          headers: {
+            Authorization: `Bearer ${huggingFaceApiKey}`,
+            "Content-Type": "application/json",
+          },
+          method: "POST",
+          signal: AbortSignal.timeout(8000),
+        },
+      );
+
+      if (!hfRes.ok) {
+        throw new Error(`HF Error: ${hfRes.statusText}`);
+      }
+
+      const hfData = (await hfRes.json()) as number[] | number[][];
+      const embedding = Array.isArray(hfData[0]) ? hfData[0] : hfData;
+
+      if (embedding?.length !== 384) {
+        throw new Error("Failed to generate a valid 384-dimensional embedding");
+      }
+
+      const { data: documents, error: searchError } = (await supabase.rpc(
+        "match_documents",
+        {
+          match_count: 5,
+          match_threshold: 0.1,
+          query_embedding: embedding,
+        },
+      )) as {
+        data: { content: string }[] | null;
+        error: { message: string } | null;
+      };
+
+      if (searchError) {
+        throw new Error(`Supabase Error: ${searchError.message}`);
+      }
+
+      context = documents?.map((doc) => doc.content).join("\n\n") ?? "";
+    } catch (err) {
+      console.error("Chat retrieval error:", err);
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/_components/ChatBot/actions.ts` around lines 85 - 132, Change the
strict failure behavior in the embedding and DB lookup flow so HF/Supabase
issues become best-effort: wrap the HuggingFace fetch (hfRes/hfData/embedding)
and the supabase.rpc("match_documents") call (searchError/documents) in
try/catch blocks and on any error or invalid embedding length set context = ""
(do not throw); also ensure the no-documents case defaults to an empty string by
mapping documents safely (e.g., (documents ?? [])...) so context is always a
string and the chat can still stream without surrounding failures.
src/app/api/chat/route.ts (1)

10-15: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not return exception messages and stacks from /api/chat.

This public endpoint currently exposes internal error text and stack traces to any caller. Log server-side, but return a generic 500 body.

Proposed fix
   } catch (err) {
     // eslint-disable-next-line no-console
     console.error("Chat API error:", err);
-    return new Response(
-      `Internal server error: ${err instanceof Error ? err.message : String(err)}\n${err instanceof Error ? err.stack : ""}`,
-      { status: 500 },
-    );
+    return new Response("Internal server error", { status: 500 });
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/api/chat/route.ts` around lines 10 - 15, The catch block in
src/app/api/chat/route.ts currently returns the raw error message and stack to
clients; instead, keep the existing server-side logging (console.error(err)) but
change the Response body to a generic message (e.g., "Internal server error")
and preserve the 500 status; do not include err.message or err.stack. Locate the
try/catch around the chat route handler (the catch uses the variable err and
constructs a new Response) and replace the interpolated response body with a
fixed string while leaving the logging intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/_components/ChatBot/actions.ts`:
- Around line 10-13: The createOpenAI client is created with raw process.env
values (see openrouter and other createOpenAI usages), causing missing API keys
to surface as runtime 500s; add explicit validation that
process.env.OPENROUTER_API_KEY (and any other provider env vars used where
createOpenAI is called) is present and non-empty before calling createOpenAI,
and if missing throw a clear startup error (or process.exit(1)) with a
descriptive message so the app fails fast rather than erroring later in
requests.

---

Duplicate comments:
In `@src/app/_components/ChatBot/actions.ts`:
- Around line 135-155: The code currently trusts client-sent assistant turns by
building modelMessages from messages filtered for role === "user" ||
"assistant"; change this to only accept server-trusted user turns: update the
filter to (m): m is UIMessage & { role: "user" } => m.role === "user" (and
remove mapping of assistant role), and if you need assistant history rehydrate
it from server-side conversation storage (not from the incoming messages) before
composing modelMessages; reference modelMessages, messages, and UIMessage when
making the change.
- Around line 85-132: Change the strict failure behavior in the embedding and DB
lookup flow so HF/Supabase issues become best-effort: wrap the HuggingFace fetch
(hfRes/hfData/embedding) and the supabase.rpc("match_documents") call
(searchError/documents) in try/catch blocks and on any error or invalid
embedding length set context = "" (do not throw); also ensure the no-documents
case defaults to an empty string by mapping documents safely (e.g., (documents
?? [])...) so context is always a string and the chat can still stream without
surrounding failures.

In `@src/app/_components/ChatBot/ChatPanel.tsx`:
- Around line 227-233: The suggestion button currently calls sendMessage
directly and can fire concurrent requests; update the onClick handler and
rendering to respect the isLoading flag (from component state/props) so clicks
are ignored when isLoading is true: either early-return from the onClick (check
isLoading before calling sendMessage) and/or set the button's disabled attribute
when isLoading, keeping the same className (styles.suggestionButton) and
preserving the payload ({ text: s }) passed to sendMessage; reference the
sendMessage function and the isLoading variable in the ChatPanel component to
locate where to add the guard.

In `@src/app/api/chat/route.ts`:
- Around line 10-15: The catch block in src/app/api/chat/route.ts currently
returns the raw error message and stack to clients; instead, keep the existing
server-side logging (console.error(err)) but change the Response body to a
generic message (e.g., "Internal server error") and preserve the 500 status; do
not include err.message or err.stack. Locate the try/catch around the chat route
handler (the catch uses the variable err and constructs a new Response) and
replace the interpolated response body with a fixed string while leaving the
logging intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 333ff2e7-34ab-4322-a115-f6532755bc36

📥 Commits

Reviewing files that changed from the base of the PR and between d471c90 and 921b1ab.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (9)
  • package.json
  • src/app/_components/ChatBot/ChatAvatar.tsx
  • src/app/_components/ChatBot/ChatBot.module.scss
  • src/app/_components/ChatBot/ChatBot.tsx
  • src/app/_components/ChatBot/ChatPanel.tsx
  • src/app/_components/ChatBot/ChatTrigger.tsx
  • src/app/_components/ChatBot/actions.ts
  • src/app/api/chat/route.ts
  • src/proxy.ts
✅ Files skipped from review due to trivial changes (1)
  • package.json

Comment thread src/app/_components/ChatBot/actions.ts
Comment thread src/app/_components/ChatBot/ChatAvatar.tsx Outdated
Comment thread src/app/api/chat/route.ts
Comment thread src/app/_components/ChatBot/ChatPanel.tsx Outdated
Comment thread src/proxy.ts
Comment thread src/app/_components/ChatBot/ChatPanel.tsx Outdated
Comment thread src/app/_components/ChatBot/actions.ts Outdated
Comment thread src/app/_components/ChatBot/actions.ts Outdated
Comment thread src/app/_components/ChatBot/actions.ts Outdated
Copy link
Copy Markdown
Contributor

@justin-phxm justin-phxm left a comment

Choose a reason for hiding this comment

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

almost

Comment thread src/app/_components/ChatBot/actions.ts
@justin-phxm
Copy link
Copy Markdown
Contributor

Will approve after setting up Supabase

Copy link
Copy Markdown

@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: 9

♻️ Duplicate comments (1)
src/app/_components/ChatBot/ChatPanel.tsx (1)

246-252: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Prevent overlapping requests from suggestion chips.

Suggested-question clicks currently bypass the in-flight guard and can enqueue concurrent requests.

Proposed fix
           {SUGGESTED.map((s) => (
             <button
               className={styles.suggestionButton}
+              disabled={isLoading}
               key={s}
               onClick={() => {
+                if (isLoading) return;
                 void sendMessage({ text: s });
               }}
             >
               {s}
             </button>
           ))}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/_components/ChatBot/ChatPanel.tsx` around lines 246 - 252, The
suggestion chip click currently calls sendMessage({ text: s }) directly and can
bypass the UI's in-flight guard; update the onClick for the suggestion button
(component using styles.suggestionButton and variable s) to first check the same
in-flight/sending flag used by the chat (e.g., isSending, isStreaming or the
state that sendMessage consults) and return early if a request is active, and
also set the button to disabled/visually indicate disabled while that flag is
true so clicks cannot enqueue concurrent requests; ensure you reuse the existing
sendMessage guard/state rather than creating a new one.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/ingest.py`:
- Around line 62-67: The code is embedding PII (schoolEmail and linkedIn) into
the RAG content string; remove or redact those fields before creating the
searchable chunk. Specifically, stop using member.get('schoolEmail', '') and
member.get('linkedIn', '') in the content construction (the `email`, `linkedin`,
and `content` variables), and instead either omit them or replace them with a
non-identifying placeholder such as "Contact: redacted" or "LinkedIn: redacted"
in the `content` string so no personal contact data is sent to `/api/chat` or
persisted in embeddings.
- Line 26: The global psycopg2 connection created by conn =
psycopg2.connect(db_url) and used in ingest() can leave the transaction aborted
and the connection/cursor unclosed on exceptions; change ingest() to manage the
connection and cursor lifecycle per operation using context managers (with
psycopg2.connect(...) as conn and with conn.cursor() as cur) or explicitly
open/close them inside try/finally, and add try/except around DB writes to call
conn.rollback() on error and conn.commit() only on success; update references to
the global conn variable in ingest() to use the local managed connection and
ensure cur.close()/conn.close() always run.

In `@scripts/main.py`:
- Line 61: The summary print currently reports the number of ingested documents
using len(data) but cleaning drops documents so it should report the
scraped/ingested count using the cleaned result; update the print call that
references data to use cleaned_data (or the appropriate variable holding
post-cleaning documents) so the message reflects the actual number of documents
after cleaning (ensure to update the f-string in the print that currently reads
print(f"Documents Processed:  {len(data):7d}") to reference len(cleaned_data) or
equivalent).

In `@scripts/requirements.txt`:
- Around line 1-5: The requirements file currently lists unpinned packages
(requests, langchain-text-splitters, sentence-transformers, psycopg2-binary,
python-dotenv); update scripts/requirements.txt to pin each package to a
specific, tested version (or switch to a constraints/lock file) to ensure
reproducible ingestion runs—e.g., add exact versions for requests,
langchain-text-splitters, sentence-transformers, psycopg2-binary and
python-dotenv or reference a constraints.txt produced by pip-compile; keep
package names unchanged so the installer behavior is identical except for fixed
versions.

In `@scripts/scrape.py`:
- Line 5: The file contains a hardcoded credential in the API_KEY variable;
remove the literal value and load the key from a secure source (e.g., read
os.environ["FIRECRAWL_API_KEY"] or use a configurable secrets manager) wherever
API_KEY is used, update code that references API_KEY to expect the
environment/config value, add guidance to deployment/README and CI to provide
FIRECRAWL_API_KEY, and ensure the leaked key is revoked/rotated out of the
provider immediately.
- Around line 29-42: requests.post(...) in scripts/scrape.py can hang and
response.json()/data["data"]["markdown"] can fail on non-2xx or invalid
responses; add a timeout to the requests.post call and check
response.status_code (or call response.raise_for_status()) before parsing, then
guard access to data["data"]["markdown"] with presence checks and handle JSON
decode errors (catch json.JSONDecodeError or
requests.exceptions.JSONDecodeError) and network exceptions
(requests.Timeout/requests.RequestException) to return or log a clear error;
update the code around the requests.post invocation, the response variable
usage, and the downstream data["data"]["markdown"] access to implement these
checks and exception handling.

In `@src/app/_components/ChatBot/actions.ts`:
- Around line 16-19: The current Supabase client creation silently falls back
from process.env.SUPABASE_SERVICE_ROLE_KEY to the anon key which can cause
permission errors for RPCs like match_documents; update the startup logic around
createClient/supabase to validate presence of SUPABASE_SERVICE_ROLE_KEY and
either (a) throw a clear error or (b) at minimum log a warning indicating
fallback to anon key and potential permission issues (include
env.NEXT_PUBLIC_SUPABASE_URL, the missing process.env.SUPABASE_SERVICE_ROLE_KEY,
and env.NEXT_PUBLIC_SUPABASE_ANON_KEY in the message) so operators see the cause
immediately.

In `@src/app/_components/ChatBot/ChatPanel.tsx`:
- Around line 190-233: The chat message container in ChatPanel.tsx isn't exposed
to screen readers—wrap or annotate the messages container to be an ARIA live
region so incoming assistant messages are announced; specifically, add ARIA
attributes (e.g., aria-live="polite" and aria-atomic="false", and optionally
role="log" or role="status") to the div with
className={styles.messagesContainer} (the ChatPanel component), and ensure
dynamic elements like the assistant Message entries (rendered by the Message
component) and the TypingDots indicator don't override or conflict with the
live-region semantics so screen readers announce new assistant messages
appropriately.

In `@src/app/api/chat/route.ts`:
- Around line 13-16: The Response in src/app/api/chat/route.ts currently returns
err.message and err.stack to the client (the new Response call in the exported
route handler), leaking internal details; change the HTTP error response to
return only a generic message like "Internal server error" with status 500 and
remove any inclusion of err.message/err.stack from the response body, and
instead log the full error server-side via the existing logger (or
console.error) inside the same catch block so debugging information is retained
internally but not exposed to clients.

---

Duplicate comments:
In `@src/app/_components/ChatBot/ChatPanel.tsx`:
- Around line 246-252: The suggestion chip click currently calls sendMessage({
text: s }) directly and can bypass the UI's in-flight guard; update the onClick
for the suggestion button (component using styles.suggestionButton and variable
s) to first check the same in-flight/sending flag used by the chat (e.g.,
isSending, isStreaming or the state that sendMessage consults) and return early
if a request is active, and also set the button to disabled/visually indicate
disabled while that flag is true so clicks cannot enqueue concurrent requests;
ensure you reuse the existing sendMessage guard/state rather than creating a new
one.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7b7fd472-b056-4bab-bc52-75ec7c6a06ef

📥 Commits

Reviewing files that changed from the base of the PR and between 860d0ae and e979de5.

⛔ Files ignored due to path filters (3)
  • public/assets/HeliosSideview.png is excluded by !**/*.png
  • public/assets/Logo.png is excluded by !**/*.png
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (18)
  • .gitignore
  • package.json
  • prisma/schema.prisma
  • scripts/clean.py
  • scripts/ingest.py
  • scripts/main.py
  • scripts/requirements.txt
  • scripts/scrape.py
  • src/app/_components/ChatBot/ChatAvatar.tsx
  • src/app/_components/ChatBot/ChatBot.module.scss
  • src/app/_components/ChatBot/ChatBot.tsx
  • src/app/_components/ChatBot/ChatPanel.tsx
  • src/app/_components/ChatBot/ChatTrigger.tsx
  • src/app/_components/ChatBot/actions.ts
  • src/app/api/chat/route.ts
  • src/app/layout.tsx
  • src/proxy.ts
  • src/server/api/trpc.ts
✅ Files skipped from review due to trivial changes (1)
  • .gitignore

Comment thread scripts/ingest.py Outdated
Comment thread scripts/ingest.py Outdated
Comment thread scripts/main.py Outdated
Comment thread scripts/requirements.txt Outdated
Comment thread scripts/scrape.py Outdated
Comment thread scripts/scrape.py Outdated
Comment thread src/app/_components/ChatBot/actions.ts
Comment thread src/app/_components/ChatBot/ChatPanel.tsx Outdated
Comment thread src/app/api/chat/route.ts Outdated
- Implemented ChatBot component with user interface for chat interactions.
- Added styles for chat interface, including message bubbles, buttons, and avatars.
- Integrated chat API for handling messages and responses using OpenAI and Supabase.
- Included typing indicators and suggested questions for user engagement.
@VyapakBansal
Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

Copilot AI and others added 2 commits May 23, 2026 19:02
Co-authored-by: VyapakBansal <167020115+VyapakBansal@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented May 23, 2026

@copilot resolve the merge conflicts in this pull request

Conflicts are resolved and merged from origin/main in commit f3c21e9 (with follow-up provider placement fix in a212f6a).

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • checkpoint.prisma.io
    • Triggering command: /opt/hostedtoolcache/node/24.15.0/x64/bin/node /opt/hostedtoolcache/node/24.15.0/x64/bin/node /home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/prisma/build/child {&#34;product&#34;:&#34;prisma&#34;,&#34;version&#34;:&#34;6.19.3&#34;,&#34;cli_install_type&#34;:&#34;local&#34;,&#34;information&#34;:&#34;&#34;,&#34;local_timestamp&#34;:&#34;2026-05-23T19:01:29Z&#34;,&#34;project_hash&#34;:&#34;90dbab93&#34;,&#34;cli_path&#34;:&#34;/home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/@prisma/client/n (dns block)
    • Triggering command: /opt/hostedtoolcache/node/24.15.0/x64/bin/node /opt/hostedtoolcache/node/24.15.0/x64/bin/node /home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/prisma/build/child {&#34;product&#34;:&#34;prisma&#34;,&#34;version&#34;:&#34;6.19.3&#34;,&#34;cli_install_type&#34;:&#34;local&#34;,&#34;information&#34;:&#34;&#34;,&#34;local_timestamp&#34;:&#34;2026-05-23T19:01:31Z&#34;,&#34;project_hash&#34;:&#34;90dbab93&#34;,&#34;cli_path&#34;:&#34;/home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/.bin/prisma&#34;,&#34;cl (dns block)
    • Triggering command: /opt/hostedtoolcache/node/24.15.0/x64/bin/node /opt/hostedtoolcache/node/24.15.0/x64/bin/node /home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/prisma/build/child {&#34;product&#34;:&#34;prisma&#34;,&#34;version&#34;:&#34;6.19.3&#34;,&#34;cli_install_type&#34;:&#34;local&#34;,&#34;information&#34;:&#34;&#34;,&#34;local_timestamp&#34;:&#34;2026-05-23T19:02:44Z&#34;,&#34;project_hash&#34;:&#34;90dbab93&#34;,&#34;cli_path&#34;:&#34;/home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/.bin/prisma&#34;,&#34;cl (dns block)
  • fonts.googleapis.com
    • Triggering command: /opt/hostedtoolcache/node/24.15.0/x64/bin/node /opt/hostedtoolcache/node/24.15.0/x64/bin/node /home/REDACTED/work/Solar-Car-Website-Next/Solar-Car-Website-Next/node_modules/.bin/next build (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@promatty
Copy link
Copy Markdown
Member

i want u to fix ur merge conflicts w/o merging main and no ai

@promatty
Copy link
Copy Markdown
Member

by reverting to before
then fixing ur merge conflicts

@VyapakBansal VyapakBansal requested a review from promatty May 23, 2026 19:09
Copy link
Copy Markdown
Member

@promatty promatty left a comment

Choose a reason for hiding this comment

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

dont merge main

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