This commit is contained in:
mahyargdz
2025-06-08 17:00:17 +03:30
parent 9334e09ac6
commit 1b6139a80e
4 changed files with 718 additions and 636 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
VITE_TOKEN_NAME = 'dzone_token' VITE_TOKEN_NAME = 'dzone_token'
VITE_REFRESH_TOKEN_NAME = 'dzone_refresh_token' VITE_REFRESH_TOKEN_NAME = 'dzone_refresh_token'
# VITE_BASE_URL = 'https://api-dzone.danakcorp.com' # 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' VITE_SLUG_ID = 'slug_id'
+618 -548
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -111,3 +111,31 @@
transform: translateY(-4px); 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;
}
+70 -86
View File
@@ -1,4 +1,4 @@
import { useCallback, useRef, useState } from "react"; import { useCallback, useRef } from "react";
import { Socket } from "socket.io-client"; import { Socket } from "socket.io-client";
import { SOCKET_EVENTS } from "../constants"; import { SOCKET_EVENTS } from "../constants";
import { Message } from "../types"; import { Message } from "../types";
@@ -26,34 +26,11 @@ export const useSocketHandlers = ({
setCurrentSessionId, setCurrentSessionId,
isProcessing, isProcessing,
}: UseSocketHandlersProps) => { }: UseSocketHandlersProps) => {
// Keep track of the current streaming message // Keep track of the current bot message like in the JS version
const currentStreamingMessageRef = useRef<{ const botMessageRef = useRef<{
id: string; id: string;
text: string; text: string;
} | null>(null); } | 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(() => { const setupSocketHandlers = useCallback(() => {
if (!socket) return () => {}; if (!socket) return () => {};
@@ -112,6 +89,7 @@ export const useSocketHandlers = ({
const onChatJoined = (data: any) => { const onChatJoined = (data: any) => {
console.log("✅ Joined chat:", data); console.log("✅ Joined chat:", data);
addSystemMessage("به چت متصل شدید", "success"); addSystemMessage("به چت متصل شدید", "success");
setStatus("متصل و آماده ✅");
}; };
const onSessionError = (data: any) => { const onSessionError = (data: any) => {
@@ -125,22 +103,28 @@ export const useSocketHandlers = ({
// Message is already shown in UI when sent // Message is already shown in UI when sent
}; };
// Bot response streaming // Bot response streaming - following the JS implementation pattern
const onBotResponseStart = (data: any) => { const onBotResponseStart = (data: any) => {
console.log("🤖 Bot response starting:", data); console.log("🤖 Bot response starting:", data);
// Reset streaming text // Turn off typing indicator since we're starting streaming
setStreamingText(""); 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({ const newMessage = addMessage({
text: "", text: "",
isUser: false, isUser: false,
streaming: true, streaming: true,
}); });
// Store the message ID and initial text in ref // Store reference like in JS version
currentStreamingMessageRef.current = { botMessageRef.current = {
id: newMessage.id, id: newMessage.id,
text: "", text: "",
}; };
@@ -149,32 +133,43 @@ export const useSocketHandlers = ({
}; };
const onBotResponseChunk = (data: any) => { const onBotResponseChunk = (data: any) => {
console.log( console.log("🤖 Bot response chunk received:", data);
"🤖 Bot response chunk received, data length:",
data?.data?.length || 0
);
if (data.data && currentStreamingMessageRef.current) { // If no bot message exists, create one (in case bot_response_start was missed)
try { if (!botMessageRef.current && data?.data) {
// Update the text in our ref and state console.log("⚠️ Creating bot message from chunk (missing start event)");
const newText = currentStreamingMessageRef.current.text + data.data;
currentStreamingMessageRef.current.text = newText;
// Update state to trigger re-render // Turn off typing indicator since we're starting streaming
setStreamingText(newText); setIsTyping(false);
// Update the message content const newMessage = addMessage({
updateStreamingMessage( text: "",
currentStreamingMessageRef.current.id, isUser: false,
newText streaming: true,
); });
} catch (error) {
console.error("Error processing bot response chunk:", error); 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 { } else {
console.warn("Received chunk but no active streaming message found", { console.warn("Received chunk but no active bot message found", {
hasData: !!data.data, hasBotMessage: !!botMessageRef.current,
hasCurrentMessage: !!currentStreamingMessageRef.current, hasData: !!data?.data,
data, data,
}); });
} }
@@ -183,45 +178,28 @@ export const useSocketHandlers = ({
const onBotResponseEnd = (data: any) => { const onBotResponseEnd = (data: any) => {
console.log("🤖 Bot response ended:", data); console.log("🤖 Bot response ended:", data);
if (currentStreamingMessageRef.current) { if (botMessageRef.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);
// Finalize the message by removing streaming flag // Finalize the message by removing streaming flag
setTimeout(() => { updateMessage(botMessageRef.current.id, {
updateMessage(messageId, { streaming: false,
streaming: false, });
});
}, 100);
// Clear the ref and state console.log(`Finalized message ${botMessageRef.current.id}`);
setStreamingText("");
currentStreamingMessageRef.current = null; // Clear the reference
botMessageRef.current = null;
} }
// Reset all states to allow user to send messages again
setIsTyping(false); setIsTyping(false);
setIsProcessing(false); setIsProcessing(false);
console.log("✅ Bot response ended - user can send messages again");
}; };
const onBotResponse = (data: any) => { const onBotResponse = (data: any) => {
console.log("🤖 Bot response (non-streaming):", data); console.log("🤖 Bot response (non-streaming):", data);
if (data.message && data.message.content) { if (data.message && data.message.content) {
console.log(
`Adding non-streaming message: "${data.message.content.substring(
0,
50
)}${data.message.content.length > 50 ? "..." : ""}"`
);
addMessage({ addMessage({
text: data.message.content, text: data.message.content,
isUser: false, isUser: false,
@@ -231,8 +209,10 @@ export const useSocketHandlers = ({
console.warn("Received bot_response event with no content", data); console.warn("Received bot_response event with no content", data);
} }
// Reset all states to allow user to send messages again
setIsTyping(false); setIsTyping(false);
setIsProcessing(false); setIsProcessing(false);
console.log("✅ Bot response completed - user can send messages again");
}; };
// Typing events // Typing events
@@ -265,15 +245,21 @@ export const useSocketHandlers = ({
const onError = (data: any) => { const onError = (data: any) => {
console.error("❌ Socket.IO error:", data); console.error("❌ Socket.IO error:", data);
addSystemMessage(data.message || "خطا در پردازش", "error"); addSystemMessage(data.message || "خطا در پردازش", "error");
// Reset states on error to allow user to try again
setIsProcessing(false); setIsProcessing(false);
setIsTyping(false); setIsTyping(false);
console.log("❌ Error occurred - reset processing state");
}; };
const onMessageError = (data: any) => { const onMessageError = (data: any) => {
console.error("❌ Message error:", data); console.error("❌ Message error:", data);
addSystemMessage(data.message || "خطا در ارسال پیام", "error"); addSystemMessage(data.message || "خطا در ارسال پیام", "error");
// Reset states on error to allow user to try again
setIsProcessing(false); setIsProcessing(false);
setIsTyping(false); setIsTyping(false);
console.log("❌ Message error - reset processing state");
}; };
// Register event handlers // Register event handlers
@@ -321,9 +307,8 @@ export const useSocketHandlers = ({
socket.off(SOCKET_EVENTS.MESSAGE_ERROR, onMessageError); socket.off(SOCKET_EVENTS.MESSAGE_ERROR, onMessageError);
socket.off(SOCKET_EVENTS.WEBSOCKET_ERROR, onError); socket.off(SOCKET_EVENTS.WEBSOCKET_ERROR, onError);
// Clear streaming message ref on cleanup // Clear bot message reference on cleanup
currentStreamingMessageRef.current = null; botMessageRef.current = null;
setStreamingText("");
}; };
}, [ }, [
socket, socket,
@@ -334,10 +319,9 @@ export const useSocketHandlers = ({
updateMessage, updateMessage,
addSystemMessage, addSystemMessage,
setCurrentSessionId, 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 // Helper function to format text with markdown-like syntax