Loading actions/chatbot.ts 0 → 100644 +6 −0 Changes for actions/chatbot.ts: 6 added lines, 0 removed lines. Original line number Diff line number Diff line 'use server'; export async function getAgentUrl(): Promise<string> { const agentUrl = process.env.NEXT_PUBLIC_MCP_BACKEND_URL; return agentUrl || 'http://192.168.5.241:30080'; } components/chat-widget.tsx +2 −1 Changes for components/chat-widget.tsx: 2 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import React, { useEffect, useRef, useState } from 'react'; import { useSession } from 'next-auth/react'; import { Button, Textarea } from '@nextui-org/react'; import { useHypoChat } from '@/hooks/useHypoChat'; // adjust to wherever you put the hook import { safeUUID } from '@/lib/uuid'; type ChatWidgetProps = { /** Distance of the launcher from the bottom of the screen, in px. Raise it on pages Loading @@ -17,7 +18,7 @@ export default function ChatWidget({ bottomOffset = 24 }: ChatWidgetProps) { // One conversation per page load, so the UI history and the server-side // memory reset together. Replace with a persisted ID if you store history. const [conversationId, setConversationId] = useState('default'); useEffect(() => setConversationId(crypto.randomUUID()), []); useEffect(() => setConversationId(safeUUID()), []); const { messages, send, stop, isStreaming, error } = useHypoChat(conversationId); Loading hooks/useHypoChat.ts +4 −2 Changes for hooks/useHypoChat.ts: 4 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -3,10 +3,10 @@ import { useCallback, useRef, useState } from 'react'; import { fetchEventSource } from '@microsoft/fetch-event-source'; import { getSession } from 'next-auth/react'; import { getAgentUrl } from '@/actions/chatbot'; export type Message = { role: 'user' | 'assistant'; content: string }; const API_URL = process.env.NEXT_PUBLIC_MCP_BACKEND_URL + '/customer-support-agent'; const WELCOME = "Welcome to HypO's AI Assistant! How can I help you today?"; class FatalError extends Error {} Loading Loading @@ -46,7 +46,9 @@ export function useHypoChat(conversationId = 'default') { abortRef.current = ctrl; try { await fetchEventSource(API_URL, { const agentUrl = await getAgentUrl(); const apiUrl = `${agentUrl}/customer-support-agent`; await fetchEventSource(apiUrl, { method: 'POST', signal: ctrl.signal, openWhenHidden: true, // don't abort/restart when the tab loses focus Loading lib/uuid.ts 0 → 100644 +15 −0 Changes for lib/uuid.ts: 15 added lines, 0 removed lines. Original line number Diff line number Diff line export function safeUUID(): string { if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { return crypto.randomUUID(); } if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') { // RFC 4122 v4 using getRandomValues (available on insecure origins too) const b = crypto.getRandomValues(new Uint8Array(16)); b[6] = (b[6] & 0x0f) | 0x40; b[8] = (b[8] & 0x3f) | 0x80; const h = Array.from(b, (x) => x.toString(16).padStart(2, '0')); return `${h.slice(0, 4).join('')}-${h.slice(4, 6).join('')}-${h.slice(6, 8).join('')}-${h.slice(8, 10).join('')}-${h.slice(10).join('')}`; } // last resort return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`; } Loading
actions/chatbot.ts 0 → 100644 +6 −0 Changes for actions/chatbot.ts: 6 added lines, 0 removed lines. Original line number Diff line number Diff line 'use server'; export async function getAgentUrl(): Promise<string> { const agentUrl = process.env.NEXT_PUBLIC_MCP_BACKEND_URL; return agentUrl || 'http://192.168.5.241:30080'; }
components/chat-widget.tsx +2 −1 Changes for components/chat-widget.tsx: 2 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import React, { useEffect, useRef, useState } from 'react'; import { useSession } from 'next-auth/react'; import { Button, Textarea } from '@nextui-org/react'; import { useHypoChat } from '@/hooks/useHypoChat'; // adjust to wherever you put the hook import { safeUUID } from '@/lib/uuid'; type ChatWidgetProps = { /** Distance of the launcher from the bottom of the screen, in px. Raise it on pages Loading @@ -17,7 +18,7 @@ export default function ChatWidget({ bottomOffset = 24 }: ChatWidgetProps) { // One conversation per page load, so the UI history and the server-side // memory reset together. Replace with a persisted ID if you store history. const [conversationId, setConversationId] = useState('default'); useEffect(() => setConversationId(crypto.randomUUID()), []); useEffect(() => setConversationId(safeUUID()), []); const { messages, send, stop, isStreaming, error } = useHypoChat(conversationId); Loading
hooks/useHypoChat.ts +4 −2 Changes for hooks/useHypoChat.ts: 4 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -3,10 +3,10 @@ import { useCallback, useRef, useState } from 'react'; import { fetchEventSource } from '@microsoft/fetch-event-source'; import { getSession } from 'next-auth/react'; import { getAgentUrl } from '@/actions/chatbot'; export type Message = { role: 'user' | 'assistant'; content: string }; const API_URL = process.env.NEXT_PUBLIC_MCP_BACKEND_URL + '/customer-support-agent'; const WELCOME = "Welcome to HypO's AI Assistant! How can I help you today?"; class FatalError extends Error {} Loading Loading @@ -46,7 +46,9 @@ export function useHypoChat(conversationId = 'default') { abortRef.current = ctrl; try { await fetchEventSource(API_URL, { const agentUrl = await getAgentUrl(); const apiUrl = `${agentUrl}/customer-support-agent`; await fetchEventSource(apiUrl, { method: 'POST', signal: ctrl.signal, openWhenHidden: true, // don't abort/restart when the tab loses focus Loading
lib/uuid.ts 0 → 100644 +15 −0 Changes for lib/uuid.ts: 15 added lines, 0 removed lines. Original line number Diff line number Diff line export function safeUUID(): string { if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { return crypto.randomUUID(); } if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') { // RFC 4122 v4 using getRandomValues (available on insecure origins too) const b = crypto.getRandomValues(new Uint8Array(16)); b[6] = (b[6] & 0x0f) | 0x40; b[8] = (b[8] & 0x3f) | 0x80; const h = Array.from(b, (x) => x.toString(16).padStart(2, '0')); return `${h.slice(0, 4).join('')}-${h.slice(4, 6).join('')}-${h.slice(6, 8).join('')}-${h.slice(8, 10).join('')}-${h.slice(10).join('')}`; } // last resort return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`; }