AI assistance pretty much integrated. 2 options currently that actually work, Claud and Ollama. More planned for later, so other options available they just don't do anything.

This commit is contained in:
Storm Dragon
2025-08-03 14:24:03 -04:00
parent 270def0a59
commit 9c8063c55e

View File

@@ -56,10 +56,9 @@ class AIAssistant(Plugin):
except:
pass
# Keybinding storage
self._kb_binding_activate = None
self._kb_binding_question = None
self._kb_binding_describe = None
# Menu and keybinding storage
self._kb_binding_menu = None
self._menu_gui = None
# AI provider and settings
self._provider_type = None
@@ -238,41 +237,144 @@ class AIAssistant(Plugin):
return False
def _register_keybindings(self):
"""Register AI Assistant keybindings."""
"""Register AI Assistant menu keybinding."""
try:
# Main AI Assistant activation - avoid conflict with Actions
self._kb_binding_activate = self.registerGestureByString(
self._handle_ai_activate,
"Activate AI Assistant",
# Single keybinding to show AI Assistant menu
self._kb_binding_menu = self.registerGestureByString(
self._show_ai_menu,
"Show AI Assistant menu",
'kb:cthulhu+control+shift+a'
)
# Ask question about current focus
self._kb_binding_question = self.registerGestureByString(
self._handle_ai_question,
"Ask AI about current focus",
'kb:cthulhu+control+shift+q'
)
# Describe current screen
self._kb_binding_describe = self.registerGestureByString(
self._handle_ai_describe,
"AI describe current screen",
'kb:cthulhu+control+shift+d'
)
logger.info("AI Assistant keybindings registered")
print(f"DEBUG: AI Assistant keybindings registered - activate: {self._kb_binding_activate}, question: {self._kb_binding_question}, describe: {self._kb_binding_describe}")
logger.info("AI Assistant menu keybinding registered")
print(f"DEBUG: AI Assistant menu keybinding registered: {self._kb_binding_menu}")
except Exception as e:
logger.error(f"Error registering AI keybindings: {e}")
logger.error(f"Error registering AI menu keybinding: {e}")
def _unregister_keybindings(self):
"""Unregister AI Assistant keybindings."""
# Keybindings are automatically cleaned up when plugin deactivates
self._kb_binding_activate = None
self._kb_binding_question = None
self._kb_binding_describe = None
self._kb_binding_menu = None
self._menu_gui = None
def _show_ai_menu(self, script=None, inputEvent=None):
"""Show the AI Assistant menu."""
try:
logger.info("Showing AI Assistant menu")
# IMPORTANT: Capture screen data BEFORE showing menu
# This ensures we get the actual screen content, not the menu itself
self._pre_menu_screen_data = self._collect_ai_data()
logger.info("Pre-captured screen data for menu actions")
# Now show the menu
self._menu_gui = AIAssistantMenu(self._handle_menu_selection)
self._menu_gui.show_gui()
return True
except Exception as e:
logger.error(f"Error showing AI menu: {e}")
import traceback
traceback.print_exc()
return False
def _handle_menu_selection(self, action_id):
"""Handle AI Assistant menu selection."""
try:
logger.info(f"AI menu selection: {action_id}")
if action_id == "ask_question":
self._handle_ai_question_with_data(self._pre_menu_screen_data)
elif action_id == "describe_screen":
self._handle_ai_describe_with_data(self._pre_menu_screen_data)
elif action_id == "request_action":
self._handle_ai_activate_with_data(self._pre_menu_screen_data)
else:
logger.warning(f"Unknown AI menu action: {action_id}")
except Exception as e:
logger.error(f"Error handling menu selection {action_id}: {e}")
def _handle_ai_describe_with_data(self, data):
"""Handle AI screen description request with pre-captured data."""
try:
logger.info("AI screen description requested with pre-captured data")
if not self._enabled:
self._present_message("AI Assistant is not enabled")
return True
# Use AI to describe the current screen
if not self._ai_provider:
self._present_message("AI provider not available. Check configuration.")
return True
self._present_message("AI Assistant analyzing screen...")
# Use pre-captured data
if data:
try:
response = self._ai_provider.describe_screen(
data.get('screenshot'),
data.get('accessibility')
)
self._show_description_dialog(response)
except Exception as e:
logger.error(f"Error getting AI screen description: {e}")
self._present_message(f"Error getting AI screen description: {e}")
else:
self._present_message("Could not collect screen data for analysis")
return True
except Exception as e:
logger.error(f"Error in AI describe handler: {e}")
return False
def _handle_ai_question_with_data(self, data):
"""Handle AI question request with pre-captured data."""
try:
logger.info("AI question requested with pre-captured data")
if not self._enabled:
self._present_message("AI Assistant is not enabled")
return True
if not self._ai_provider:
self._present_message("AI provider not available. Check configuration.")
return True
# Store the pre-captured data for use by the question dialog
self._current_screen_data = data
# Show question dialog
self._show_question_dialog()
return True
except Exception as e:
logger.error(f"Error in AI question handler: {e}")
return False
def _handle_ai_activate_with_data(self, data):
"""Handle AI action request with pre-captured data."""
try:
logger.info("AI action requested with pre-captured data")
if not self._enabled:
self._present_message("AI Assistant is not enabled")
return True
if not self._ai_provider:
self._present_message("AI provider not available. Check configuration.")
return True
# Store the pre-captured data for use by the action dialog
self._current_screen_data = data
# Show action dialog
self._show_action_dialog()
return True
except Exception as e:
logger.error(f"Error in AI action handler: {e}")
return False
def _handle_ai_activate(self, script=None, inputEvent=None):
"""Handle main AI Assistant activation - now shows action dialog."""
@@ -361,7 +463,7 @@ class AIAssistant(Plugin):
data.get('screenshot'),
data.get('accessibility')
)
self._present_message(response)
self._show_description_dialog(response)
except Exception as e:
logger.error(f"Error getting AI screen description: {e}")
self._present_message(f"Error getting AI screen description: {e}")
@@ -779,6 +881,51 @@ class AIAssistant(Plugin):
self._present_message(f"Error processing question: {e}")
# ============================================================================
def _show_description_dialog(self, description):
"""Show a read-only dialog with the screen description."""
try:
dialog = Gtk.Dialog(
title="AI Screen Description",
parent=None,
flags=Gtk.DialogFlags.MODAL,
buttons=(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
)
dialog.set_default_size(600, 400)
content_area = dialog.get_content_area()
# Create scrollable text view
scrolled_window = Gtk.ScrolledWindow()
scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
scrolled_window.set_shadow_type(Gtk.ShadowType.IN)
text_view = Gtk.TextView()
text_view.set_editable(False) # Read-only
text_view.set_cursor_visible(False)
text_view.set_wrap_mode(Gtk.WrapMode.WORD)
# Set the description text
text_buffer = text_view.get_buffer()
text_buffer.set_text(description)
scrolled_window.add(text_view)
content_area.pack_start(scrolled_window, True, True, 10)
dialog.set_default_response(Gtk.ResponseType.CLOSE)
dialog.show_all()
# Focus the text view so screen reader reads the content
text_view.grab_focus()
# Show dialog and wait for user to close
response = dialog.run()
dialog.destroy()
except Exception as e:
logger.error(f"Error showing description dialog: {e}")
self._present_message(f"Error showing description: {e}")
# NEW: Action System Methods for Phase 5
# ============================================================================
@@ -1545,3 +1692,56 @@ class AIAssistant(Plugin):
except Exception as e:
logger.error(f"Error extracting text from action: {e}")
return None
class AIAssistantMenu(Gtk.Menu):
"""A menu containing AI Assistant options."""
def __init__(self, handler):
super().__init__()
self.connect("popped-up", self._on_popped_up)
self.on_option_selected = handler
# AI Assistant menu options
options = [
("ask_question", "Ask Question"),
("describe_screen", "Describe Screen"),
("request_action", "Request Action")
]
for action_id, label in options:
menu_item = Gtk.MenuItem(label=label)
menu_item.connect("activate", self._on_activate, action_id)
self.append(menu_item)
def _on_activate(self, widget, action_id):
"""Handler for menu item activation."""
self.on_option_selected(action_id)
def _on_popped_up(self, *args):
"""Handler for menu popup."""
logger.info("AI Assistant menu popped up")
def show_gui(self):
"""Shows the AI Assistant menu."""
self.show_all()
display = Gdk.Display.get_default()
seat = display.get_default_seat()
device = seat.get_pointer()
screen, x, y = device.get_position()
event = Gdk.Event.new(Gdk.EventType.BUTTON_PRESS)
event.set_screen(screen)
event.set_device(device)
event.time = Gtk.get_current_event_time()
event.x = x
event.y = y
rect = Gdk.Rectangle()
rect.x = x
rect.y = y
rect.width = 1
rect.height = 1
window = Gdk.get_default_root_window()
self.popup_at_rect(window, rect, Gdk.Gravity.NORTH_WEST, Gdk.Gravity.NORTH_WEST, event)