clean up silly chat_widget that was in the wrong place

This commit is contained in:
perf3ct 2025-03-19 18:31:54 +00:00
parent f6afb1d963
commit 492c05bad4
No known key found for this signature in database
GPG Key ID: 569C4EEC436F5232
2 changed files with 0 additions and 415 deletions

View File

@ -1,9 +1,3 @@
import options from "../../../services/options.js";
import ChatWidget from "../widgets/llm/chat_widget.js";
import TabContext from "../widgets/right_panel_tabs.js";
import rightPaneTabManager from "./right_pane_tab_manager.js";
import keyboardActionsService from "./keyboard_actions.js";
function initComponents() {
// ... existing code ...
@ -12,50 +6,6 @@ function initComponents() {
// ... existing code ...
}
function addChatTab() {
if (!options.getOptionBool('aiEnabled')) {
return;
}
const chatWidget = new ChatWidget();
// Add chat widget to the right pane
const chatTab = new TabContext("AI Chat", chatWidget);
chatTab.renderTitle = title => {
return $(`<span class="tab-title"><span class="bx bx-bot"></span> ${title}</span>`);
};
rightPaneTabManager.addTabContext(chatTab);
// Add chat button to the global menu
const $button = $('<button class="button-widget global-menu-button" title="Open AI Chat (Ctrl+Shift+C)"><span class="bx bx-chat"></span></button>');
$button.on('click', () => {
chatTab.activate();
chatWidget.refresh();
});
$button.insertBefore($('.global-menu-button:first')); // Add to the beginning of global menu
// Add keyboard shortcut
keyboardActionsService.setupActionsForScope('window', {
'openAiChat': {
'enabled': true,
'title': 'Open AI Chat',
'clickNote': true,
'shortcutKeys': {
'keyCode': 'C',
'ctrlKey': true,
'shiftKey': true
},
'handler': () => {
chatTab.activate();
chatWidget.refresh();
}
}
});
}
// Export the functions to make them available to other modules
export default {
initComponents,

View File

@ -1,365 +0,0 @@
import TabAwareWidget from "../tab_aware_widget.js";
import chatService from "../../../../services/llm/chat_service.js";
import options from "../../services/options.js";
import utils from "../../services/utils.js";
const TPL = `
<div class="chat-widget">
<div class="chat-header">
<div class="chat-title"></div>
<div class="chat-actions">
<button class="btn btn-sm chat-new-btn" title="New Chat">
<span class="bx bx-plus"></span>
</button>
<button class="btn btn-sm chat-options-btn" title="Chat Options">
<span class="bx bx-cog"></span>
</button>
</div>
</div>
<div class="chat-messages"></div>
<div class="chat-controls">
<div class="chat-input-container">
<textarea class="chat-input form-control" placeholder="Type your message here..." rows="2"></textarea>
</div>
<div class="chat-buttons">
<button class="btn btn-primary btn-sm chat-send-btn" title="Send Message">
<span class="bx bx-send"></span>
</button>
<button class="btn btn-outline-secondary btn-sm chat-add-context-btn" title="Add current note as context">
<span class="bx bx-link"></span>
</button>
</div>
</div>
</div>
`;
const MESSAGE_TPL = `
<div class="chat-message">
<div class="chat-message-avatar">
<span class="bx"></span>
</div>
<div class="chat-message-content"></div>
</div>
`;
export default class ChatWidget extends TabAwareWidget {
constructor() {
super();
this.activeSessionId = null;
this.$widget = $(TPL);
this.$title = this.$widget.find('.chat-title');
this.$messagesContainer = this.$widget.find('.chat-messages');
this.$input = this.$widget.find('.chat-input');
this.$sendBtn = this.$widget.find('.chat-send-btn');
this.$newChatBtn = this.$widget.find('.chat-new-btn');
this.$optionsBtn = this.$widget.find('.chat-options-btn');
this.$addContextBtn = this.$widget.find('.chat-add-context-btn');
this.initialized = false;
this.isActiveTab = false;
}
isEnabled() {
return options.getOptionBool('aiEnabled');
}
doRender() {
this.$widget.on('click', '.chat-send-btn', async () => {
if (!this.activeSessionId) return;
const message = this.$input.val().trim();
if (!message) return;
this.$input.val('');
this.$input.prop('disabled', true);
this.$sendBtn.prop('disabled', true);
await this.sendMessage(message);
this.$input.prop('disabled', false);
this.$sendBtn.prop('disabled', false);
this.$input.focus();
});
this.$input.on('keydown', async e => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
this.$sendBtn.click();
}
});
this.$newChatBtn.on('click', async () => {
await this.startNewChat();
});
this.$addContextBtn.on('click', async () => {
if (!this.activeSessionId || !this.noteId) return;
this.$input.prop('disabled', true);
this.$sendBtn.prop('disabled', true);
this.$addContextBtn.prop('disabled', true);
await this.addNoteContext();
this.$input.prop('disabled', false);
this.$sendBtn.prop('disabled', false);
this.$addContextBtn.prop('disabled', false);
});
this.$optionsBtn.on('click', () => {
this.triggerEvent('openOptions');
});
return this.$widget;
}
async refresh() {
if (!this.isEnabled()) {
this.toggleVisibility(false);
return;
}
this.toggleVisibility(true);
if (!this.initialized) {
await this.initialize();
}
if (this.activeSessionId) {
await this.loadSession(this.activeSessionId);
} else {
await this.startNewChat();
}
}
toggleVisibility(show) {
this.$widget.toggleClass('d-none', !show);
}
async initialize() {
// Load last or create new chat session
const sessions = await chatService.getAllSessions();
if (sessions.length > 0) {
// Use the most recent session
this.activeSessionId = sessions[0].id;
await this.loadSession(this.activeSessionId);
} else {
await this.startNewChat();
}
this.initialized = true;
}
async loadSession(sessionId) {
try {
const session = await chatService.getOrCreateSession(sessionId);
this.activeSessionId = session.id;
// Update title
this.$title.text(session.title || 'New Chat');
// Clear and reload messages
this.$messagesContainer.empty();
for (const message of session.messages) {
this.addMessageToUI(message);
}
// Scroll to bottom
this.scrollToBottom();
} catch (error) {
console.error('Failed to load chat session:', error);
await this.startNewChat();
}
}
async startNewChat() {
try {
const session = await chatService.createSession();
this.activeSessionId = session.id;
// Update title
this.$title.text(session.title || 'New Chat');
// Clear messages
this.$messagesContainer.empty();
// Add welcome message
const welcomeMessage = {
role: 'assistant',
content: 'Hello! How can I assist you today?'
};
this.addMessageToUI(welcomeMessage);
// Focus input
this.$input.focus();
} catch (error) {
console.error('Failed to create new chat session:', error);
}
}
async sendMessage(content) {
if (!this.activeSessionId) return;
// Add user message to UI immediately
const userMessage = { role: 'user', content };
this.addMessageToUI(userMessage);
// Prepare for streaming response
const $assistantMessage = this.createEmptyAssistantMessage();
// Send to service with streaming callback
try {
await chatService.sendMessage(
this.activeSessionId,
content,
null,
(content, isDone) => {
// Update the message content as it streams
$assistantMessage.find('.chat-message-content').html(this.formatMessageContent(content));
this.scrollToBottom();
if (isDone) {
// Update session title if it changed
chatService.getOrCreateSession(this.activeSessionId).then(session => {
this.$title.text(session.title);
});
}
}
);
} catch (error) {
console.error('Error sending message:', error);
// Show error in UI if not already shown by streaming
$assistantMessage.find('.chat-message-content').html(
this.formatMessageContent(`Error: Failed to generate response. ${error.message || 'Please check AI settings and try again.'}`)
);
}
this.scrollToBottom();
}
async addNoteContext() {
if (!this.activeSessionId || !this.noteId) return;
try {
// Show loading message
const $loadingMessage = this.createEmptyAssistantMessage();
$loadingMessage.find('.chat-message-content').html('Loading note context...');
await chatService.addNoteContext(this.activeSessionId, this.noteId);
// Remove loading message
$loadingMessage.remove();
// Reload the session to show updated messages
await this.loadSession(this.activeSessionId);
} catch (error) {
console.error('Error adding note context:', error);
}
}
addMessageToUI(message) {
const $message = $(MESSAGE_TPL);
// Set avatar icon based on role
if (message.role === 'user') {
$message.addClass('chat-message-user');
$message.find('.chat-message-avatar .bx').addClass('bx-user');
} else {
$message.addClass('chat-message-assistant');
$message.find('.chat-message-avatar .bx').addClass('bx-bot');
}
// Set content
$message.find('.chat-message-content').html(this.formatMessageContent(message.content));
// Add to container
this.$messagesContainer.append($message);
// Scroll to bottom
this.scrollToBottom();
return $message;
}
createEmptyAssistantMessage() {
const $message = $(MESSAGE_TPL);
$message.addClass('chat-message-assistant');
$message.find('.chat-message-avatar .bx').addClass('bx-bot');
$message.find('.chat-message-content').html('<div class="chat-loading">●●●</div>');
this.$messagesContainer.append($message);
this.scrollToBottom();
return $message;
}
formatMessageContent(content) {
if (!content) return '';
// First extract code blocks to protect them from HTML escaping
const codeBlocks = [];
let processedContent = content.replace(/```(\w+)?\n([\s\S]+?)\n```/g, (match, language, code) => {
const placeholder = `__CODE_BLOCK_${codeBlocks.length}__`;
const languageClass = language ? ` language-${language}` : '';
codeBlocks.push(`<pre class="code${languageClass}"><code>${utils.escapeHtml(code)}</code></pre>`);
return placeholder;
});
// Escape HTML in the remaining content
processedContent = utils.escapeHtml(processedContent);
// Convert inline code - look for backticks that weren't part of a code block
processedContent = processedContent.replace(/`([^`]+)`/g, '<code>$1</code>');
// Convert line breaks
processedContent = processedContent.replace(/\n/g, '<br>');
// Restore code blocks
codeBlocks.forEach((block, index) => {
processedContent = processedContent.replace(`__CODE_BLOCK_${index}__`, block);
});
return processedContent;
}
scrollToBottom() {
this.$messagesContainer.scrollTop(this.$messagesContainer[0].scrollHeight);
}
/**
* @param {string} noteId
*/
async noteSwitched(noteId) {
this.noteId = noteId;
if (this.isActiveTab) {
// Only refresh if we're the active tab
await this.refresh();
}
}
/**
* @param {boolean} active
*/
activeTabChanged(active) {
this.isActiveTab = active;
if (active) {
this.refresh();
}
}
entitiesReloaded() {
if (this.isActiveTab) {
this.refresh();
}
}
}