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 {
|
if !in_analysis {
|
||||||
full_response.push_str(&chunk);
|
// Accumulate full response - DO NOT send chunks
|
||||||
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("llm_end: Streaming loop ended for session {}, chunk_count={}, full_response_len={}", session.id, chunk_count, full_response.len());
|
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"))]
|
#[cfg(not(feature = "chat"))]
|
||||||
let switchers: Vec<Switcher> = Vec::new();
|
let switchers: Vec<Switcher> = Vec::new();
|
||||||
|
|
||||||
// Content was already sent as streaming chunks.
|
// Send accumulated full response (not streaming anymore)
|
||||||
// Sending full_response again would duplicate it (especially for WhatsApp which accumulates buffer).
|
let final_response = BotResponse {
|
||||||
// The final response is just a signal that streaming is complete - it should not contain content.
|
bot_id: message.bot_id,
|
||||||
let final_content = String::new();
|
user_id: message.user_id,
|
||||||
|
session_id: message.session_id,
|
||||||
let final_response = BotResponse {
|
channel: message.channel,
|
||||||
bot_id: message.bot_id,
|
content: full_response.clone(),
|
||||||
user_id: message.user_id,
|
message_type: MessageType::BOT_RESPONSE,
|
||||||
session_id: message.session_id,
|
stream_token: None,
|
||||||
channel: message.channel,
|
is_complete: true,
|
||||||
content: final_content,
|
suggestions,
|
||||||
message_type: MessageType::BOT_RESPONSE,
|
switchers,
|
||||||
stream_token: None,
|
context_name: None,
|
||||||
is_complete: true,
|
context_length: 0,
|
||||||
suggestions,
|
context_max_length: 0,
|
||||||
switchers,
|
|
||||||
context_name: None,
|
|
||||||
context_length: 0,
|
|
||||||
context_max_length: 0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
response_tx.send(final_response).await?;
|
response_tx.send(final_response).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,13 +83,21 @@ function setupEventHandlers() {
|
||||||
form.onsubmit = function (e) { e.preventDefault(); sendMessage(); return false; };
|
form.onsubmit = function (e) { e.preventDefault(); sendMessage(); return false; };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input) {
|
if (input) {
|
||||||
input.addEventListener("input", handleMentionInput);
|
if (typeof handleMentionInput === 'function') {
|
||||||
input.onkeydown = function (e) {
|
input.addEventListener("input", handleMentionInput);
|
||||||
if (handleMentionKeydown(e)) return;
|
}
|
||||||
if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendMessage(); }
|
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) {
|
if (sendBtn) {
|
||||||
sendBtn.onclick = function (e) { e.preventDefault(); sendMessage(); };
|
sendBtn.onclick = function (e) { e.preventDefault(); sendMessage(); };
|
||||||
|
|
@ -110,16 +118,20 @@ function setupEventHandlers() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("click", function (e) {
|
document.addEventListener("click", function (e) {
|
||||||
if (!e.target.closest("#mentionDropdown") && !e.target.closest("#messageInput")) {
|
if (!e.target.closest("#mentionDropdown") && !e.target.closest("#messageInput")) {
|
||||||
hideMentionDropdown();
|
if (typeof hideMentionDropdown === 'function') {
|
||||||
}
|
hideMentionDropdown();
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initChat() {
|
function initChat() {
|
||||||
loadBotConfig();
|
if (typeof loadBotConfig === 'function') {
|
||||||
proceedWithChatInit();
|
loadBotConfig();
|
||||||
|
}
|
||||||
|
proceedWithChatInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showChatApp() {
|
function showChatApp() {
|
||||||
|
|
@ -132,5 +144,15 @@ function showChatApp() {
|
||||||
|
|
||||||
window.showChatApp = 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();
|
setupEventHandlers();
|
||||||
initChat();
|
initChat();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setupEventHandlers();
|
||||||
|
initChat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,36 +10,50 @@ function renderSuggestions(suggestions) {
|
||||||
chip.className = "suggestion-chip";
|
chip.className = "suggestion-chip";
|
||||||
chip.textContent = suggestion.text || "Suggestion";
|
chip.textContent = suggestion.text || "Suggestion";
|
||||||
|
|
||||||
chip.onclick = (function (sugg) {
|
chip.onclick = (function (sugg) {
|
||||||
return function () {
|
return function () {
|
||||||
if (sugg.action) {
|
console.log("[SUGGESTION] Clicked:", sugg.text, "Action:", sugg.action);
|
||||||
try {
|
if (sugg.action) {
|
||||||
var action = typeof sugg.action === "string"
|
try {
|
||||||
? JSON.parse(sugg.action)
|
var actionData = typeof sugg.action === "string"
|
||||||
: sugg.action;
|
? JSON.parse(sugg.action)
|
||||||
|
: sugg.action;
|
||||||
|
|
||||||
if (action.type === "invoke_tool") {
|
console.log("[SUGGESTION] Parsed action:", actionData);
|
||||||
ChatState.ws.send(JSON.stringify({
|
|
||||||
bot_id: ChatState.currentBotId,
|
if (actionData.type === "invoke_tool") {
|
||||||
user_id: ChatState.currentUserId,
|
console.log("[SUGGESTION] Invoking tool:", actionData.tool);
|
||||||
session_id: ChatState.currentSessionId,
|
// Check if WebSocket is available
|
||||||
channel: "web",
|
if (ChatState.ws && ChatState.ws.readyState === WebSocket.OPEN) {
|
||||||
content: action.tool,
|
var msg = {
|
||||||
message_type: 6,
|
bot_id: ChatState.currentBotId,
|
||||||
active_switchers: Array.from(ChatState.activeSwitchers),
|
user_id: ChatState.currentUserId,
|
||||||
timestamp: new Date().toISOString(),
|
session_id: ChatState.currentSessionId,
|
||||||
}));
|
channel: "web",
|
||||||
return;
|
content: actionData.tool,
|
||||||
} else if (action.type === "switch_context" && action.switcher) {
|
message_type: 6,
|
||||||
if (!ChatState.activeSwitchers.has(action.switcher)) {
|
active_switchers: Array.from(ChatState.activeSwitchers),
|
||||||
ChatState.activeSwitchers.add(action.switcher);
|
timestamp: new Date().toISOString(),
|
||||||
renderSwitcherChips();
|
};
|
||||||
}
|
console.log("[SUGGESTION] Sending via WS:", msg);
|
||||||
window.sendMessage(sugg.text);
|
ChatState.ws.send(JSON.stringify(msg));
|
||||||
} else if (action.type === "send_message") {
|
console.log("[SUGGESTION] Sent successfully");
|
||||||
window.sendMessage(action.message || sugg.text);
|
} else {
|
||||||
} else if (action.type === "select_context") {
|
console.log("[SUGGESTION] WS not available, fallback to sendMessage");
|
||||||
window.sendMessage(action.context);
|
// 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 {
|
} else {
|
||||||
window.sendMessage(sugg.text);
|
window.sendMessage(sugg.text);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,70 +1,74 @@
|
||||||
<link rel="stylesheet" href="/suite/chat/chat.css?v=3" />
|
<!DOCTYPE html>
|
||||||
<link rel="stylesheet" href="/suite/css/markdown-message.css" />
|
<html lang="pt-BR">
|
||||||
<link rel="stylesheet" href="/suite/css/chat-agent-mode.css" />
|
<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;">
|
<main id="messages"></main>
|
||||||
<div class="chat-loading-overlay" id="chatLoadingOverlay">
|
|
||||||
<div class="chat-loading-spinner"></div>
|
<footer>
|
||||||
<div class="chat-loading-text">Carregando...</div>
|
<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>
|
||||||
|
|
||||||
<div class="chat-content-wrapper" id="chatContentWrapper">
|
<div class="entity-card-tooltip" id="entityCardTooltip">
|
||||||
<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-header">
|
<div class="entity-card-header">
|
||||||
<span class="entity-card-type"></span>
|
<span class="entity-card-type"></span>
|
||||||
<span class="entity-card-status"></span>
|
<span class="entity-card-status"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="entity-card-title"></div>
|
<div class="entity-card-title"></div>
|
||||||
<div class="entity-card-details"></div>
|
<div class="entity-card-details"></div>
|
||||||
<div class="entity-card-actions">
|
<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>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/suite/js/vendor/marked.min.js"></script>
|
<script src="/suite/js/vendor/marked.min.js"></script>
|
||||||
<script src="/suite/chat/chat-state.js"></script>
|
<script src="/suite/chat/chat-state.js?v=4"></script>
|
||||||
<script src="/suite/chat/chat-switchers.js"></script>
|
<script src="/suite/chat/chat-switchers.js?v=4"></script>
|
||||||
<script src="/suite/chat/chat-mentions.js"></script>
|
<script src="/suite/chat/chat-mentions.js?v=4"></script>
|
||||||
<script src="/suite/chat/chat-messages.js"></script>
|
<script src="/suite/chat/chat-messages.js?v=4"></script>
|
||||||
<script src="/suite/chat/chat-suggestions.js"></script>
|
<script src="/suite/chat/chat-suggestions.js?v=4"></script>
|
||||||
<script src="/suite/chat/chat-theme.js"></script>
|
<script src="/suite/chat/chat-theme.js?v=4"></script>
|
||||||
<script src="/suite/chat/chat-websocket.js"></script>
|
<script src="/suite/chat/chat-websocket.js?v=4"></script>
|
||||||
<script src="/suite/chat/chat-init.js"></script>
|
<script src="/suite/chat/chat-init.js?v=4"></script>
|
||||||
<script src="/suite/js/chat-agent-mode.js"></script>
|
<script src="/suite/js/chat-agent-mode.js?v=4"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue