diff --git a/apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx b/apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx index 2547afc0db0..8fab0e3fd72 100644 --- a/apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx +++ b/apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx @@ -102,6 +102,7 @@ function CustomChatContentLoggedIn(props: { message: messageToSend.content.find((x) => x.type === "text")?.text ?? "", conversationId: sessionId, + source: "dashboard-support", }; const apiUrl = process.env.NEXT_PUBLIC_SIWA_URL; const response = await fetch(`${apiUrl}/v1/chat`, { diff --git a/apps/portal/src/app/Header.tsx b/apps/portal/src/app/Header.tsx index 35f4b5f11ac..f4a2b0bf5d3 100644 --- a/apps/portal/src/app/Header.tsx +++ b/apps/portal/src/app/Header.tsx @@ -10,9 +10,9 @@ import { } from "@/components/ui/dropdown-menu"; import clsx from "clsx"; import { - BotIcon, ChevronDownIcon, MenuIcon, + MessageCircleIcon, TableOfContentsIcon, } from "lucide-react"; import Link from "next/link"; @@ -222,12 +222,11 @@ export function Header() {
@@ -254,7 +253,7 @@ export function Header() { className="p-2" onClick={() => router.push("/chat")} > - + + diff --git a/apps/portal/src/components/AI/api.ts b/apps/portal/src/components/AI/api.ts index 247063ffdc0..4024d693967 100644 --- a/apps/portal/src/components/AI/api.ts +++ b/apps/portal/src/components/AI/api.ts @@ -11,6 +11,7 @@ export const getChatResponse = async ( const payload = { message: userMessage, conversationId: sessionId, + source: "portal", }; const response = await fetch(`${apiUrl}/v1/chat`, { method: "POST", @@ -41,3 +42,31 @@ export const getChatResponse = async ( return null; } }; + +export const sendFeedback = async ( + conversationId: string, + feedbackRating: 1 | -1, +) => { + try { + const response = await fetch(`${apiUrl}/v1/chat/feedback`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-service-api-key": serviceKey, + }, + body: JSON.stringify({ conversationId, feedbackRating }), + }); + + if (!response.ok) { + const error = await response.text(); + throw new Error(`Failed to send feedback: ${response.status} - ${error}`); + } + return true; + } catch (error) { + console.error( + "Feedback API error:", + error instanceof Error ? error.message : "Unknown error", + ); + return false; + } +}; diff --git a/apps/portal/src/components/AI/chat.tsx b/apps/portal/src/components/AI/chat.tsx index a72d8521b7a..a3c6aabdc90 100644 --- a/apps/portal/src/components/AI/chat.tsx +++ b/apps/portal/src/components/AI/chat.tsx @@ -5,7 +5,8 @@ import { LoadingDots } from "@/components/ui/LoadingDots"; import { Button } from "@/components/ui/button"; import { AutoResizeTextarea } from "@/components/ui/textarea"; import { cn } from "@/lib/utils"; -import { ArrowUpIcon, BotIcon } from "lucide-react"; +import { MessageCircleIcon } from "lucide-react"; +import { ArrowUpIcon, ThumbsDownIcon, ThumbsUpIcon } from "lucide-react"; import { usePostHog } from "posthog-js/react"; import { type ChangeEvent, @@ -15,13 +16,14 @@ import { useRef, useState, } from "react"; -import { getChatResponse } from "./api"; +import { getChatResponse, sendFeedback } from "./api"; interface Message { id: string; role: "user" | "assistant"; content: string; isLoading?: boolean; + feedback?: 1 | -1; } const predefinedPrompts = [ @@ -36,7 +38,7 @@ function ChatEmptyState({ }: { onPromptClick: (prompt: string) => void }) { return (
- +

How can I help you
@@ -153,6 +155,21 @@ export function Chat() { } }; + const handleFeedback = async (messageId: string, feedback: 1 | -1) => { + if (!conversationId) return; // Don't send feedback if no conversation + + try { + await sendFeedback(conversationId, feedback); + setMessages((prevMessages) => + prevMessages.map((msg) => + msg.id === messageId ? { ...msg, feedback } : msg, + ), + ); + } catch (_e) { + // Optionally handle error + } + }; + return (
) : ( - + <> + + {message.role === "assistant" && !message.isLoading && ( +
+ {!message.feedback && ( + <> + + + + )} +
+ )} + )}

diff --git a/apps/portal/src/icons/siwa-icon.png b/apps/portal/src/icons/siwa-icon.png new file mode 100644 index 00000000000..60b8027bd42 Binary files /dev/null and b/apps/portal/src/icons/siwa-icon.png differ