mirror of
https://github.com/kovidgoyal/calibre.git
synced 2026-03-31 22:32:28 -04:00
New chat widget basically works
This commit is contained in:
parent
c08e37168b
commit
444a3069a8
@ -98,6 +98,7 @@ class ChatWidget(QWidget):
|
||||
def __init__(self, parent: QWidget = None, placeholder_text: str = ''):
|
||||
super().__init__(parent)
|
||||
l = QVBoxLayout(self)
|
||||
l.setContentsMargins(0, 0, 0, 0)
|
||||
self.browser = b = Browser(self)
|
||||
b.anchorClicked.connect(self.link_clicked)
|
||||
l.addWidget(b)
|
||||
@ -110,6 +111,10 @@ class ChatWidget(QWidget):
|
||||
self.alternate_color = pal.color(QPalette.ColorRole.Window).name()
|
||||
self.base_color = pal.color(QPalette.ColorRole.Base).name()
|
||||
|
||||
def wrap_content_in_padding_table(self, html: str, background_color: str = '') -> str:
|
||||
style = f'style="background-color: {background_color}"' if background_color else ''
|
||||
return f'''<table width="100%" {style} cellpadding="2"><tr><td>{html}</td></tr></table>'''
|
||||
|
||||
# API {{{
|
||||
def add_block(self, body_html: str, header: Header = Header(), is_alternate: bool = False) -> None:
|
||||
self.current_message = ''
|
||||
@ -118,8 +123,7 @@ class ChatWidget(QWidget):
|
||||
html += f'<div>{header.as_html}</div>'
|
||||
html += f'<div>{body_html}</div>'
|
||||
bg = self.alternate_color if is_alternate else self.base_color
|
||||
html = f'''<table width="100%" style="background-color: {bg}" cellpadding="2"><tr><td>{html}</td></tr></table>'''
|
||||
self.blocks.append(html)
|
||||
self.blocks.append(self.wrap_content_in_padding_table(html, bg))
|
||||
|
||||
def replace_last_block(self, body_html: str, header: Header = Header(), is_alternate: bool = False) -> None:
|
||||
if self.blocks:
|
||||
@ -136,7 +140,7 @@ class ChatWidget(QWidget):
|
||||
html = f'<div style="{style}">{msg_html}</div>'
|
||||
if details:
|
||||
html += f"<pre>{_('Details:')}\n{escape(details)}</pre>"
|
||||
self.current_message = f'<table width="100%" cellpadding="2"><tr><td>{html}</td></tr></table>'
|
||||
self.current_message = self.wrap_content_in_padding_table(html)
|
||||
self.re_render()
|
||||
|
||||
def clear(self) -> None:
|
||||
@ -158,7 +162,8 @@ class ChatWidget(QWidget):
|
||||
def re_render(self) -> None:
|
||||
if self.current_message:
|
||||
self.browser.setHtml(self.current_message)
|
||||
return
|
||||
else:
|
||||
self.browser.setHtml('\n\n'.join(self.blocks))
|
||||
|
||||
def on_input(self) -> None:
|
||||
text = self.input.toPlainText()
|
||||
|
||||
@ -353,17 +353,19 @@ class LLMPanel(QWidget):
|
||||
return self.ai_provider_plugin.human_readable_model_name(self.conversation_history.model_used) or _('Assistant')
|
||||
|
||||
def show_ai_conversation(self):
|
||||
self.result_display.clear()
|
||||
assistant = self.assistant_name
|
||||
for i, message in enumerate(self.conversation_history):
|
||||
content_for_display = for_display_to_human(message)
|
||||
if not content_for_display:
|
||||
continue
|
||||
if you_block := not message.from_assistant:
|
||||
header = Header()
|
||||
else:
|
||||
header = Header()
|
||||
alternate = False
|
||||
if message.from_assistant:
|
||||
alternate = True
|
||||
header = Header(assistant, (Button(
|
||||
_('Save'), f'http://{self.save_note_hostname}/{i}', _('Save this specific response as the note')),))
|
||||
self.result_display.add_block(content_for_display, header, not you_block)
|
||||
self.result_display.add_block(content_for_display, header, alternate)
|
||||
if self.conversation_history.api_call_active:
|
||||
content_for_display = for_display_to_human(ChatMessage(self.conversation_history.accumulator.all_content))
|
||||
self.result_display.add_block(content_for_display, Header(_('{} thinking…').format(assistant)))
|
||||
@ -399,7 +401,6 @@ class LLMPanel(QWidget):
|
||||
self.conversation_history.new_api_call()
|
||||
Thread(name='LLMAPICall', daemon=True, target=self.do_api_call, args=(
|
||||
self.conversation_history.copy(), self.current_api_call_number, self.ai_provider_plugin)).start()
|
||||
self.show_ai_conversation()
|
||||
|
||||
def do_api_call(
|
||||
self, conversation_history: ConversationHistory, current_api_call_number: int, ai_plugin: AIProviderPlugin
|
||||
@ -661,6 +662,7 @@ def develop(show_initial_messages: bool = False):
|
||||
# return LLMSettingsDialog().exec()
|
||||
d = QDialog()
|
||||
l = QVBoxLayout(d)
|
||||
l.setContentsMargins(0, 0, 0, 0)
|
||||
llm = LLMPanel(d)
|
||||
llm.update_with_text('developing')
|
||||
h = llm.conversation_history
|
||||
|
||||
@ -414,31 +414,22 @@ class Lookup(QTabWidget):
|
||||
return panel
|
||||
|
||||
def _activate_llm_panel(self):
|
||||
if self.llm_panel is None:
|
||||
# Deferred import to avoid circular dependencies and improve startup time; import may be redundant
|
||||
from calibre.live import start_worker
|
||||
start_worker() # needed for live loading of AI backends
|
||||
from calibre.gui2.viewer.llm import LLMPanel
|
||||
self.llm_panel = LLMPanel(self)
|
||||
self.llm_container.layout().addWidget(self.llm_panel)
|
||||
|
||||
if self.current_book_metadata:
|
||||
self.llm_panel.update_book_metadata(self.current_book_metadata)
|
||||
|
||||
try:
|
||||
self.llm_panel.add_note_requested.disconnect(self.llm_add_note_requested)
|
||||
except TypeError:
|
||||
pass
|
||||
self.llm_panel.add_note_requested.connect(self.llm_add_note_requested)
|
||||
|
||||
self.removeTab(self.llm_tab_index)
|
||||
self.llm_tab_index = self.addTab(self.llm_panel, QIcon.ic('ai.png'), _('Ask &AI'))
|
||||
self.setCurrentIndex(self.llm_tab_index)
|
||||
self.llm_panel.update_with_text(self.selected_text, self.current_highlight_data)
|
||||
' Only load LLM code when actually requested by the user '
|
||||
if self.llm_panel is not None:
|
||||
return
|
||||
from calibre.live import start_worker
|
||||
start_worker() # needed for live loading of AI backends
|
||||
from calibre.gui2.viewer.llm import LLMPanel
|
||||
self.llm_panel = LLMPanel(self)
|
||||
self.llm_container.layout().addWidget(self.llm_panel)
|
||||
if self.current_book_metadata:
|
||||
self.llm_panel.update_book_metadata(self.current_book_metadata)
|
||||
self.llm_panel.add_note_requested.connect(self.llm_add_note_requested)
|
||||
self.llm_panel.update_with_text(self.selected_text, self.current_highlight_data)
|
||||
|
||||
def _tab_changed(self, index):
|
||||
vprefs.set('llm_lookup_tab_index', index)
|
||||
if index == self.llm_tab_index and self.llm_panel is None:
|
||||
if index == self.llm_tab_index:
|
||||
self._activate_llm_panel()
|
||||
self.update_query()
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user