chat bot
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
VITE_TOKEN_NAME = 'dzone_token'
|
||||
VITE_REFRESH_TOKEN_NAME = 'dzone_refresh_token'
|
||||
# VITE_BASE_URL = 'https://api-dzone.danakcorp.com'
|
||||
VITE_BASE_URL = 'https://nhrq9m1d-4000.eun1.devtunnels.ms'
|
||||
VITE_BASE_URL = 'http://localhost:4000'
|
||||
|
||||
VITE_SLUG_ID = 'slug_id'
|
||||
+619
-549
File diff suppressed because it is too large
Load Diff
@@ -111,3 +111,31 @@
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Typing dots for streaming messages */
|
||||
.typing-dots {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.typing-dots span {
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
margin: 0 1px;
|
||||
background-color: #3b82f6;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
animation: typing-dot 1.2s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.typing-dots span:nth-child(1) {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
.typing-dots span:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.typing-dots span:nth-child(3) {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useRef, useState } from "react";
|
||||
import { useCallback, useRef } from "react";
|
||||
import { Socket } from "socket.io-client";
|
||||
import { SOCKET_EVENTS } from "../constants";
|
||||
import { Message } from "../types";
|
||||
@@ -26,34 +26,11 @@ export const useSocketHandlers = ({
|
||||
setCurrentSessionId,
|
||||
isProcessing,
|
||||
}: UseSocketHandlersProps) => {
|
||||
// Keep track of the current streaming message
|
||||
const currentStreamingMessageRef = useRef<{
|
||||
// Keep track of the current bot message like in the JS version
|
||||
const botMessageRef = useRef<{
|
||||
id: string;
|
||||
text: string;
|
||||
} | null>(null);
|
||||
const [streamingText, setStreamingText] = useState<string>("");
|
||||
|
||||
// Simple function to update streaming message content
|
||||
const updateStreamingMessage = (id: string, text: string) => {
|
||||
console.log(
|
||||
`Updating streaming message ${id} with ${text.length} characters`
|
||||
);
|
||||
|
||||
// Update the state for React
|
||||
updateMessage(id, { text });
|
||||
|
||||
// Also try direct DOM update as a fallback
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const element = document.getElementById(`message-${id}`);
|
||||
if (element) {
|
||||
element.innerHTML = formatText(text);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Error updating DOM directly:", e);
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
|
||||
const setupSocketHandlers = useCallback(() => {
|
||||
if (!socket) return () => {};
|
||||
@@ -112,6 +89,7 @@ export const useSocketHandlers = ({
|
||||
const onChatJoined = (data: any) => {
|
||||
console.log("✅ Joined chat:", data);
|
||||
addSystemMessage("به چت متصل شدید", "success");
|
||||
setStatus("متصل و آماده ✅");
|
||||
};
|
||||
|
||||
const onSessionError = (data: any) => {
|
||||
@@ -125,22 +103,28 @@ export const useSocketHandlers = ({
|
||||
// Message is already shown in UI when sent
|
||||
};
|
||||
|
||||
// Bot response streaming
|
||||
// Bot response streaming - following the JS implementation pattern
|
||||
const onBotResponseStart = (data: any) => {
|
||||
console.log("🤖 Bot response starting:", data);
|
||||
|
||||
// Reset streaming text
|
||||
setStreamingText("");
|
||||
// Turn off typing indicator since we're starting streaming
|
||||
setIsTyping(false);
|
||||
|
||||
// Create a new message and store its ID
|
||||
// Clear any existing bot message first
|
||||
if (botMessageRef.current) {
|
||||
console.log("⚠️ Clearing existing bot message before starting new one");
|
||||
botMessageRef.current = null;
|
||||
}
|
||||
|
||||
// Create new bot message with streaming flag
|
||||
const newMessage = addMessage({
|
||||
text: "",
|
||||
isUser: false,
|
||||
streaming: true,
|
||||
});
|
||||
|
||||
// Store the message ID and initial text in ref
|
||||
currentStreamingMessageRef.current = {
|
||||
// Store reference like in JS version
|
||||
botMessageRef.current = {
|
||||
id: newMessage.id,
|
||||
text: "",
|
||||
};
|
||||
@@ -149,32 +133,43 @@ export const useSocketHandlers = ({
|
||||
};
|
||||
|
||||
const onBotResponseChunk = (data: any) => {
|
||||
console.log(
|
||||
"🤖 Bot response chunk received, data length:",
|
||||
data?.data?.length || 0
|
||||
);
|
||||
console.log("🤖 Bot response chunk received:", data);
|
||||
|
||||
if (data.data && currentStreamingMessageRef.current) {
|
||||
try {
|
||||
// Update the text in our ref and state
|
||||
const newText = currentStreamingMessageRef.current.text + data.data;
|
||||
currentStreamingMessageRef.current.text = newText;
|
||||
// If no bot message exists, create one (in case bot_response_start was missed)
|
||||
if (!botMessageRef.current && data?.data) {
|
||||
console.log("⚠️ Creating bot message from chunk (missing start event)");
|
||||
|
||||
// Update state to trigger re-render
|
||||
setStreamingText(newText);
|
||||
// Turn off typing indicator since we're starting streaming
|
||||
setIsTyping(false);
|
||||
|
||||
// Update the message content
|
||||
updateStreamingMessage(
|
||||
currentStreamingMessageRef.current.id,
|
||||
newText
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error processing bot response chunk:", error);
|
||||
}
|
||||
const newMessage = addMessage({
|
||||
text: "",
|
||||
isUser: false,
|
||||
streaming: true,
|
||||
});
|
||||
|
||||
botMessageRef.current = {
|
||||
id: newMessage.id,
|
||||
text: "",
|
||||
};
|
||||
}
|
||||
|
||||
if (botMessageRef.current && data?.data) {
|
||||
// Accumulate text like in JS version
|
||||
botMessageRef.current.text += data.data;
|
||||
|
||||
// Update the message content
|
||||
updateMessage(botMessageRef.current.id, {
|
||||
text: botMessageRef.current.text,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`Updated message to length: ${botMessageRef.current.text.length}`
|
||||
);
|
||||
} else {
|
||||
console.warn("Received chunk but no active streaming message found", {
|
||||
hasData: !!data.data,
|
||||
hasCurrentMessage: !!currentStreamingMessageRef.current,
|
||||
console.warn("Received chunk but no active bot message found", {
|
||||
hasBotMessage: !!botMessageRef.current,
|
||||
hasData: !!data?.data,
|
||||
data,
|
||||
});
|
||||
}
|
||||
@@ -183,45 +178,28 @@ export const useSocketHandlers = ({
|
||||
const onBotResponseEnd = (data: any) => {
|
||||
console.log("🤖 Bot response ended:", data);
|
||||
|
||||
if (currentStreamingMessageRef.current) {
|
||||
// Make sure we have the final text
|
||||
const finalText = currentStreamingMessageRef.current.text;
|
||||
const messageId = currentStreamingMessageRef.current.id;
|
||||
|
||||
console.log(
|
||||
`Finalizing message ${messageId} with text length: ${finalText.length}`
|
||||
);
|
||||
|
||||
// Final update to the message content
|
||||
updateStreamingMessage(messageId, finalText);
|
||||
|
||||
if (botMessageRef.current) {
|
||||
// Finalize the message by removing streaming flag
|
||||
setTimeout(() => {
|
||||
updateMessage(messageId, {
|
||||
streaming: false,
|
||||
});
|
||||
}, 100);
|
||||
updateMessage(botMessageRef.current.id, {
|
||||
streaming: false,
|
||||
});
|
||||
|
||||
// Clear the ref and state
|
||||
setStreamingText("");
|
||||
currentStreamingMessageRef.current = null;
|
||||
console.log(`Finalized message ${botMessageRef.current.id}`);
|
||||
|
||||
// Clear the reference
|
||||
botMessageRef.current = null;
|
||||
}
|
||||
|
||||
// Reset all states to allow user to send messages again
|
||||
setIsTyping(false);
|
||||
setIsProcessing(false);
|
||||
console.log("✅ Bot response ended - user can send messages again");
|
||||
};
|
||||
|
||||
const onBotResponse = (data: any) => {
|
||||
console.log("🤖 Bot response (non-streaming):", data);
|
||||
|
||||
if (data.message && data.message.content) {
|
||||
console.log(
|
||||
`Adding non-streaming message: "${data.message.content.substring(
|
||||
0,
|
||||
50
|
||||
)}${data.message.content.length > 50 ? "..." : ""}"`
|
||||
);
|
||||
|
||||
addMessage({
|
||||
text: data.message.content,
|
||||
isUser: false,
|
||||
@@ -231,8 +209,10 @@ export const useSocketHandlers = ({
|
||||
console.warn("Received bot_response event with no content", data);
|
||||
}
|
||||
|
||||
// Reset all states to allow user to send messages again
|
||||
setIsTyping(false);
|
||||
setIsProcessing(false);
|
||||
console.log("✅ Bot response completed - user can send messages again");
|
||||
};
|
||||
|
||||
// Typing events
|
||||
@@ -265,15 +245,21 @@ export const useSocketHandlers = ({
|
||||
const onError = (data: any) => {
|
||||
console.error("❌ Socket.IO error:", data);
|
||||
addSystemMessage(data.message || "خطا در پردازش", "error");
|
||||
|
||||
// Reset states on error to allow user to try again
|
||||
setIsProcessing(false);
|
||||
setIsTyping(false);
|
||||
console.log("❌ Error occurred - reset processing state");
|
||||
};
|
||||
|
||||
const onMessageError = (data: any) => {
|
||||
console.error("❌ Message error:", data);
|
||||
addSystemMessage(data.message || "خطا در ارسال پیام", "error");
|
||||
|
||||
// Reset states on error to allow user to try again
|
||||
setIsProcessing(false);
|
||||
setIsTyping(false);
|
||||
console.log("❌ Message error - reset processing state");
|
||||
};
|
||||
|
||||
// Register event handlers
|
||||
@@ -321,9 +307,8 @@ export const useSocketHandlers = ({
|
||||
socket.off(SOCKET_EVENTS.MESSAGE_ERROR, onMessageError);
|
||||
socket.off(SOCKET_EVENTS.WEBSOCKET_ERROR, onError);
|
||||
|
||||
// Clear streaming message ref on cleanup
|
||||
currentStreamingMessageRef.current = null;
|
||||
setStreamingText("");
|
||||
// Clear bot message reference on cleanup
|
||||
botMessageRef.current = null;
|
||||
};
|
||||
}, [
|
||||
socket,
|
||||
@@ -334,10 +319,9 @@ export const useSocketHandlers = ({
|
||||
updateMessage,
|
||||
addSystemMessage,
|
||||
setCurrentSessionId,
|
||||
streamingText, // Add dependency to ensure handler is updated when streaming text changes
|
||||
]);
|
||||
|
||||
return { setupSocketHandlers, streamingText };
|
||||
return { setupSocketHandlers };
|
||||
};
|
||||
|
||||
// Helper function to format text with markdown-like syntax
|
||||
|
||||
Reference in New Issue
Block a user