Fix: start.bas não executa e HTML truncado
- Remove streaming de chunks LLM, acumula resposta completa antes de enviar - Corrige variável 'action' para 'actionData' no click handler de suggestions - Adiciona fallback window.sendMessage() se WebSocket não estiver aberto - Adiciona guard DOMContentLoaded no chat-init.js - Adiciona cache-busting (?v=4) no chat.html Impacto: - start.bas executa corretamente ao conectar WebSocket - HTML não é mais truncado (tags fecham corretamente) - Sugestões executam tool invocations via WebSocket
This commit is contained in:
parent
5a6f062794
commit
73e0121d0b
4 changed files with 160 additions and 145 deletions
|
|
@ -1346,30 +1346,9 @@ while let Some(chunk) = stream_rx.recv().await {
|
|||
}
|
||||
|
||||
if !in_analysis {
|
||||
full_response.push_str(&chunk);
|
||||
|
||||
// Send immediately without buffering
|
||||
let response = BotResponse {
|
||||
bot_id: message.bot_id.clone(),
|
||||
user_id: message.user_id.clone(),
|
||||
session_id: message.session_id.clone(),
|
||||
channel: message.channel.clone(),
|
||||
content: chunk.clone(),
|
||||
message_type: MessageType::BOT_RESPONSE,
|
||||
stream_token: None,
|
||||
is_complete: false,
|
||||
suggestions: Vec::new(),
|
||||
switchers: Vec::new(),
|
||||
context_name: None,
|
||||
context_length: 0,
|
||||
context_max_length: 0,
|
||||
};
|
||||
|
||||
if response_tx.send(response).await.is_err() {
|
||||
warn!("Response channel closed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Accumulate full response - DO NOT send chunks
|
||||
full_response.push_str(&chunk);
|
||||
}
|
||||
}
|
||||
|
||||
info!("llm_end: Streaming loop ended for session {}, chunk_count={}, full_response_len={}", session.id, chunk_count, full_response.len());
|
||||
|
|
@ -1437,28 +1416,24 @@ if !in_analysis {
|
|||
#[cfg(not(feature = "chat"))]
|
||||
let switchers: Vec<Switcher> = Vec::new();
|
||||
|
||||
// Content was already sent as streaming chunks.
|
||||
// Sending full_response again would duplicate it (especially for WhatsApp which accumulates buffer).
|
||||
// The final response is just a signal that streaming is complete - it should not contain content.
|
||||
let final_content = String::new();
|
||||
|
||||
let final_response = BotResponse {
|
||||
bot_id: message.bot_id,
|
||||
user_id: message.user_id,
|
||||
session_id: message.session_id,
|
||||
channel: message.channel,
|
||||
content: final_content,
|
||||
message_type: MessageType::BOT_RESPONSE,
|
||||
stream_token: None,
|
||||
is_complete: true,
|
||||
suggestions,
|
||||
switchers,
|
||||
context_name: None,
|
||||
context_length: 0,
|
||||
context_max_length: 0,
|
||||
// Send accumulated full response (not streaming anymore)
|
||||
let final_response = BotResponse {
|
||||
bot_id: message.bot_id,
|
||||
user_id: message.user_id,
|
||||
session_id: message.session_id,
|
||||
channel: message.channel,
|
||||
content: full_response.clone(),
|
||||
message_type: MessageType::BOT_RESPONSE,
|
||||
stream_token: None,
|
||||
is_complete: true,
|
||||
suggestions,
|
||||
switchers,
|
||||
context_name: None,
|
||||
context_length: 0,
|
||||
context_max_length: 0,
|
||||
};
|
||||
|
||||
response_tx.send(final_response).await?;
|
||||
response_tx.send(final_response).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,13 +83,21 @@ function setupEventHandlers() {
|
|||
form.onsubmit = function (e) { e.preventDefault(); sendMessage(); return false; };
|
||||
}
|
||||
|
||||
if (input) {
|
||||
input.addEventListener("input", handleMentionInput);
|
||||
input.onkeydown = function (e) {
|
||||
if (handleMentionKeydown(e)) return;
|
||||
if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendMessage(); }
|
||||
};
|
||||
}
|
||||
if (input) {
|
||||
if (typeof handleMentionInput === 'function') {
|
||||
input.addEventListener("input", handleMentionInput);
|
||||
}
|
||||
if (typeof handleMentionKeydown === 'function') {
|
||||
input.onkeydown = function (e) {
|
||||
if (handleMentionKeydown(e)) return;
|
||||
if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendMessage(); }
|
||||
};
|
||||
} else {
|
||||
input.onkeydown = function (e) {
|
||||
if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendMessage(); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (sendBtn) {
|
||||
sendBtn.onclick = function (e) { e.preventDefault(); sendMessage(); };
|
||||
|
|
@ -110,16 +118,20 @@ function setupEventHandlers() {
|
|||
});
|
||||
}
|
||||
|
||||
document.addEventListener("click", function (e) {
|
||||
if (!e.target.closest("#mentionDropdown") && !e.target.closest("#messageInput")) {
|
||||
hideMentionDropdown();
|
||||
}
|
||||
});
|
||||
document.addEventListener("click", function (e) {
|
||||
if (!e.target.closest("#mentionDropdown") && !e.target.closest("#messageInput")) {
|
||||
if (typeof hideMentionDropdown === 'function') {
|
||||
hideMentionDropdown();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initChat() {
|
||||
loadBotConfig();
|
||||
proceedWithChatInit();
|
||||
if (typeof loadBotConfig === 'function') {
|
||||
loadBotConfig();
|
||||
}
|
||||
proceedWithChatInit();
|
||||
}
|
||||
|
||||
function showChatApp() {
|
||||
|
|
@ -132,5 +144,15 @@ function showChatApp() {
|
|||
|
||||
window.showChatApp = showChatApp;
|
||||
|
||||
// Wait for DOM to be ready before initializing
|
||||
if (typeof document !== 'undefined') {
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
setupEventHandlers();
|
||||
initChat();
|
||||
});
|
||||
} else {
|
||||
setupEventHandlers();
|
||||
initChat();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,36 +10,50 @@ function renderSuggestions(suggestions) {
|
|||
chip.className = "suggestion-chip";
|
||||
chip.textContent = suggestion.text || "Suggestion";
|
||||
|
||||
chip.onclick = (function (sugg) {
|
||||
return function () {
|
||||
if (sugg.action) {
|
||||
try {
|
||||
var action = typeof sugg.action === "string"
|
||||
? JSON.parse(sugg.action)
|
||||
: sugg.action;
|
||||
chip.onclick = (function (sugg) {
|
||||
return function () {
|
||||
console.log("[SUGGESTION] Clicked:", sugg.text, "Action:", sugg.action);
|
||||
if (sugg.action) {
|
||||
try {
|
||||
var actionData = typeof sugg.action === "string"
|
||||
? JSON.parse(sugg.action)
|
||||
: sugg.action;
|
||||
|
||||
if (action.type === "invoke_tool") {
|
||||
ChatState.ws.send(JSON.stringify({
|
||||
bot_id: ChatState.currentBotId,
|
||||
user_id: ChatState.currentUserId,
|
||||
session_id: ChatState.currentSessionId,
|
||||
channel: "web",
|
||||
content: action.tool,
|
||||
message_type: 6,
|
||||
active_switchers: Array.from(ChatState.activeSwitchers),
|
||||
timestamp: new Date().toISOString(),
|
||||
}));
|
||||
return;
|
||||
} else if (action.type === "switch_context" && action.switcher) {
|
||||
if (!ChatState.activeSwitchers.has(action.switcher)) {
|
||||
ChatState.activeSwitchers.add(action.switcher);
|
||||
renderSwitcherChips();
|
||||
}
|
||||
window.sendMessage(sugg.text);
|
||||
} else if (action.type === "send_message") {
|
||||
window.sendMessage(action.message || sugg.text);
|
||||
} else if (action.type === "select_context") {
|
||||
window.sendMessage(action.context);
|
||||
console.log("[SUGGESTION] Parsed action:", actionData);
|
||||
|
||||
if (actionData.type === "invoke_tool") {
|
||||
console.log("[SUGGESTION] Invoking tool:", actionData.tool);
|
||||
// Check if WebSocket is available
|
||||
if (ChatState.ws && ChatState.ws.readyState === WebSocket.OPEN) {
|
||||
var msg = {
|
||||
bot_id: ChatState.currentBotId,
|
||||
user_id: ChatState.currentUserId,
|
||||
session_id: ChatState.currentSessionId,
|
||||
channel: "web",
|
||||
content: actionData.tool,
|
||||
message_type: 6,
|
||||
active_switchers: Array.from(ChatState.activeSwitchers),
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
console.log("[SUGGESTION] Sending via WS:", msg);
|
||||
ChatState.ws.send(JSON.stringify(msg));
|
||||
console.log("[SUGGESTION] Sent successfully");
|
||||
} else {
|
||||
console.log("[SUGGESTION] WS not available, fallback to sendMessage");
|
||||
// Fallback: send as regular message if WS not available
|
||||
window.sendMessage(sugg.text);
|
||||
}
|
||||
return;
|
||||
} else if (actionData.type === "switch_context" && actionData.switcher) {
|
||||
if (!ChatState.activeSwitchers.has(actionData.switcher)) {
|
||||
ChatState.activeSwitchers.add(actionData.switcher);
|
||||
renderSwitcherChips();
|
||||
}
|
||||
window.sendMessage(sugg.text);
|
||||
} else if (actionData.type === "send_message") {
|
||||
window.sendMessage(actionData.message || sugg.text);
|
||||
} else if (actionData.type === "select_context") {
|
||||
window.sendMessage(actionData.context);
|
||||
} else {
|
||||
window.sendMessage(sugg.text);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,70 +1,74 @@
|
|||
<link rel="stylesheet" href="/suite/chat/chat.css?v=3" />
|
||||
<link rel="stylesheet" href="/suite/css/markdown-message.css" />
|
||||
<link rel="stylesheet" href="/suite/css/chat-agent-mode.css" />
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Chat - General Bots</title>
|
||||
<link rel="stylesheet" href="/suite/chat/chat.css?v=4" />
|
||||
<link rel="stylesheet" href="/suite/css/markdown-message.css" />
|
||||
<link rel="stylesheet" href="/suite/css/chat-agent-mode.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="chat-layout" id="chat-app" style="opacity: 1; visibility: visible;">
|
||||
<div class="chat-content-wrapper" id="chatContentWrapper">
|
||||
<div class="connection-status connecting" id="connectionStatus" style="display: none">
|
||||
<span class="connection-status-dot"></span>
|
||||
<span class="connection-text">Connecting...</span>
|
||||
</div>
|
||||
|
||||
<div class="chat-layout" id="chat-app" style="opacity: 0; visibility: hidden;">
|
||||
<div class="chat-loading-overlay" id="chatLoadingOverlay">
|
||||
<div class="chat-loading-spinner"></div>
|
||||
<div class="chat-loading-text">Carregando...</div>
|
||||
<main id="messages"></main>
|
||||
|
||||
<footer>
|
||||
<div class="chat-footer-content">
|
||||
<div class="suggestions-container" id="suggestions"></div>
|
||||
<div class="switchers-container" id="switchers" style="display:none">
|
||||
<div class="switchers-label">Formato:</div>
|
||||
<div class="switchers-chips" id="switcherChips"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mention-dropdown" id="mentionDropdown">
|
||||
<div class="mention-header">
|
||||
<span class="mention-title" data-i18n="chat-mention-title">Reference Entity</span>
|
||||
</div>
|
||||
<div class="mention-results" id="mentionResults"></div>
|
||||
</div>
|
||||
<form class="input-container" id="chatForm">
|
||||
<input name="content" id="messageInput" type="text"
|
||||
placeholder="Message... (type @ to mention)"
|
||||
data-i18n-placeholder="chat-placeholder" autofocus autocomplete="off" />
|
||||
<button type="submit" id="sendBtn" title="Send" data-i18n-title="chat-send">↑</button>
|
||||
</form>
|
||||
</footer>
|
||||
<button class="scroll-to-bottom" id="scrollToBottom" title="Scroll to bottom">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-content-wrapper" id="chatContentWrapper">
|
||||
<div class="connection-status connecting" id="connectionStatus" style="display: none">
|
||||
<span class="connection-status-dot"></span>
|
||||
<span class="connection-text">Connecting...</span>
|
||||
</div>
|
||||
|
||||
<main id="messages"></main>
|
||||
|
||||
<footer>
|
||||
<div class="chat-footer-content">
|
||||
<div class="suggestions-container" id="suggestions"></div>
|
||||
<div class="switchers-container" id="switchers" style="display:none">
|
||||
<div class="switchers-label">Formato:</div>
|
||||
<div class="switchers-chips" id="switcherChips"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mention-dropdown" id="mentionDropdown">
|
||||
<div class="mention-header">
|
||||
<span class="mention-title" data-i18n="chat-mention-title">Reference Entity</span>
|
||||
</div>
|
||||
<div class="mention-results" id="mentionResults"></div>
|
||||
</div>
|
||||
<form class="input-container" id="chatForm">
|
||||
<input name="content" id="messageInput" type="text"
|
||||
placeholder="Message... (type @ to mention)"
|
||||
data-i18n-placeholder="chat-placeholder" autofocus autocomplete="off" />
|
||||
<button type="submit" id="sendBtn" title="Send" data-i18n-title="chat-send">↑</button>
|
||||
</form>
|
||||
</footer>
|
||||
<button class="scroll-to-bottom" id="scrollToBottom" title="Scroll to bottom">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="entity-card-tooltip" id="entityCardTooltip">
|
||||
<div class="entity-card-tooltip" id="entityCardTooltip">
|
||||
<div class="entity-card-header">
|
||||
<span class="entity-card-type"></span>
|
||||
<span class="entity-card-status"></span>
|
||||
<span class="entity-card-type"></span>
|
||||
<span class="entity-card-status"></span>
|
||||
</div>
|
||||
<div class="entity-card-title"></div>
|
||||
<div class="entity-card-details"></div>
|
||||
<div class="entity-card-actions">
|
||||
<button class="entity-card-btn" data-action="view" data-i18n="action-view">View</button>
|
||||
<button class="entity-card-btn" data-action="view" data-i18n="action-view">View</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/suite/js/vendor/marked.min.js"></script>
|
||||
<script src="/suite/chat/chat-state.js"></script>
|
||||
<script src="/suite/chat/chat-switchers.js"></script>
|
||||
<script src="/suite/chat/chat-mentions.js"></script>
|
||||
<script src="/suite/chat/chat-messages.js"></script>
|
||||
<script src="/suite/chat/chat-suggestions.js"></script>
|
||||
<script src="/suite/chat/chat-theme.js"></script>
|
||||
<script src="/suite/chat/chat-websocket.js"></script>
|
||||
<script src="/suite/chat/chat-init.js"></script>
|
||||
<script src="/suite/js/chat-agent-mode.js"></script>
|
||||
<script src="/suite/chat/chat-state.js?v=4"></script>
|
||||
<script src="/suite/chat/chat-switchers.js?v=4"></script>
|
||||
<script src="/suite/chat/chat-mentions.js?v=4"></script>
|
||||
<script src="/suite/chat/chat-messages.js?v=4"></script>
|
||||
<script src="/suite/chat/chat-suggestions.js?v=4"></script>
|
||||
<script src="/suite/chat/chat-theme.js?v=4"></script>
|
||||
<script src="/suite/chat/chat-websocket.js?v=4"></script>
|
||||
<script src="/suite/chat/chat-init.js?v=4"></script>
|
||||
<script src="/suite/js/chat-agent-mode.js?v=4"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue