Skip to content

Commit

Permalink
Merge pull request #6 from max1mde/powershell_translation_prompt
Browse files Browse the repository at this point in the history
Powershell translation prompt
  • Loading branch information
max1mde authored Nov 18, 2024
2 parents 29cea90 + 7384354 commit 827e700
Show file tree
Hide file tree
Showing 3 changed files with 257 additions and 2 deletions.
198 changes: 196 additions & 2 deletions src/autocorrect_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import tiktoken
from PyQt6.QtCore import Qt, QPoint, pyqtSignal, QObject, QThread
from PyQt6.QtGui import QPainter, QColor, QCursor
from PyQt6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLineEdit, QPushButton, QApplication
from PyQt6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLineEdit, QPushButton, QApplication, QMessageBox

logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
Expand All @@ -24,13 +24,152 @@

class Worker(QObject):
show_dialog = pyqtSignal(str)

show_command_dialog = pyqtSignal(str)
def handle_custom_prompt(self, selected_text):
try:
self.show_dialog.emit(selected_text)
except Exception as e:
logger.error(f"Error in handle_custom_prompt: {str(e)}")

def handle_command_execution(self):
try:
self.show_command_dialog.emit("")
except Exception as e:
logger.error(f"Error in handle_command_execution: {str(e)}")

class CommandExecutionDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
try:
self.setup_ui()
except Exception as e:
logger.error(f"Error initializing CommandExecutionDialog: {str(e)}")
self.close()

def setup_ui(self):
self.setWindowFlags(
Qt.WindowType.FramelessWindowHint | Qt.WindowType.Popup | Qt.WindowType.NoDropShadowWindowHint)
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
self.setModal(True)
self.selected_command = None

layout = QVBoxLayout(self)
layout.setSpacing(10)
layout.setContentsMargins(10, 10, 10, 10)

top_layout = QHBoxLayout()
top_layout.addStretch()

self.is_dragging = False
self.drag_position = QPoint()

self.close_button = QPushButton("X")
self.close_button.setFixedSize(20, 20)
self.close_button.setStyleSheet("""
QPushButton {
background-color: rgba(30, 30, 30, 0.9);
color: white;
border-radius: 10px;
font-size: 16px;
font-weight: bold;
padding: 0;
margin: 0;
}
QPushButton:hover {
background-color: rgba(255, 0, 0, 0.8);
}
""")
top_layout.addWidget(self.close_button)

cursor_position = QCursor.pos()
x_position = cursor_position.x() - (self.width() // 5) + 5
y_position = cursor_position.y() + 80
self.move(x_position, y_position)

layout.addLayout(top_layout)

self.command_input = QLineEdit()
self.command_input.setPlaceholderText("Enter command (e.g., 'open explorer', 'shutdown pc in 20 minutes')...")
self.command_input.setStyleSheet("""
QLineEdit {
background-color: rgba(20, 20, 20, 0.85);
border-radius: 15px;
padding: 10px;
font-size: 14px;
border: 1px solid #ccc;
color: white;
}
""")
layout.addWidget(self.command_input)

quick_actions = {
"Open Explorer": "open explorer",
"Open PowerShell": "open powershell",
"Shutdown in 30min": "shutdown pc in 30 minutes",
"Restart PC": "restart pc",
"Lock PC": "lock pc",
}

buttons_layout = QHBoxLayout()
for action_name, action_command in quick_actions.items():
btn = QPushButton(action_name)
btn.setStyleSheet("""
QPushButton {
background-color: rgba(30, 30, 30, 0.9);
color: white;
border-radius: 10px;
padding: 5px 10px;
margin: 2px;
}
QPushButton:hover {
background-color: rgba(70, 70, 70, 1);
}
""")
buttons_layout.addWidget(btn)
btn.clicked.connect(lambda checked, c=action_command: self.handle_quick_action(c))

layout.addLayout(buttons_layout)

self.command_input.returnPressed.connect(self.handle_return_pressed)
self.close_button.clicked.connect(self.reject)

def handle_quick_action(self, command):
try:
self.selected_command = command
self.accept()
except Exception as e:
logger.error(f"Error in handle_quick_action: {str(e)}")

def handle_return_pressed(self):
self.selected_command = self.command_input.text()
self.accept()

def get_result(self):
return self.selected_command

def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
painter.setBrush(QColor(1, 1, 1, 170))
painter.setPen(Qt.PenStyle.NoPen)
painter.drawRoundedRect(self.rect(), 15, 15)

def mousePressEvent(self, event):
if event.button() == Qt.MouseButton.LeftButton:
self.is_dragging = True
self.drag_position = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
event.accept()

def mouseMoveEvent(self, event):
if self.is_dragging and event.buttons() == Qt.MouseButton.LeftButton:
self.move(event.globalPosition().toPoint() - self.drag_position)
event.accept()

def mouseReleaseEvent(self, event):
if event.button() == Qt.MouseButton.LeftButton:
self.is_dragging = False
event.accept()


class CustomPromptDialog(QDialog):
def __init__(self, parent=None, last_prompt=None, show_suggestions=None):
Expand Down Expand Up @@ -271,6 +410,7 @@ def __init__(self, settings_manager):
self.worker_thread = QThread()
self.worker.moveToThread(self.worker_thread)
self.worker.show_dialog.connect(self.get_custom_prompt)
self.worker.show_command_dialog.connect(self.get_command_execution)
self.worker_thread.start()
self.setup_hotkeys()
except Exception as e:
Expand Down Expand Up @@ -488,6 +628,58 @@ def handle_translation_hotkey(self):
except Exception as e:
logger.error(f"Error in handle_translation_hotkey: {str(e)}")

def handle_command_execution_hotkey(self):
try:
if not self.enabled:
return

self.worker.handle_command_execution()

except Exception as e:
logger.error(f"Error in handle_command_execution_hotkey: {str(e)}")

def get_command_execution(self, _):
try:
dialog = CommandExecutionDialog()

if dialog.exec() == QDialog.DialogCode.Accepted:
command = dialog.get_result()
if command:
self.execute_command(command)

except Exception as e:
logger.error(f"Error in get_command_execution: {str(e)}")

def execute_command(self, command_text):
try:
prompt = self.settings.get_setting('command_execution.prompt') + command_text

try:
response_data = self.make_api_request(prompt)
command = response_data['choices'][0]['message']['content'].strip()

if "This action is impossible" in command:
QMessageBox.warning(None, "Command Execution",
"This action cannot be performed or might be dangerous.")
return

print(command)
import subprocess
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si.wShowWindow = 0

subprocess.Popen(['powershell.exe', '-Command', command],
startupinfo=si, creationflags=subprocess.CREATE_NEW_CONSOLE)

except Exception as e:
logger.error(f"Error in API communication or command execution: {str(e)}")
QMessageBox.critical(None, "Error",
f"Failed to execute command: {str(e)}")

except Exception as e:
logger.error(f"Error in execute_command: {str(e)}")

def handle_custom_prompt_hotkey(self):
try:
if not self.enabled:
Expand Down Expand Up @@ -558,6 +750,8 @@ def setup_hotkeys(self):
keyboard.add_hotkey(self.settings.get_setting('rephrase.switch_phrasings_hotkey'), self.switch_phrasings)
keyboard.add_hotkey(self.settings.get_setting('translate.hotkey'), self.handle_translation_hotkey)
keyboard.add_hotkey(self.settings.get_setting('custom_prompt.hotkey'), self.handle_custom_prompt_hotkey)
keyboard.add_hotkey(self.settings.get_setting('command_execution.hotkey'),
self.handle_command_execution_hotkey)
logger.info("Hotkeys successfully set up")
except Exception as e:
logger.error(f"Error setting up hotkeys: {str(e)}")
Expand Down
8 changes: 8 additions & 0 deletions src/settings_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ class SettingsManager:
'custom_prompt.hotkey': 'Ctrl+F12',
'custom_prompt.use_replacements': True,
'custom_prompt.auto_custom_prompt': True,
'command_execution.hotkey': 'Ctrl+F7',
'command_execution.prompt': (
'Convert this command to a PowerShell script. If impossible (Or you cannot get it to work in one try) or dangerous, respond with "This action is impossible". '
'Output only the command. Do not include explanations, notes, or instructions. Examples:\n'
'- "open discord" → Start-Process "C:\\Users\\$env:USERNAME\\AppData\\Local\\Discord\\Update.exe" --processStart Discord.exe\n'
'- "shutdown in 30 minutes" → shutdown.exe /s /t 1800\n'
'Convert this:'
),
'auto_select_text': False,
'provider_api_key': '',
'api_endpoint': 'https://openrouter.ai/api/v1/chat/completions',
Expand Down
53 changes: 53 additions & 0 deletions src/ui/settings_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,51 @@ def mark_modified(self):
self.settings_modified = True


class CommandExecutionModuleWindow(QDialog):
def __init__(self, settings_manager, parent=None):
super().__init__(parent)
self.settings = settings_manager
self.setWindowTitle("Command Execution Module Settings (AI)")
self.setWindowIcon(QIcon("assets/icon.ico"))
self.setup_ui()
self.load_settings()
self.settings_modified = False

def setup_ui(self):
layout = QVBoxLayout(self)

self.prompt = QLineEdit()
self.prompt.textChanged.connect(self.mark_modified)
prompt_label = QLabel("Command Execution Prompt:")

self.hotkey_input = QKeySequenceEdit()
hotkey_label = QLabel("Command Execution Hotkey:")

layout.addWidget(prompt_label)
layout.addWidget(self.prompt)
layout.addWidget(hotkey_label)
layout.addWidget(self.hotkey_input)

save_btn = QPushButton("Save")
save_btn.clicked.connect(self.save_settings)
layout.addWidget(save_btn)

def load_settings(self):
self.prompt.setText(self.settings.get_setting('command_execution.prompt',
'Convert the following user prompt into a PowerShell command or script. If it is impossible or dangerous, '
'reply with "This action is impossible". Respond with only the command or script (It will be executed directly):'
))
self.hotkey_input.setKeySequence(QKeySequence(self.settings.get_setting('command_execution.hotkey', 'Ctrl+F7')))

def save_settings(self):
self.settings.set_setting('command_execution.prompt', self.prompt.text())
self.settings.set_setting('command_execution.hotkey', self.hotkey_input.keySequence().toString())
self.settings_modified = False
self.close()

def mark_modified(self):
self.settings_modified = True

class CustomPromptModuleWindow(QDialog):
def __init__(self, settings_manager, parent=None):
super().__init__(parent)
Expand Down Expand Up @@ -434,6 +479,10 @@ def setup_ui(self):
custom_prompt_btn.clicked.connect(self.show_custom_prompt_settings)
modules_layout.addWidget(custom_prompt_btn)

command_execution_btn = QPushButton("Command Execution Module Settings (AI)")
command_execution_btn.clicked.connect(self.show_command_execution_settings)
modules_layout.addWidget(command_execution_btn)

modules_group.setLayout(modules_layout)
layout.addWidget(modules_group)

Expand Down Expand Up @@ -537,6 +586,10 @@ def show_custom_prompt_settings(self):
dialog = CustomPromptModuleWindow(self.settings, self)
dialog.exec()

def show_command_execution_settings(self):
dialog = CommandExecutionModuleWindow(self.settings, self)
dialog.exec()

def show_replacements(self):
replacements = self.settings.get_replacements()
dialog = ReplacementsDialog(replacements, self)
Expand Down

0 comments on commit 827e700

Please sign in to comment.